mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
fix text-decoration property in layout
This commit is contained in:
parent
d11e431887
commit
b0380ae96a
6 changed files with 97 additions and 34 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,7 +702,7 @@ 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
|
||||||
};
|
};
|
||||||
|
|
||||||
for kid in self.base.child_iter() {
|
for kid in self.base.child_iter() {
|
||||||
|
@ -711,18 +711,20 @@ impl Flow for BlockFlow {
|
||||||
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)
|
// FIXME(ksh8281): avoid copy
|
||||||
|
child_base.flags_info.propagate_text_decoration_from_parent(self.base.flags_info);
|
||||||
|
|
||||||
|
child_base.flags_info.propagate_text_alignment_from_parent(self.base.flags_info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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, Auto, specified};
|
use layout::model::{MaybeAuto, Auto, specified};
|
||||||
use layout::util::OpaqueNode;
|
use layout::util::OpaqueNode;
|
||||||
|
@ -747,14 +747,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;
|
||||||
|
|
||||||
|
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| {
|
||||||
|
@ -765,7 +777,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,
|
||||||
|
underline_color: flow_flags.underline_color,
|
||||||
|
line_through_color: flow_flags.line_through_color,
|
||||||
flags: text_flags,
|
flags: text_flags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,6 +259,15 @@ pub trait PostorderFlowTraversal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FlowFlagsInfo{
|
||||||
|
flags: FlowFlags,
|
||||||
|
|
||||||
|
/// text-decoration colors
|
||||||
|
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.
|
||||||
pub struct FlowFlags(u8);
|
pub struct FlowFlags(u8);
|
||||||
|
|
||||||
|
@ -275,25 +286,44 @@ 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 underline_color = style.Color.color.to_gfx_color();
|
||||||
|
let overline_color = style.Color.color.to_gfx_color();
|
||||||
|
let line_through_color = style.Color.color.to_gfx_color();
|
||||||
|
FlowFlagsInfo {
|
||||||
|
flags: flags,
|
||||||
|
underline_color: underline_color,
|
||||||
|
overline_color: overline_color,
|
||||||
|
line_through_color: line_through_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 !self.flags.override_underline() && parent.flags.override_underline() {
|
||||||
|
self.underline_color = parent.underline_color;
|
||||||
|
}
|
||||||
|
if !self.flags.override_overline() && parent.flags.override_overline() {
|
||||||
|
self.overline_color = parent.overline_color;
|
||||||
|
}
|
||||||
|
if !self.flags.override_line_through() && parent.flags.override_line_through() {
|
||||||
|
self.line_through_color = parent.line_through_color;
|
||||||
|
}
|
||||||
|
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 +356,16 @@ 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
|
@ -365,8 +405,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 +449,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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -643,8 +643,9 @@ impl Flow for InlineFlow {
|
||||||
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)
|
// FIXME(ksh8281) avoid copy
|
||||||
|
child_base.flags_info.propagate_text_alignment_from_parent(self.base.flags_info)
|
||||||
}
|
}
|
||||||
// There are no child contexts, so stop here.
|
// There are no child contexts, so stop here.
|
||||||
|
|
||||||
|
@ -685,7 +686,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() {
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue