mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
auto merge of #481 : eric93/servo/underline_tweak, r=metajack
Fix style problems with last PR. Also better propagation of text-decoration.
This commit is contained in:
commit
40cb22d270
10 changed files with 210 additions and 10 deletions
|
@ -9,7 +9,7 @@ use text::SendableTextRun;
|
||||||
|
|
||||||
use clone_arc = std::arc::clone;
|
use clone_arc = std::arc::clone;
|
||||||
use geom::Rect;
|
use geom::Rect;
|
||||||
use geom::Point2D;
|
use geom::{Point2D, Size2D};
|
||||||
use std::arc::ARC;
|
use std::arc::ARC;
|
||||||
use servo_net::image::base::Image;
|
use servo_net::image::base::Image;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
|
@ -56,6 +56,16 @@ pub impl<'self> DisplayItem {
|
||||||
let origin = self.d().bounds.origin;
|
let origin = self.d().bounds.origin;
|
||||||
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);
|
let baseline_origin = Point2D(origin.x, origin.y + font.metrics.ascent);
|
||||||
font.draw_text_into_context(ctx, new_run, range, baseline_origin, color);
|
font.draw_text_into_context(ctx, new_run, range, baseline_origin, color);
|
||||||
|
if(new_run.underline){
|
||||||
|
//TODO: Use the font metrics to properly position the underline bar
|
||||||
|
let width = self.d().bounds.size.width;
|
||||||
|
let u_size = font.metrics.underline_size;
|
||||||
|
let u_bounds = Rect(
|
||||||
|
Point2D(baseline_origin.x, baseline_origin.y),
|
||||||
|
Size2D(width, u_size)
|
||||||
|
);
|
||||||
|
ctx.draw_solid_color(&u_bounds, color);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
&Image(_, ref img) => {
|
&Image(_, ref img) => {
|
||||||
debug!("drawing image at %?", self.d().bounds);
|
debug!("drawing image at %?", self.d().bounds);
|
||||||
|
|
|
@ -181,11 +181,11 @@ pub impl FontGroup {
|
||||||
self.fonts = ~[];
|
self.fonts = ~[];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_textrun(&self, text: ~str) -> TextRun {
|
fn create_textrun(&self, text: ~str, underline: bool) -> TextRun {
|
||||||
assert!(self.fonts.len() > 0);
|
assert!(self.fonts.len() > 0);
|
||||||
|
|
||||||
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
|
// TODO(Issue #177): Actually fall back through the FontGroup when a font is unsuitable.
|
||||||
return TextRun::new(self.fonts[0], text);
|
return TextRun::new(self.fonts[0], text, underline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use servo_util::range::Range;
|
||||||
pub struct TextRun {
|
pub struct TextRun {
|
||||||
text: ~str,
|
text: ~str,
|
||||||
font: @mut Font,
|
font: @mut Font,
|
||||||
|
underline: bool,
|
||||||
glyphs: GlyphStore,
|
glyphs: GlyphStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ pub struct TextRun {
|
||||||
pub struct SendableTextRun {
|
pub struct SendableTextRun {
|
||||||
text: ~str,
|
text: ~str,
|
||||||
font: FontDescriptor,
|
font: FontDescriptor,
|
||||||
|
underline: bool,
|
||||||
priv glyphs: GlyphStore,
|
priv glyphs: GlyphStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,13 +34,14 @@ impl SendableTextRun {
|
||||||
TextRun {
|
TextRun {
|
||||||
text: copy self.text,
|
text: copy self.text,
|
||||||
font: font,
|
font: font,
|
||||||
|
underline: self.underline,
|
||||||
glyphs: copy self.glyphs
|
glyphs: copy self.glyphs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl<'self> TextRun {
|
pub impl<'self> TextRun {
|
||||||
fn new(font: @mut Font, text: ~str) -> TextRun {
|
fn new(font: @mut Font, text: ~str, underline: bool) -> TextRun {
|
||||||
let mut glyph_store = GlyphStore::new(str::char_len(text));
|
let mut glyph_store = GlyphStore::new(str::char_len(text));
|
||||||
TextRun::compute_potential_breaks(text, &mut glyph_store);
|
TextRun::compute_potential_breaks(text, &mut glyph_store);
|
||||||
font.shape_text(text, &mut glyph_store);
|
font.shape_text(text, &mut glyph_store);
|
||||||
|
@ -46,6 +49,7 @@ pub impl<'self> TextRun {
|
||||||
let run = TextRun {
|
let run = TextRun {
|
||||||
text: text,
|
text: text,
|
||||||
font: font,
|
font: font,
|
||||||
|
underline: underline,
|
||||||
glyphs: glyph_store,
|
glyphs: glyph_store,
|
||||||
};
|
};
|
||||||
return run;
|
return run;
|
||||||
|
@ -101,6 +105,7 @@ pub impl<'self> TextRun {
|
||||||
SendableTextRun {
|
SendableTextRun {
|
||||||
text: copy self.text,
|
text: copy self.text,
|
||||||
font: self.font.get_descriptor(),
|
font: self.font.get_descriptor(),
|
||||||
|
underline: self.underline,
|
||||||
glyphs: copy self.glyphs,
|
glyphs: copy self.glyphs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ use newcss::units::{Cursive, Em, Fantasy, Length, Monospace, Pt, Px, SansSerif,
|
||||||
use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
|
use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
|
||||||
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
|
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
|
||||||
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
|
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
|
||||||
use newcss::values::{CSSFontStyleOblique, CSSTextAlign};
|
use newcss::values::{CSSFontStyleOblique, CSSTextAlign, CSSTextDecoration};
|
||||||
|
use newcss::values::{CSSTextDecorationNone, CSSFloatNone, CSSPositionStatic};
|
||||||
|
use newcss::values::{CSSDisplayInlineBlock, CSSDisplayInlineTable};
|
||||||
use servo_net::image::holder::ImageHolder;
|
use servo_net::image::holder::ImageHolder;
|
||||||
use servo_net::local_image_cache::LocalImageCache;
|
use servo_net::local_image_cache::LocalImageCache;
|
||||||
use servo_util::range::*;
|
use servo_util::range::*;
|
||||||
|
@ -256,7 +258,7 @@ pub impl RenderBox {
|
||||||
fn can_merge_with_box(&self, other: RenderBox) -> bool {
|
fn can_merge_with_box(&self, other: RenderBox) -> bool {
|
||||||
match (self, &other) {
|
match (self, &other) {
|
||||||
(&UnscannedTextRenderBoxClass(*), &UnscannedTextRenderBoxClass(*)) => {
|
(&UnscannedTextRenderBoxClass(*), &UnscannedTextRenderBoxClass(*)) => {
|
||||||
self.font_style() == other.font_style()
|
self.font_style() == other.font_style() && self.text_decoration() == other.text_decoration()
|
||||||
},
|
},
|
||||||
(&TextRenderBoxClass(text_box_a), &TextRenderBoxClass(text_box_b)) => {
|
(&TextRenderBoxClass(text_box_a), &TextRenderBoxClass(text_box_b)) => {
|
||||||
managed::ptr_eq(text_box_a.text_data.run, text_box_b.text_data.run)
|
managed::ptr_eq(text_box_a.text_data.run, text_box_b.text_data.run)
|
||||||
|
@ -759,6 +761,46 @@ pub impl RenderBox {
|
||||||
fn text_align(&self) -> CSSTextAlign {
|
fn text_align(&self) -> CSSTextAlign {
|
||||||
self.nearest_ancestor_element().style().text_align()
|
self.nearest_ancestor_element().style().text_align()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the text decoration of the computed style of the nearest `Element` node
|
||||||
|
fn text_decoration(&self) -> CSSTextDecoration {
|
||||||
|
/// Computes the propagated value of text-decoration, as specified in CSS 2.1 § 16.3.1
|
||||||
|
/// TODO: make sure this works with anonymous box generation.
|
||||||
|
fn get_propagated_text_decoration(element: AbstractNode) -> CSSTextDecoration {
|
||||||
|
//Skip over non-element nodes in the DOM
|
||||||
|
if(!element.is_element()){
|
||||||
|
return match element.parent_node() {
|
||||||
|
None => CSSTextDecorationNone,
|
||||||
|
Some(parent) => get_propagated_text_decoration(parent),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//FIXME: is the root param on display() important?
|
||||||
|
let display_in_flow = match element.style().display(false) {
|
||||||
|
CSSDisplayInlineTable | CSSDisplayInlineBlock => false,
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let position = element.style().position();
|
||||||
|
let float = element.style().float();
|
||||||
|
|
||||||
|
let in_flow = (position == CSSPositionStatic) && (float == CSSFloatNone) &&
|
||||||
|
display_in_flow;
|
||||||
|
|
||||||
|
let text_decoration = element.style().text_decoration();
|
||||||
|
|
||||||
|
if(text_decoration == CSSTextDecorationNone && in_flow){
|
||||||
|
match element.parent_node() {
|
||||||
|
None => CSSTextDecorationNone,
|
||||||
|
Some(parent) => get_propagated_text_decoration(parent),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_decoration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_propagated_text_decoration(self.nearest_ancestor_element())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugMethods for RenderBox {
|
impl DebugMethods for RenderBox {
|
||||||
|
|
|
@ -21,6 +21,8 @@ use gfx::text::text_run::TextRun;
|
||||||
use gfx::text::util::*;
|
use gfx::text::util::*;
|
||||||
use newcss::values::{CSSTextAlignCenter, CSSTextAlignJustify, CSSTextAlignLeft};
|
use newcss::values::{CSSTextAlignCenter, CSSTextAlignJustify, CSSTextAlignLeft};
|
||||||
use newcss::values::{CSSTextAlignRight};
|
use newcss::values::{CSSTextAlignRight};
|
||||||
|
use newcss::values::CSSTextDecorationUnderline;
|
||||||
|
use newcss::values::CSSTextDecoration;
|
||||||
use servo_util::range::Range;
|
use servo_util::range::Range;
|
||||||
use std::deque::Deque;
|
use std::deque::Deque;
|
||||||
|
|
||||||
|
@ -243,6 +245,13 @@ impl TextRunScanner {
|
||||||
let inline = &mut *flow.inline();
|
let inline = &mut *flow.inline();
|
||||||
let in_boxes = &inline.boxes;
|
let in_boxes = &inline.boxes;
|
||||||
|
|
||||||
|
fn has_underline(decoration: CSSTextDecoration) -> bool{
|
||||||
|
match decoration {
|
||||||
|
CSSTextDecorationUnderline => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert!(self.clump.length() > 0);
|
assert!(self.clump.length() > 0);
|
||||||
|
|
||||||
debug!("TextRunScanner: flushing boxes in range=%?", self.clump);
|
debug!("TextRunScanner: flushing boxes in range=%?", self.clump);
|
||||||
|
@ -264,6 +273,7 @@ impl TextRunScanner {
|
||||||
let old_box = in_boxes[self.clump.begin()];
|
let old_box = in_boxes[self.clump.begin()];
|
||||||
let text = old_box.raw_text();
|
let text = old_box.raw_text();
|
||||||
let font_style = old_box.font_style();
|
let font_style = old_box.font_style();
|
||||||
|
let underline = has_underline(old_box.text_decoration());
|
||||||
|
|
||||||
// TODO(#115): Use the actual CSS `white-space` property of the relevant style.
|
// TODO(#115): Use the actual CSS `white-space` property of the relevant style.
|
||||||
let compression = CompressWhitespaceNewline;
|
let compression = CompressWhitespaceNewline;
|
||||||
|
@ -274,7 +284,7 @@ impl TextRunScanner {
|
||||||
// font group fonts. This is probably achieved by creating the font group above
|
// 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.
|
// 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 fontgroup = ctx.font_ctx.get_resolved_font_for_style(&font_style);
|
||||||
let run = @fontgroup.create_textrun(transformed_text);
|
let run = @fontgroup.create_textrun(transformed_text, underline);
|
||||||
|
|
||||||
debug!("TextRunScanner: pushing single text box in range: %?", self.clump);
|
debug!("TextRunScanner: pushing single text box in range: %?", self.clump);
|
||||||
let new_box = do old_box.with_imm_base |old_box_base| {
|
let new_box = do old_box.with_imm_base |old_box_base| {
|
||||||
|
@ -316,12 +326,13 @@ impl TextRunScanner {
|
||||||
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
// and then letting `FontGroup` decide which `Font` to stick into the text run.
|
||||||
let font_style = in_boxes[self.clump.begin()].font_style();
|
let font_style = in_boxes[self.clump.begin()].font_style();
|
||||||
let fontgroup = ctx.font_ctx.get_resolved_font_for_style(&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());
|
||||||
|
|
||||||
// TextRuns contain a cycle which is usually resolved by the teardown
|
// TextRuns contain a cycle which is usually resolved by the teardown
|
||||||
// sequence. If no clump takes ownership, however, it will leak.
|
// sequence. If no clump takes ownership, however, it will leak.
|
||||||
let clump = self.clump;
|
let clump = self.clump;
|
||||||
let run = if clump.length() != 0 {
|
let run = if clump.length() != 0 {
|
||||||
Some(@TextRun::new(fontgroup.fonts[0], run_str))
|
Some(@TextRun::new(fontgroup.fonts[0], run_str, underline))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 83ab48961487dc65d8921cc5ea829430e4e46f5e
|
Subproject commit e3057f02d48bf43856a0c13ad17372647f3b934f
|
|
@ -1 +1 @@
|
||||||
Subproject commit 01a90ed6771560ef4a84c42c0419c3e7e3b21abb
|
Subproject commit 36a651dd83089c01da888ee9b5fff14437d4bcb8
|
55
src/test/test_italic_bold.html
Normal file
55
src/test/test_italic_bold.html
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>The Book of Mozilla, 11:9</title>
|
||||||
|
<style type="text/css">
|
||||||
|
html {
|
||||||
|
background: maroon;
|
||||||
|
color: white;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
#moztext {
|
||||||
|
margin-top: 15%;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-family: serif;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#from {
|
||||||
|
font-size: 1.95em;
|
||||||
|
font-family: serif;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-size: 1.3em;
|
||||||
|
line-height: 0;
|
||||||
|
font-style: oblique;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p id="moztext">
|
||||||
|
Mammon slept. And the <em>beast reborn</em> spread over the earth and its numbers
|
||||||
|
grew legion. And they proclaimed the times and <em>sacrificed</em> crops unto the
|
||||||
|
fire, with the <em>cunning of foxes</em>. And they built a new world in their own
|
||||||
|
image as promised by the <em><a href="http://www.mozilla.org/about/mozilla-manifesto.html">
|
||||||
|
sacred words</a></em>, and <em><a href="http://wiki.mozilla.org/About:mozilla">spoke
|
||||||
|
</a></em> of the beast with their children. Mammon awoke, and lo! it was
|
||||||
|
<em>naught</em> but a follower.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p id="from">
|
||||||
|
from <strong>The Book of Mozilla,</strong> 11:9<br/><small>(10th Edition)</small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
60
src/test/test_underline.html
Normal file
60
src/test/test_underline.html
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>The Book of Mozilla, 11:9</title>
|
||||||
|
<style type="text/css">
|
||||||
|
html {
|
||||||
|
background: maroon;
|
||||||
|
color: white;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
#moztext {
|
||||||
|
margin-top: 15%;
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-family: serif;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.5;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#from {
|
||||||
|
font-size: 1.95em;
|
||||||
|
font-family: serif;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
em {
|
||||||
|
font-size: 1.3em;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p id="moztext">
|
||||||
|
Mammon slept. And the <em>beast reborn</em> spread over the earth and its numbers
|
||||||
|
grew legion. And they proclaimed the times and <em>sacrificed</em> crops unto the
|
||||||
|
fire, with the <em>cunning of foxes</em>. And they built a new world in their own
|
||||||
|
image as promised by the <em><a href="http://www.mozilla.org/about/mozilla-manifesto.html">
|
||||||
|
sacred words</a></em>, and <em><a href="http://wiki.mozilla.org/About:mozilla">spoke
|
||||||
|
</a></em> of the beast with their children. Mammon awoke, and lo! it was
|
||||||
|
<em>naught</em> but a follower.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p id="from">
|
||||||
|
from <strong>The Book of Mozilla,</strong> 11:9<br/><small>(10th Edition)</small>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
17
src/test/test_underline_helloworld.html
Normal file
17
src/test/test_underline_helloworld.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>The Book of Mozilla, 11:9</title>
|
||||||
|
<style type="text/css">
|
||||||
|
div { text-decoration: underline; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div>Hello</div>
|
||||||
|
|
||||||
|
<div>World</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue