auto merge of #1506 : ksh8281/servo/inline_add, r=pcwalton

add inline stuff & color support
it makes same result with firefox in "http://www.w3.org/Style/CSS/Test/CSS1/current/sec543.htm"
makes line-height property can inherit
This commit is contained in:
bors-servo 2014-01-22 17:13:03 -08:00
commit 6662fb0c32
8 changed files with 204 additions and 43 deletions

View file

@ -102,10 +102,15 @@ pub struct TextDisplayItem<E> {
range: Range, range: Range,
/// The color of the text. /// The color of the text.
color: Color, text_color: Color,
/// A bitfield of flags for text display items. /// A bitfield of flags for text display items.
flags: TextDisplayItemFlags, flags: TextDisplayItemFlags,
/// The color of text-decorations
underline_color: Color,
overline_color: Color,
line_through_color: Color,
} }
/// Flags for text display items. /// Flags for text display items.
@ -202,7 +207,7 @@ impl<E> DisplayItem<E> {
text.text_run.get(), text.text_run.get(),
&text.range, &text.range,
baseline_origin, baseline_origin,
text.color); text.text_color);
}); });
let width = text.base.bounds.size.width; let width = text.base.bounds.size.width;
let underline_size = font_metrics.underline_size; let underline_size = font_metrics.underline_size;
@ -214,18 +219,18 @@ impl<E> DisplayItem<E> {
let underline_y = baseline_origin.y - underline_offset; let underline_y = baseline_origin.y - underline_offset;
let underline_bounds = Rect(Point2D(baseline_origin.x, underline_y), let underline_bounds = Rect(Point2D(baseline_origin.x, underline_y),
Size2D(width, underline_size)); 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() { if text_run.decoration.overline || text.flags.override_overline() {
let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y), let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y),
Size2D(width, underline_size)); 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() { if text_run.decoration.line_through || text.flags.override_line_through() {
let strikeout_y = baseline_origin.y - strikeout_offset; let strikeout_y = baseline_origin.y - strikeout_offset;
let strikeout_bounds = Rect(Point2D(baseline_origin.x, strikeout_y), let strikeout_bounds = Rect(Point2D(baseline_origin.x, strikeout_y),
Size2D(width, strikeout_size)); Size2D(width, strikeout_size));
render_context.draw_solid_color(&strikeout_bounds, text.color); render_context.draw_solid_color(&strikeout_bounds, text.line_through_color);
} }
} }

View file

@ -629,7 +629,7 @@ impl Flow for BlockFlow {
self.base.position.origin = Au::zero_point(); self.base.position.origin = Au::zero_point();
self.base.position.size.width = ctx.shared.screen_size.width; self.base.position.size.width = ctx.shared.screen_size.width;
self.base.floats_in = FloatContext::new(self.base.num_floats); 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. // 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; self.float.get_mut_ref().containing_width = remaining_width;
// Parent usually sets this, but floats are never inorder // 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() { for box_ in self.box_.iter() {
let style = box_.style(); let style = box_.style();
// The text alignment of a block flow is the text alignment of its box's 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. // Can compute padding here since we know containing block width.
box_.compute_padding(style, remaining_width); box_.compute_padding(style, remaining_width);
@ -702,27 +702,29 @@ impl Flow for BlockFlow {
let has_inorder_children = if self.is_float() { let has_inorder_children = if self.is_float() {
self.base.num_floats > 0 self.base.num_floats > 0
} else { } 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() { for kid in self.base.child_iter() {
assert!(kid.starts_block_flow() || kid.starts_inline_flow()); assert!(kid.starts_block_flow() || kid.starts_inline_flow());
let child_base = flow::mut_base(*kid); let child_base = flow::mut_base(*kid);
child_base.position.origin.x = x_offset; child_base.position.origin.x = x_offset;
child_base.position.size.width = remaining_width; 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); child_base.floats_in = FloatContext::new(0);
} }
// Per CSS 2.1 § 16.3.1, text decoration propagates to all children in flow. // 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. // 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)
} }
} }

View file

