auto merge of #4311 : pcwalton/servo/text-transform, r=SimonSapin

The Unicode awareness of `text-transform` is implemented as well as
possible given the Rust standard library's Unicode support. In
particular, the notion of an alphabetic character is used instead of a
letter.

Gecko has a subclass of text run to handle text transforms, but I
implemented this in a simpler way.

r? @SimonSapin
This commit is contained in:
bors-servo 2014-12-10 15:12:58 -07:00
commit 9bf1d1862a
11 changed files with 132 additions and 2 deletions

View file

@ -22,7 +22,7 @@ use servo_util::smallvec::{SmallVec, SmallVec1};
use std::collections::DList; use std::collections::DList;
use std::mem; use std::mem;
use style::ComputedValues; use style::ComputedValues;
use style::computed_values::{line_height, text_orientation, white_space}; use style::computed_values::{line_height, text_orientation, text_transform, white_space};
use style::style_structs::Font as FontStyle; use style::style_structs::Font as FontStyle;
use sync::Arc; use sync::Arc;
@ -104,6 +104,7 @@ impl TextRunScanner {
let run = { let run = {
let fontgroup; let fontgroup;
let compression; let compression;
let text_transform;
{ {
let in_fragment = self.clump.front().unwrap(); let in_fragment = self.clump.front().unwrap();
let font_style = in_fragment.style().get_font_arc(); let font_style = in_fragment.style().get_font_arc();
@ -111,7 +112,8 @@ impl TextRunScanner {
compression = match in_fragment.white_space() { compression = match in_fragment.white_space() {
white_space::normal | white_space::nowrap => CompressWhitespaceNewline, white_space::normal | white_space::nowrap => CompressWhitespaceNewline,
white_space::pre => CompressNone, white_space::pre => CompressNone,
} };
text_transform = in_fragment.style().get_inheritedtext().text_transform;
} }
// First, transform/compress text of all the nodes. // First, transform/compress text of all the nodes.
@ -136,6 +138,10 @@ impl TextRunScanner {
char_total = char_total + added_chars; char_total = char_total + added_chars;
} }
// Account for `text-transform`. (Confusingly, this is not handled in "text
// transformation" above, but we follow Gecko in the naming.)
self.apply_style_transform_if_necessary(&mut run_text, text_transform);
// Now create the run. // Now create the run.
// //
// TextRuns contain a cycle which is usually resolved by the teardown sequence. // TextRuns contain a cycle which is usually resolved by the teardown sequence.
@ -176,6 +182,55 @@ impl TextRunScanner {
last_whitespace last_whitespace
} }
/// Accounts for `text-transform`.
///
/// FIXME(#4311, pcwalton): Case mapping can change length of the string; case mapping should
/// be language-specific; `full-width`; use graphemes instead of characters.
fn apply_style_transform_if_necessary(&mut self,
string: &mut String,
text_transform: text_transform::T) {
match text_transform {
text_transform::none => {}
text_transform::uppercase => {
let length = string.len();
let original = mem::replace(string, String::with_capacity(length));
for character in original.chars() {
string.push(character.to_uppercase())
}
}
text_transform::lowercase => {
let length = string.len();
let original = mem::replace(string, String::with_capacity(length));
for character in original.chars() {
string.push(character.to_lowercase())
}
}
text_transform::capitalize => {
let length = string.len();
let original = mem::replace(string, String::with_capacity(length));
let mut capitalize_next_letter = true;
for character in original.chars() {
// FIXME(#4311, pcwalton): Should be the CSS/Unicode notion of a *typographic
// letter unit*, not an *alphabetic* character:
//
// http://dev.w3.org/csswg/css-text/#typographic-letter-unit
if capitalize_next_letter && character.is_alphabetic() {
string.push(character.to_uppercase());
capitalize_next_letter = false;
continue
}
string.push(character);
// FIXME(#4311, pcwalton): Try UAX29 instead of just whitespace.
if character.is_whitespace() {
capitalize_next_letter = true
}
}
}
}
}
} }
struct NewLinePositions(Vec<CharIndex>); struct NewLinePositions(Vec<CharIndex>);

View file

@ -1185,6 +1185,9 @@ pub mod longhands {
${single_keyword("white-space", "normal pre nowrap")} ${single_keyword("white-space", "normal pre nowrap")}
// TODO(pcwalton): `full-width`
${single_keyword("text-transform", "none capitalize uppercase lowercase")}
// CSS 2.1, Section 17 - Tables // CSS 2.1, Section 17 - Tables
${new_style_struct("Table", is_inherited=False)} ${new_style_struct("Table", is_inherited=False)}

View file

@ -187,3 +187,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
== incremental_float_a.html incremental_float_ref.html == incremental_float_a.html incremental_float_ref.html
== opacity_simple_a.html opacity_simple_ref.html == opacity_simple_a.html opacity_simple_ref.html
== opacity_stacking_context_a.html opacity_stacking_context_ref.html == opacity_stacking_context_a.html opacity_stacking_context_ref.html
== text_transform_none_a.html text_transform_none_ref.html
== text_transform_uppercase_a.html text_transform_uppercase_ref.html
== text_transform_lowercase_a.html text_transform_lowercase_ref.html
== text_transform_capitalize_a.html text_transform_capitalize_ref.html

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: capitalize` works. -->
<body>
<h1 style='text-transform: capitalize; font-family: Hiragino Maru Gothic Pro'>ュゥゥゥゥ can do ányThing at ゾムボ.cOm</h1>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: capitalize` works. -->
<body>
<h1 style='font-family: Hiragino Maru Gothic Pro'>ュゥゥゥゥ Can Do ÁnyThing At ゾムボ.cOm</h1>
</body>
</html>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: lowercase` works. -->
<body>
<h1 style='text-transform: lowercase; font-family: Hiragino Maru Gothic Pro'>YoU CaN dO ÁnYtHiNg At ゾムボ.cOm</h1>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: lowercase` works. -->
<body>
<h1 style='font-family: Hiragino Maru Gothic Pro'>you can do ánything at ゾムボ.com</h1>
</body>
</html>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: none` works. -->
<body>
<h1 style='text-transform: none; font-family: Hiragino Maru Gothic Pro'>You can do anything at ゾムボ.com</h1>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: none` works. -->
<body>
<h1 style='font-family: Hiragino Maru Gothic Pro'>You can do anything at ゾムボ.com</h1>
</body>
</html>

View file

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: uppercase` works. -->
<body>
<h1 style='text-transform: uppercase; font-family: Hiragino Maru Gothic Pro'>You çan do anything at ゾムボ.com</h1>
</body>
</html>

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<!-- Tests that `text-transform: uppercase` works. -->
<body>
<h1 style='font-family: Hiragino Maru Gothic Pro'>YOU ÇAN DO ANYTHING AT ゾムボ.COM</h1>
</body>
</html>