auto merge of #932 : june0cho/servo/text_deco, r=metajack

Implement 'overline' and 'line-through' in 'text-decoration' property. Add a test case.
This commit is contained in:
bors-servo 2013-09-16 06:06:45 -07:00
commit 77a09b2003
8 changed files with 98 additions and 30 deletions

View file

@ -26,6 +26,8 @@ use servo_net::image::base::Image;
use servo_util::range::Range;
use extra::arc::Arc;
use newcss::values::{CSSTextDecorationUnderline, CSSTextDecorationOverline, CSSTextDecorationLineThrough};
/// A list of rendering operations to be performed.
pub struct DisplayList<E> {
list: ~[DisplayItem<E>]
@ -135,14 +137,31 @@ impl<E> DisplayItem<E> {
baseline_origin,
text.color);
if new_run.underline {
// TODO(eatkinson): Use the font metrics to properly position the underline
// bar.
let width = text.base.bounds.size.width;
let underline_size = font.metrics.underline_size;
let underline_bounds = Rect(Point2D(baseline_origin.x, baseline_origin.y),
Size2D(width, underline_size));
render_context.draw_solid_color(&underline_bounds, text.color);
let width = text.base.bounds.size.width;
let underline_size = font.metrics.underline_size;
let underline_offset = font.metrics.underline_offset;
let strikeout_size = font.metrics.strikeout_size;
let strikeout_offset = font.metrics.strikeout_offset;
match new_run.decoration {
CSSTextDecorationUnderline => {
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);
},
CSSTextDecorationOverline => {
let overline_bounds = Rect(Point2D(baseline_origin.x, origin.y),
Size2D(width, underline_size));
render_context.draw_solid_color(&overline_bounds, text.color);
},
CSSTextDecorationLineThrough => {
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);
},
_ => ()
}
}

View file

