From 25a3da6180122cb1e6947ded83cb498a4ea23027 Mon Sep 17 00:00:00 2001 From: patrick kim Date: Wed, 15 Jan 2014 11:50:09 +0900 Subject: [PATCH] initial implement for inline background --- src/components/main/layout/box_.rs | 72 ++++++++++++++++++++++- src/components/main/layout/construct.rs | 42 ++++++++++++- src/components/main/layout/inline.rs | 15 ++++- src/test/html/inline_bg_color_simple.html | 2 +- 4 files changed, 124 insertions(+), 7 deletions(-) diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index 57eed410b6a8..fe052de786a9 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -88,6 +88,9 @@ pub struct Box { /// positioned box offsets position_offsets: RefCell>, + + /// Inline data + inline_info: RefCell>, } /// Info specific to the kind of box. Keep this enum small. @@ -224,6 +227,34 @@ pub enum SplitBoxResult { SplitDidNotFit(Option, Option) } + +/// data for inline boxes +#[deriving(Clone)] +pub struct InlineInfo { + parent_info: ~[InlineParentInfo], + baseline: Au, +} + +impl InlineInfo { + pub fn new() -> InlineInfo { + InlineInfo { + parent_info: ~[], + baseline: Au::new(0), + } + } +} + +#[deriving(Clone)] +pub struct InlineParentInfo { + padding: SideOffsets2D, + border: SideOffsets2D, + margin: SideOffsets2D, + style: Arc, + font_ascent: Au, + font_descent: Au, +} + + impl Box { /// Constructs a new `Box` instance. pub fn new(node: LayoutNode, specific: SpecificBoxInfo) -> Box { @@ -263,6 +294,7 @@ impl Box { margin: RefCell::new(Zero::zero()), specific: specific, position_offsets: RefCell::new(Zero::zero()), + inline_info: RefCell::new(None), } } @@ -285,7 +317,8 @@ impl Box { padding: RefCell::new(self.padding.get()), margin: RefCell::new(self.margin.get()), specific: specific, - position_offsets: RefCell::new(Zero::zero()) + position_offsets: RefCell::new(Zero::zero()), + inline_info: self.inline_info.clone(), } } @@ -493,11 +526,44 @@ impl Box { pub fn paint_background_if_applicable( &self, list: &RefCell>, - absolute_bounds: &Rect) { + absolute_bounds: &Rect, + offset: &Point2D) { // FIXME: This causes a lot of background colors to be displayed when they are clearly not // needed. We could use display list optimization to clean this up, but it still seems // inefficient. What we really want is something like "nearest ancestor element that // doesn't have a box". + + + self.inline_info.with( |info| { + match info { + &Some(ref box_info) => { + let mut bg_rect = absolute_bounds.clone(); + for info in box_info.parent_info.rev_iter() { + // TODO (ksh8281) compute vertical-align, line-height + bg_rect.origin.y = box_info.baseline + offset.y - info.font_ascent; + bg_rect.size.height = info.font_ascent + info.font_descent; + let background_color = info.style.get().resolve_color( + info.style.get().Background.background_color); + + if !background_color.alpha.approx_eq(&0.0) { + list.with_mut(|list| { + let solid_color_display_item = ~SolidColorDisplayItem { + base: BaseDisplayItem { + bounds: bg_rect.clone(), + extra: ExtraDisplayListData::new(self), + }, + color: background_color.to_gfx_color(), + }; + + list.append_item(SolidColorDisplayItemClass(solid_color_display_item)) + }); + } + + } + }, + &None => {} + } + }); let style = self.style(); let background_color = style.resolve_color(style.Background.background_color); if !background_color.alpha.approx_eq(&0.0) { @@ -598,7 +664,7 @@ impl Box { } // Add the background to the list, if applicable. - self.paint_background_if_applicable(list, &absolute_box_bounds); + self.paint_background_if_applicable(list, &absolute_box_bounds, &offset); match self.specific { UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."), diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 3c65a6363a74..27d350fa62da 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -23,7 +23,7 @@ use css::node_style::StyledNode; use layout::block::BlockFlow; use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo}; -use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo}; +use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo, InlineInfo, InlineParentInfo}; use layout::context::LayoutContext; use layout::float_context::FloatType; use layout::flow::{BaseFlow, Flow, MutableFlowUtils}; @@ -39,6 +39,7 @@ use style::computed_values::{display, float}; use std::cell::RefCell; use std::util; +use std::num::Zero; /// The results of flow construction for a DOM node. pub enum ConstructionResult { @@ -415,7 +416,44 @@ impl<'fc> FlowConstructor<'fc> { } } - // TODO(pcwalton): Add in our own borders/padding/margins if necessary. + match opt_box_accumulator { + Some(ref mut boxes) => { + let parent_box = self.build_box_for_node(node); + let font_style = parent_box.font_style(); + let font_group = self.layout_context.font_ctx.get_resolved_font_for_style(&font_style); + let (font_ascent,font_descent) = font_group.borrow().with_mut( |fg| { + fg.fonts[0].borrow().with_mut( |font| { + (font.metrics.ascent,font.metrics.descent) + }) + }); + + for box_ in boxes.mut_iter() { + if box_.inline_info.with( |data| data.is_none() ) { + box_.inline_info.set(Some(InlineInfo::new())); + } + + box_.inline_info.with_mut( |info| { + match info { + &Some(ref mut info) => { + // TODO(ksh8281) compute margin,border,padding + info.parent_info.push( + InlineParentInfo { + padding: Zero::zero(), + border: Zero::zero(), + margin: Zero::zero(), + style: parent_box.style.clone(), + font_ascent: font_ascent, + font_descent: font_descent, + }); + }, + &None => {} + } + }); + + } + }, + None => {} + } // Finally, make a new construction result. if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 { diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 576b727cd44e..28da9b58a269 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -4,7 +4,7 @@ use css::node_style::StyledNode; use layout::box_::{Box, CannotSplit, GenericBox, IframeBox, ImageBox, ScannedTextBox, SplitDidFit}; -use layout::box_::{SplitDidNotFit, UnscannedTextBox}; +use layout::box_::{SplitDidNotFit, UnscannedTextBox, InlineInfo}; use layout::context::LayoutContext; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData}; use layout::flow::{BaseFlow, FlowClass, Flow, InlineFlowClass}; @@ -837,6 +837,19 @@ impl Flow for InlineFlow { cur_box.position.borrow_mut().get().origin.y = cur_box.position.get().origin.y + adjust_offset; + + if cur_box.inline_info.with(|info| info.is_none()) { + cur_box.inline_info.set(Some(InlineInfo::new())); + } + cur_box.inline_info.with_mut( |info| { + match info { + &Some(ref mut info) => { + // TODO (ksh8281) compute vertical-align, line-height + info.baseline = line.bounds.origin.y + baseline_offset; + }, + &None => {} + } + }); } // This is used to set the top y position of the next linebox in the next loop. diff --git a/src/test/html/inline_bg_color_simple.html b/src/test/html/inline_bg_color_simple.html index 5f145e64e963..7d6efcfbe0de 100644 --- a/src/test/html/inline_bg_color_simple.html +++ b/src/test/html/inline_bg_color_simple.html @@ -5,7 +5,7 @@

paragraph yellow

[inline background color test] - span bluetexttexttextspan yellownested-span redtest finishes + span bluetexttexttextspan yellownested-span redtest finishes