@ -35,7 +35,7 @@ use css::node_style::StyledNode;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor}; use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToGfxColor};
use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth}; use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
use layout::flow::Flow; use layout::flow::{Flow, FlowFlagsInfo};
use layout::flow; use layout::flow;
use layout::model::{MaybeAuto, specified, Auto, Specified}; use layout::model::{MaybeAuto, specified, Auto, Specified};
use layout::util::OpaqueNode; use layout::util::OpaqueNode;
@ -782,14 +782,26 @@ impl Box {
list.append_item(ClipDisplayItemClass(item)); 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. // 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(); let mut text_flags = TextDisplayItemFlags::new();
text_flags.set_override_underline(flow_flags.override_underline()); text_flags.set_override_underline(flow_flags.flags.override_underline());
text_flags.set_override_overline(flow_flags.override_overline()); text_flags.set_override_overline(flow_flags.flags.override_overline());
text_flags.set_override_line_through(flow_flags.override_line_through()); text_flags.set_override_line_through(flow_flags.flags.override_line_through());
// Create the text box. // Create the text box.
list.with_mut(|list| { list.with_mut(|list| {
@ -800,7 +812,10 @@ impl Box {
}, },
text_run: text_box.run.clone(), text_run: text_box.run.clone(),
range: text_box.range, 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, flags: text_flags,
}; };

View file

@ -407,8 +407,11 @@ impl<'fc> FlowConstructor<'fc> {
ConstructionItemConstructionResult(InlineBoxesConstructionItem( ConstructionItemConstructionResult(InlineBoxesConstructionItem(
InlineBoxesConstructionResult { InlineBoxesConstructionResult {
splits: opt_splits, 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. // Bubble up {ib} splits.
match opt_splits { match opt_splits {
None => {} 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. // Finally, make a new construction result.
if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 { if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 {
let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult { let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult {

View file

@ -42,6 +42,8 @@ use extra::container::Deque;
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
use gfx::display_list::{ClipDisplayItemClass, DisplayList}; use gfx::display_list::{ClipDisplayItemClass, DisplayList};
use layout::display_list_builder::ToGfxColor;
use gfx::color::Color;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::cast; use std::cast;
use std::cell::RefCell; 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. /// Flags used in flows, tightly packed to save space.
#[deriving(Clone)]
pub struct FlowFlags(u8); pub struct FlowFlags(u8);
/// The bitmask of flags that represent text decoration fields that get propagated downward. /// 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. /// NB: If you update this field, you must update the bitfields below.
static TEXT_ALIGN_SHIFT: u8 = 4; static TEXT_ALIGN_SHIFT: u8 = 4;
impl FlowFlags { impl FlowFlagsInfo {
/// Creates a new set of flow flags from the given style. /// 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 text_decoration = style.Text.text_decoration;
let mut flags = FlowFlags(0); let mut flags = FlowFlags(0);
flags.set_override_underline(text_decoration.underline); flags.set_override_underline(text_decoration.underline);
flags.set_override_overline(text_decoration.overline); flags.set_override_overline(text_decoration.overline);
flags.set_override_line_through(text_decoration.line_through); 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. /// 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) { pub fn propagate_text_decoration_from_parent(&mut self, parent: &FlowFlagsInfo) {
*self = FlowFlags(**self | (*parent & TEXT_DECORATION_OVERRIDE_BITMASK)) 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. /// Propagates text alignment flags from an appropriate parent flow per CSS 2.1.
pub fn propagate_text_alignment_from_parent(&mut self, parent: FlowFlags) { pub fn propagate_text_alignment_from_parent(&mut self, parent: &FlowFlagsInfo) {
*self = FlowFlags(**self | (*parent & TEXT_ALIGN_BITMASK)) 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) { pub fn set_text_align(&mut self, value: text_align::T) {
*self = FlowFlags((**self & !TEXT_ALIGN_BITMASK) | ((value as u8) << TEXT_ALIGN_SHIFT)) *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. /// Data common to all flows.
@ -365,8 +506,8 @@ pub struct BaseFlow {
num_floats: uint, num_floats: uint,
abs_position: Point2D<Au>, abs_position: Point2D<Au>,
/// Various flags for flows, tightly packed to save space. /// Various flags for flows and some info
flags: FlowFlags, flags_info: FlowFlagsInfo,
} }
pub struct BoxIterator { pub struct BoxIterator {
@ -409,7 +550,7 @@ impl BaseFlow {
num_floats: 0, num_floats: 0,
abs_position: Point2D(Au::new(0), Au::new(0)), abs_position: Point2D(Au::new(0), Au::new(0)),
flags: FlowFlags::new(style.get()), flags_info: FlowFlagsInfo::new(style.get()),
} }
} }

View file

@ -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() { for kid in self.base.child_iter() {
let child_base = flow::mut_base(*kid); let child_base = flow::mut_base(*kid);
child_base.position.size.width = self.base.position.size.width; child_base.position.size.width = self.base.position.size.width;
child_base.flags.set_inorder(self.base.flags.inorder()); child_base.flags_info.flags.set_inorder(self.base.flags_info.flags.inorder());
child_base.flags.propagate_text_alignment_from_parent(self.base.flags) child_base.flags_info.propagate_text_alignment_from_parent(&flags_info)
} }
// There are no child contexts, so stop here. // There are no child contexts, so stop here.
@ -689,7 +691,7 @@ impl Flow for InlineFlow {
let mut line_height_offset = Au::new(0); let mut line_height_offset = Au::new(0);
// All lines use text alignment of the flow. // 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. // Now, go through each line and lay out the boxes inside.
for line in self.lines.mut_iter() { for line in self.lines.mut_iter() {

View file

@ -186,7 +186,7 @@ impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
#[inline] #[inline]
fn should_process(&mut self, flow: &mut Flow) -> bool { fn should_process(&mut self, flow: &mut Flow) -> bool {
!flow::base(flow).flags.inorder() !flow::base(flow).flags_info.flags.inorder()
} }
} }

View file

@ -287,7 +287,7 @@ pub mod longhands {
"parse_non_negative")} "parse_non_negative")}
<%self:single_component_value name="line-height"> <%self:single_component_value name="line-height" inherited="True">
#[deriving(Clone)] #[deriving(Clone)]
pub enum SpecifiedValue { pub enum SpecifiedValue {
SpecifiedNormal, SpecifiedNormal,