@ -28,6 +28,8 @@ use servo_util::time;
use servo_util::time::profile;
use servo_util::time::ProfilerChan;
use newcss::values::CSSTextDecoration;
// FontHandle encapsulates access to the platform's font API,
// e.g. quartz, FreeType. It provides access to metrics and tables
// needed by the text shaper as well as access to the underlying font
@ -80,6 +82,8 @@ pub trait FontTableMethods {
pub struct FontMetrics {
underline_size: Au,
underline_offset: Au,
strikeout_size: Au,
strikeout_offset: Au,
leading: Au,
x_height: Au,
em_size: Au,
@ -191,11 +195,11 @@ impl FontGroup {
self.fonts = ~[];
}
pub fn create_textrun(&self, text: ~str, underline: bool) -> TextRun {
pub fn create_textrun(&self, text: ~str, decoration: CSSTextDecoration) -> TextRun {
assert!(self.fonts.len() > 0);
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
return TextRun::new(self.fonts[0], text, underline);
return TextRun::new(self.fonts[0], text, decoration);
}
}

View file

@ -219,6 +219,7 @@ impl FontHandleMethods for FontHandle {
}
}
#[fixed_stack_segment]
fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */
let face = self.get_face_rec();
@ -230,11 +231,26 @@ impl FontHandleMethods for FontHandle {
let descent = self.font_units_to_au(face.descender as float);
let max_advance = self.font_units_to_au(face.max_advance_width as float);
let mut strikeout_size = geometry::from_pt(0.0);
let mut strikeout_offset = geometry::from_pt(0.0);
let mut x_height = geometry::from_pt(0.0);
unsafe {
let os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2) as *TT_OS2;
let valid = os2.is_not_null() && (*os2).version != 0xffff;
if valid {
strikeout_size = self.font_units_to_au((*os2).yStrikeoutSize as float);
strikeout_offset = self.font_units_to_au((*os2).yStrikeoutPosition as float);
x_height = self.font_units_to_au((*os2).sxHeight as float);
}
}
return FontMetrics {
underline_size: underline_size,
underline_offset: underline_offset,
strikeout_size: strikeout_size,
strikeout_offset: strikeout_offset,
leading: geometry::from_pt(0.0), //FIXME
x_height: geometry::from_pt(0.0), //FIXME
x_height: x_height,
em_size: em_size,
ascent: ascent,
descent: -descent, // linux font's seem to use the opposite sign from mac

View file

@ -219,6 +219,7 @@ impl FontHandleMethods for FontHandle {
}
}
#[fixed_stack_segment]
fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */
let face = self.get_face_rec();
@ -230,11 +231,26 @@ impl FontHandleMethods for FontHandle {
let descent = self.font_units_to_au(face.descender as float);
let max_advance = self.font_units_to_au(face.max_advance_width as float);
let mut strikeout_size = geometry::from_pt(0.0);
let mut strikeout_offset = geometry::from_pt(0.0);
let mut x_height = geometry::from_pt(0.0);
unsafe {
let os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2) as *TT_OS2;
let valid = os2.is_not_null() && (*os2).version != 0xffff;
if valid {
strikeout_size = self.font_units_to_au((*os2).yStrikeoutSize as float);
strikeout_offset = self.font_units_to_au((*os2).yStrikeoutPosition as float);
x_height = self.font_units_to_au((*os2).sxHeight as float);
}
}
return FontMetrics {
underline_size: underline_size,
underline_offset: underline_offset,
strikeout_size: strikeout_size,
strikeout_offset: strikeout_offset,
leading: geometry::from_pt(0.0), //FIXME
x_height: geometry::from_pt(0.0), //FIXME
x_height: x_height,
em_size: em_size,
ascent: ascent,
descent: -descent, // linux font's seem to use the opposite sign from mac

View file

@ -13,6 +13,7 @@ use font::{FontTableTag, FontWeight100, FontWeight200, FontWeight300, FontWeight
use font::{FontWeight500, FontWeight600, FontWeight700, FontWeight800, FontWeight900};
use font::{FractionalPixel, SpecifiedFontStyle};
use geometry::{Au, px_to_pt};
use geometry;
use platform::macos::font_context::FontContextHandle;
use text::glyph::GlyphIndex;
@ -171,6 +172,8 @@ impl FontHandleMethods for FontHandle {
// see also: https://bugs.webkit.org/show_bug.cgi?id=16768
// see also: https://bugreports.qt-project.org/browse/QTBUG-13364
underline_offset: Au::from_pt(self.ctfont.underline_position() as float),
strikeout_size: geometry::from_pt(0.0), // FIXME(Issue #942)
strikeout_offset: geometry::from_pt(0.0), // FIXME(Issue #942)
leading: Au::from_pt(self.ctfont.leading() as float),
x_height: Au::from_pt(self.ctfont.x_height() as float),
em_size: em_size,

View file

@ -10,12 +10,13 @@ use text::glyph::GlyphStore;
use font::{Font, FontDescriptor, RunMetrics};
use servo_util::range::Range;
use extra::arc::Arc;
use newcss::values::CSSTextDecoration;
/// A text run.
pub struct TextRun {
text: ~str,
font: @mut Font,
underline: bool,
decoration: CSSTextDecoration,
glyphs: ~[Arc<GlyphStore>],
}
@ -23,7 +24,7 @@ pub struct TextRun {
pub struct SendableTextRun {
text: ~str,
font: FontDescriptor,
underline: bool,
decoration: CSSTextDecoration,
priv glyphs: ~[Arc<GlyphStore>],
}
@ -37,7 +38,7 @@ impl SendableTextRun {
TextRun {
text: self.text.clone(),
font: font,
underline: self.underline,
decoration: self.decoration,
glyphs: self.glyphs.clone(),
}
}
@ -116,13 +117,13 @@ impl<'self> Iterator<Range> for LineIterator<'self> {
}
impl<'self> TextRun {
pub fn new(font: @mut Font, text: ~str, underline: bool) -> TextRun {
pub fn new(font: @mut Font, text: ~str, decoration: CSSTextDecoration) -> TextRun {
let glyphs = TextRun::break_and_shape(font, text);
let run = TextRun {
text: text,
font: font,
underline: underline,
decoration: decoration,
glyphs: glyphs,
};
return run;
@ -191,7 +192,7 @@ impl<'self> TextRun {
SendableTextRun {
text: self.text.clone(),
font: self.font.get_descriptor(),
underline: self.underline,
decoration: self.decoration,
glyphs: self.glyphs.clone(),
}
}

View file

@ -12,7 +12,6 @@ use layout::box::{RenderBox, RenderBoxBase, TextRenderBox};
use layout::box::{TextRenderBoxClass, UnscannedTextRenderBoxClass};
use layout::context::LayoutContext;
use layout::flow::FlowContext;
use newcss::values::{CSSTextDecoration, CSSTextDecorationUnderline};
use servo_util::range::Range;
@ -128,13 +127,6 @@ impl TextRunScanner {
let inline = flow.inline();
let in_boxes = &inline.boxes;
fn has_underline(decoration: CSSTextDecoration) -> bool{
match decoration {
CSSTextDecorationUnderline => true,
_ => false
}
}
assert!(self.clump.length() > 0);
debug!("TextRunScanner: flushing boxes in range=%?", self.clump);
@ -158,7 +150,7 @@ impl TextRunScanner {
let old_box = in_boxes[self.clump.begin()];
let text = old_box.raw_text();
let font_style = old_box.font_style();
let underline = has_underline(old_box.text_decoration());
let decoration = old_box.text_decoration();
// TODO(#115): Use the actual CSS `white-space` property of the relevant style.
let compression = CompressWhitespaceNewline;
@ -171,7 +163,7 @@ impl TextRunScanner {
// font group fonts. This is probably achieved by creating the font group above
// and then letting `FontGroup` decide which `Font` to stick into the text run.
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let run = @fontgroup.create_textrun(transformed_text, underline);
let run = @fontgroup.create_textrun(transformed_text, decoration);
debug!("TextRunScanner: pushing single text box in range: %? (%?)", self.clump, text);
let new_box = do old_box.with_base |old_box_base| {
@ -220,13 +212,13 @@ impl TextRunScanner {
// and then letting `FontGroup` decide which `Font` to stick into the text run.
let font_style = in_boxes[self.clump.begin()].font_style();
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
let underline = has_underline(in_boxes[self.clump.begin()].text_decoration());
let decoration = in_boxes[self.clump.begin()].text_decoration();
// TextRuns contain a cycle which is usually resolved by the teardown
// sequence. If no clump takes ownership, however, it will leak.
let clump = self.clump;
let run = if clump.length() != 0 && run_str.len() > 0 {
Some(@TextRun::new(fontgroup.fonts[0], run_str, underline))
Some(@TextRun::new(fontgroup.fonts[0], run_str, decoration))
} else {
None
};

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p style="text-decoration:none;"> none </p>
<p style="text-decoration:underline;"> text underline </p>
<p style="text-decoration:overline;"> text underline </p>
<p style="text-decoration:line-through;"> text underline </p>
<p>
<p style="font-size:40px; text-decoration:underline; font-family:Verdana;"> text underline pqrstg </p>
<p style="text-decoration:overline;"> text overline xxxxxxxxXXXXXXX</p>
<p style="font-size:50px; text-decoration:line-through;"> text line-through xxxxxxxxXXXXX</p>
<p style="text-decoration:blink;"> text blink </p>
</body>
</html>