diff --git a/src/components/gfx/display_list.rs b/src/components/gfx/display_list.rs index 1b3df8808cc..7f44dc224fe 100644 --- a/src/components/gfx/display_list.rs +++ b/src/components/gfx/display_list.rs @@ -102,10 +102,15 @@ pub struct TextDisplayItem { range: Range, /// The color of the text. - color: Color, + text_color: Color, /// A bitfield of flags for text display items. flags: TextDisplayItemFlags, + + /// The color of text-decorations + underline_color: Color, + overline_color: Color, + line_through_color: Color, } /// Flags for text display items. @@ -202,7 +207,7 @@ impl DisplayItem { text.text_run.get(), &text.range, baseline_origin, - text.color); + text.text_color); }); let width = text.base.bounds.size.width; let underline_size = font_metrics.underline_size; @@ -214,18 +219,18 @@ impl DisplayItem { let underline_y = baseline_origin.y - underline_offset; let underline_bounds = Rect(Point2D(baseline_origin.x, underline_y), Size2D(width, underline_size)); - render_context.draw_solid_color(&underline_bounds, text.color); + render_context.draw_solid_color(&underline_bounds, text.underline_color); } if text_run.decoration.overline || text.flags.override_overline() { let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y), Size2D(width, underline_size)); - render_context.draw_solid_color(&overline_bounds, text.color); + render_context.draw_solid_color(&overline_bounds, text.overline_color); } if text_run.decoration.line_through || text.flags.override_line_through() { let strikeout_y = baseline_origin.y - strikeout_offset; let strikeout_bounds = Rect(Point2D(baseline_origin.x, strikeout_y), Size2D(width, strikeout_size)); - render_context.draw_solid_color(&strikeout_bounds, text.color); + render_context.draw_solid_color(&strikeout_bounds, text.line_through_color); } } diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index 3d1429b1a8d..b7c945c0d93 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -629,7 +629,7 @@ impl Flow for BlockFlow { self.base.position.origin = Au::zero_point(); self.base.position.size.width = ctx.shared.screen_size.width; self.base.floats_in = FloatContext::new(self.base.num_floats); - self.base.flags.set_inorder(false); + self.base.flags_info.flags.set_inorder(false); } // The position was set to the containing block by the flow's parent. @@ -640,14 +640,14 @@ impl Flow for BlockFlow { self.float.get_mut_ref().containing_width = remaining_width; // Parent usually sets this, but floats are never inorder - self.base.flags.set_inorder(false); + self.base.flags_info.flags.set_inorder(false); } for box_ in self.box_.iter() { let style = box_.style(); // The text alignment of a block flow is the text alignment of its box's style. - self.base.flags.set_text_align(style.Text.text_align); + self.base.flags_info.flags.set_text_align(style.Text.text_align); // Can compute padding here since we know containing block width. box_.compute_padding(style, remaining_width); @@ -702,27 +702,29 @@ impl Flow for BlockFlow { let has_inorder_children = if self.is_float() { self.base.num_floats > 0 } else { - self.base.flags.inorder() || self.base.num_floats > 0 + self.base.flags_info.flags.inorder() || self.base.num_floats > 0 }; + // FIXME(ksh8281): avoid copy + let flags_info = self.base.flags_info.clone(); for kid in self.base.child_iter() { assert!(kid.starts_block_flow() || kid.starts_inline_flow()); let child_base = flow::mut_base(*kid); child_base.position.origin.x = x_offset; child_base.position.size.width = remaining_width; - child_base.flags.set_inorder(has_inorder_children); + child_base.flags_info.flags.set_inorder(has_inorder_children); - if !child_base.flags.inorder() { + if !child_base.flags_info.flags.inorder() { child_base.floats_in = FloatContext::new(0); } // Per CSS 2.1 § 16.3.1, text decoration propagates to all children in flow. // // TODO(pcwalton): When we have out-of-flow children, don't unconditionally propagate. - child_base.flags.propagate_text_decoration_from_parent(self.base.flags); - child_base.flags.propagate_text_alignment_from_parent(self.base.flags) + child_base.flags_info.propagate_text_decoration_from_parent(&flags_info); + child_base.flags_info.propagate_text_alignment_from_parent(&flags_info) } } diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index 4ca9177b073..d7e2de5763c 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -35,7 +35,7 @@ use css::node_style::StyledNode; use layout::context::LayoutContext; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor}; use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth}; -use layout::flow::Flow; +use layout::flow::{Flow, FlowFlagsInfo}; use layout::flow; use layout::model::{MaybeAuto, specified, Auto, Specified}; use layout::util::OpaqueNode; @@ -782,14 +782,26 @@ impl Box { list.append_item(ClipDisplayItemClass(item)); }); - let color = self.style().Color.color.to_gfx_color(); + let text_color = self.style().Color.color.to_gfx_color(); // Set the various text display item flags. - let flow_flags = flow::base(flow).flags; + let mut flow_flags = flow::base(flow).flags_info.clone(); + + let inline_info = self.inline_info.borrow(); + match inline_info.get() { + &Some(ref info) => { + for data in info.parent_info.rev_iter() { + let parent_info = FlowFlagsInfo::new(data.style.get()); + //FIXME(ksh8281) avoid copy + flow_flags.propagate_text_decoration_from_parent(&parent_info); + } + }, + &None => {} + } let mut text_flags = TextDisplayItemFlags::new(); - text_flags.set_override_underline(flow_flags.override_underline()); - text_flags.set_override_overline(flow_flags.override_overline()); - text_flags.set_override_line_through(flow_flags.override_line_through()); + text_flags.set_override_underline(flow_flags.flags.override_underline()); + text_flags.set_override_overline(flow_flags.flags.override_overline()); + text_flags.set_override_line_through(flow_flags.flags.override_line_through()); // Create the text box. list.with_mut(|list| { @@ -800,7 +812,10 @@ impl Box { }, text_run: text_box.run.clone(), range: text_box.range, - color: color, + text_color: text_color, + overline_color: flow_flags.overline_color(text_color), + underline_color: flow_flags.underline_color(text_color), + line_through_color: flow_flags.line_through_color(text_color), flags: text_flags, }; diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 070e1f5b687..539240f53fa 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -407,8 +407,11 @@ impl<'fc> FlowConstructor<'fc> { ConstructionItemConstructionResult(InlineBoxesConstructionItem( InlineBoxesConstructionResult { splits: opt_splits, - boxes: boxes + boxes: mut boxes })) => { + // fill inline info + self.set_inline_info_for_inline_child(&mut boxes, node); + // Bubble up {ib} splits. match opt_splits { None => {} @@ -436,13 +439,6 @@ impl<'fc> FlowConstructor<'fc> { } } - match opt_box_accumulator { - Some(ref mut boxes) => { - self.set_inline_info_for_inline_child(boxes, node) - }, - None => {} - } - // Finally, make a new construction result. if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 { let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult { diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index 22719ff9f2b..f8cb46dada1 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -42,6 +42,8 @@ use extra::container::Deque; use geom::point::Point2D; use geom::rect::Rect; use gfx::display_list::{ClipDisplayItemClass, DisplayList}; +use layout::display_list_builder::ToGfxColor; +use gfx::color::Color; use servo_util::geometry::Au; use std::cast; use std::cell::RefCell; @@ -257,7 +259,23 @@ pub trait PostorderFlowTraversal { } } +#[deriving(Clone)] +pub struct FlowFlagsInfo{ + flags: FlowFlags, + + /// text-decoration colors + rare_flow_flags: Option<~RareFlowFlags>, +} + +#[deriving(Clone)] +pub struct RareFlowFlags { + underline_color: Color, + overline_color: Color, + line_through_color: Color, +} + /// Flags used in flows, tightly packed to save space. +#[deriving(Clone)] pub struct FlowFlags(u8); /// The bitmask of flags that represent text decoration fields that get propagated downward. @@ -275,25 +293,133 @@ static TEXT_ALIGN_BITMASK: u8 = 0b00110000; /// NB: If you update this field, you must update the bitfields below. static TEXT_ALIGN_SHIFT: u8 = 4; -impl FlowFlags { +impl FlowFlagsInfo { /// Creates a new set of flow flags from the given style. - fn new(style: &ComputedValues) -> FlowFlags { + pub fn new(style: &ComputedValues) -> FlowFlagsInfo { let text_decoration = style.Text.text_decoration; let mut flags = FlowFlags(0); flags.set_override_underline(text_decoration.underline); flags.set_override_overline(text_decoration.overline); flags.set_override_line_through(text_decoration.line_through); - flags + + // TODO(ksh8281) compute text-decoration-color,style,line + let rare_flow_flags = if flags.is_text_decoration_enabled() { + Some(~RareFlowFlags { + underline_color: style.Color.color.to_gfx_color(), + overline_color: style.Color.color.to_gfx_color(), + line_through_color: style.Color.color.to_gfx_color(), + }) + } else { + None + }; + + FlowFlagsInfo { + flags: flags, + rare_flow_flags: rare_flow_flags, + } + } + + pub fn underline_color(&self, default_color: Color) -> Color { + match self.rare_flow_flags { + Some(ref data) => { + data.underline_color + }, + None => { + default_color + } + } + } + + pub fn overline_color(&self, default_color: Color) -> Color { + match self.rare_flow_flags { + Some(ref data) => { + data.overline_color + }, + None => { + default_color + } + } + } + + pub fn line_through_color(&self, default_color: Color) -> Color { + match self.rare_flow_flags { + Some(ref data) => { + data.line_through_color + }, + None => { + default_color + } + } } /// Propagates text decoration flags from an appropriate parent flow per CSS 2.1 § 16.3.1. - pub fn propagate_text_decoration_from_parent(&mut self, parent: FlowFlags) { - *self = FlowFlags(**self | (*parent & TEXT_DECORATION_OVERRIDE_BITMASK)) + pub fn propagate_text_decoration_from_parent(&mut self, parent: &FlowFlagsInfo) { + if !parent.flags.is_text_decoration_enabled() { + return ; + } + + if !self.flags.is_text_decoration_enabled() && parent.flags.is_text_decoration_enabled() { + self.rare_flow_flags = parent.rare_flow_flags.clone(); + return ; + } + + if !self.flags.override_underline() && parent.flags.override_underline() { + match parent.rare_flow_flags { + Some(ref parent_data) => { + match self.rare_flow_flags { + Some(ref mut data) => { + data.underline_color = parent_data.underline_color; + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + } + if !self.flags.override_overline() && parent.flags.override_overline() { + match parent.rare_flow_flags { + Some(ref parent_data) => { + match self.rare_flow_flags { + Some(ref mut data) => { + data.overline_color = parent_data.overline_color; + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + } + if !self.flags.override_line_through() && parent.flags.override_line_through() { + match parent.rare_flow_flags { + Some(ref parent_data) => { + match self.rare_flow_flags { + Some(ref mut data) => { + data.line_through_color = parent_data.line_through_color; + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + }, + None => { + fail!("if flow has text-decoration, it must have rare_flow_flags"); + } + } + } + self.flags.set_text_decoration_override(parent.flags); } /// Propagates text alignment flags from an appropriate parent flow per CSS 2.1. - pub fn propagate_text_alignment_from_parent(&mut self, parent: FlowFlags) { - *self = FlowFlags(**self | (*parent & TEXT_ALIGN_BITMASK)) + pub fn propagate_text_alignment_from_parent(&mut self, parent: &FlowFlagsInfo) { + self.flags.set_text_align_override(parent.flags); } } @@ -326,6 +452,21 @@ impl FlowFlags { pub fn set_text_align(&mut self, value: text_align::T) { *self = FlowFlags((**self & !TEXT_ALIGN_BITMASK) | ((value as u8) << TEXT_ALIGN_SHIFT)) } + + #[inline] + pub fn set_text_align_override(&mut self, parent: FlowFlags) { + *self = FlowFlags(**self | (*parent & TEXT_ALIGN_BITMASK)) + } + + #[inline] + pub fn set_text_decoration_override(&mut self, parent: FlowFlags) { + *self = FlowFlags(**self | (*parent & TEXT_DECORATION_OVERRIDE_BITMASK)); + } + + #[inline] + pub fn is_text_decoration_enabled(&self) -> bool { + (**self & TEXT_DECORATION_OVERRIDE_BITMASK) != 0 + } } /// Data common to all flows. @@ -365,8 +506,8 @@ pub struct BaseFlow { num_floats: uint, abs_position: Point2D, - /// Various flags for flows, tightly packed to save space. - flags: FlowFlags, + /// Various flags for flows and some info + flags_info: FlowFlagsInfo, } pub struct BoxIterator { @@ -409,7 +550,7 @@ impl BaseFlow { num_floats: 0, abs_position: Point2D(Au::new(0), Au::new(0)), - flags: FlowFlags::new(style.get()), + flags_info: FlowFlagsInfo::new(style.get()), } } diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 74857cb38bf..552ea88de6e 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -640,11 +640,13 @@ impl Flow for InlineFlow { } } + // FIXME(ksh8281) avoid copy + let flags_info = self.base.flags_info.clone(); for kid in self.base.child_iter() { let child_base = flow::mut_base(*kid); child_base.position.size.width = self.base.position.size.width; - child_base.flags.set_inorder(self.base.flags.inorder()); - child_base.flags.propagate_text_alignment_from_parent(self.base.flags) + child_base.flags_info.flags.set_inorder(self.base.flags_info.flags.inorder()); + child_base.flags_info.propagate_text_alignment_from_parent(&flags_info) } // There are no child contexts, so stop here. @@ -689,7 +691,7 @@ impl Flow for InlineFlow { let mut line_height_offset = Au::new(0); // All lines use text alignment of the flow. - let text_align = self.base.flags.text_align(); + let text_align = self.base.flags_info.flags.text_align(); // Now, go through each line and lay out the boxes inside. for line in self.lines.mut_iter() { diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 22e34b2fe97..2fbea22074f 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -186,7 +186,7 @@ impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> { #[inline] fn should_process(&mut self, flow: &mut Flow) -> bool { - !flow::base(flow).flags.inorder() + !flow::base(flow).flags_info.flags.inorder() } } diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index 4c6f2511658..553464659cd 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -287,7 +287,7 @@ pub mod longhands { "parse_non_negative")} - <%self:single_component_value name="line-height"> + <%self:single_component_value name="line-height" inherited="True"> #[deriving(Clone)] pub enum SpecifiedValue { SpecifiedNormal,