servo: Merge #7013 - Make the Ahem font available to test-css and test-wpt tests (from servo:user-stylesheets); r=mbrubeck

Add support for user stylesheets, and provide one to tests with an `@font-face` rule for it.

Fix #6195.

Many previously-failing tests now pass, and a few previously-passing now fail.

Among the latter, `font-family-013.htm` and `fonts-013.htm` are testing that the Ahem font is not used for characters it doesn’t have a glyph for. They were passing because Ahem was not available at all, and now fail because we don’t implement font fallback correctly.

The others also use Ahem, but I don’t understand yet what’s going on exactly.

Source-Repo: https://github.com/servo/servo
Source-Revision: 08987e3eda370e3eb00876c7f5efdebf3ba0265a
This commit is contained in:
Simon Sapin 2015-08-07 14:05:19 -06:00
parent 47428352a3
commit 5a1ac2d8f1
14 changed files with 161 additions and 43 deletions

View File

@ -297,6 +297,14 @@ impl<'a> DerefMut for RWGuard<'a> {
}
}
fn add_font_face_rules(stylesheet: &Stylesheet, device: &Device, font_cache_task: &FontCacheTask) {
for font_face in stylesheet.effective_rules(&device).font_face() {
for source in font_face.sources.iter() {
font_cache_task.add_web_font(font_face.family.clone(), source.clone());
}
}
}
impl LayoutTask {
/// Creates a new `LayoutTask` structure.
fn new(id: PipelineId,
@ -336,6 +344,11 @@ impl LayoutTask {
let image_cache_receiver =
ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_image_cache_receiver);
let stylist = box Stylist::new(device);
for user_or_user_agent_stylesheet in stylist.stylesheets() {
add_font_face_rules(user_or_user_agent_stylesheet, &stylist.device, &font_cache_task);
}
LayoutTask {
id: id,
url: url,
@ -362,7 +375,7 @@ impl LayoutTask {
constellation_chan: constellation_chan,
screen_size: screen_size,
stacking_context: None,
stylist: box Stylist::new(device),
stylist: stylist,
parallel_traversal: parallel_traversal,
dirty: Rect::zero(),
generation: 0,
@ -735,11 +748,7 @@ impl LayoutTask {
let mut rw_data = self.lock_rw_data(possibly_locked_rw_data);
if mq.evaluate(&rw_data.stylist.device) {
for font_face in sheet.effective_rules(&rw_data.stylist.device).font_face() {
for source in font_face.sources.iter() {
self.font_cache_task.add_web_font(font_face.family.clone(), source.clone());
}
}
add_font_face_rules(&sheet, &rw_data.stylist.device, &self.font_cache_task);
rw_data.stylist.add_stylesheet(sheet);
}

View File

@ -462,6 +462,14 @@ dependencies = [
"winapi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getopts"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gfx"
version = "0.0.1"
@ -1521,6 +1529,7 @@ dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"html5ever 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)",
"js 0.1.0 (git+https://github.com/servo/rust-mozjs)",

View File

@ -12,6 +12,7 @@ use selectors::Element;
use std::process;
use smallvec::VecLike;
use util::resource_files::read_resource_file;
use util::opts;
use legacy::PresentationalHintSynthesis;
use media_queries::Device;
@ -76,9 +77,18 @@ impl Stylist {
}
}
}
for &(ref contents, ref url) in &opts::get().user_stylesheets {
stylist.add_stylesheet(Stylesheet::from_bytes(
&contents, url.clone(), None, None, Origin::User));
}
stylist
}
#[inline]
pub fn stylesheets(&self) -> &[Stylesheet] {
&self.stylesheets
}
pub fn constrain_viewport(&self) -> Option<ViewportConstraints> {
let cascaded_rule = self.stylesheets.iter()
.flat_map(|s| s.effective_rules(&self.device).viewport())

View File

@ -53,3 +53,4 @@ serde = "0.4"
serde_macros = "0.4"
string_cache = "0.1"
lazy_static = "0.1"
getopts = "0.2.11"

View File

@ -14,7 +14,6 @@
#![feature(optin_builtin_traits)]
#![feature(path_ext)]
#![feature(plugin)]
#![feature(rustc_private)]
#![feature(slice_splits)]
#![feature(step_by)]
#![feature(step_trait)]

View File

@ -8,13 +8,13 @@
use geometry::ScreenPx;
use euclid::size::{Size2D, TypedSize2D};
use getopts;
use getopts::Options;
use num_cpus;
use std::collections::HashSet;
use std::cmp;
use std::env;
use std::io::{self, Write};
use std::fs::PathExt;
use std::io::{self, Read, Write};
use std::fs::{File, PathExt};
use std::path::Path;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
@ -66,6 +66,8 @@ pub struct Opts {
/// won't be loaded
pub userscripts: Option<String>,
pub user_stylesheets: Vec<(Vec<u8>, Url)>,
pub output_file: Option<String>,
/// Replace unpaires surrogates in DOM strings with U+FFFD.
@ -172,9 +174,9 @@ pub struct Opts {
pub exit_after_load: bool,
}
fn print_usage(app: &str, opts: &[getopts::OptGroup]) {
fn print_usage(app: &str, opts: &Options) {
let message = format!("Usage: {} [ options ... ] [URL]\n\twhere options include", app);
println!("{}", getopts::usage(&message, opts));
println!("{}", opts.usage(&message));
}
pub fn print_debug_usage(app: &str) -> ! {
@ -241,6 +243,7 @@ pub fn default_opts() -> Opts {
nonincremental_layout: false,
nossl: false,
userscripts: None,
user_stylesheets: Vec::new(),
output_file: None,
replace_surrogates: false,
gc_profile: false,
@ -278,37 +281,38 @@ pub fn default_opts() -> Opts {
pub fn from_cmdline_args(args: &[String]) {
let (app_name, args) = args.split_first().unwrap();
let opts = vec!(
getopts::optflag("c", "cpu", "CPU painting (default)"),
getopts::optflag("g", "gpu", "GPU painting"),
getopts::optopt("o", "output", "Output file", "output.png"),
getopts::optopt("s", "size", "Size of tiles", "512"),
getopts::optopt("", "device-pixel-ratio", "Device pixels per px", ""),
getopts::optflag("e", "experimental", "Enable experimental web features"),
getopts::optopt("t", "threads", "Number of paint threads", "1"),
getopts::optflagopt("p", "profile", "Profiler flag and output interval", "10"),
getopts::optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10"),
getopts::optflag("x", "exit", "Exit after load flag"),
getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"),
getopts::optflag("i", "nonincremental-layout", "Enable to turn off incremental layout."),
getopts::optflag("", "no-ssl", "Disables ssl certificate verification."),
getopts::optflagopt("", "userscripts",
"Uses userscripts in resources/user-agent-js, or a specified full path",""),
getopts::optflag("z", "headless", "Headless mode"),
getopts::optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure"),
getopts::optflagopt("", "devtools", "Start remote devtools server on port", "6000"),
getopts::optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000"),
getopts::optopt("", "resolution", "Set window resolution.", "800x600"),
getopts::optopt("u", "user-agent", "Set custom user agent string", "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)"),
getopts::optflag("M", "multiprocess", "Run in multiprocess mode"),
getopts::optopt("Z", "debug",
"A comma-separated string of debug options. Pass help to show available options.", ""),
getopts::optflag("h", "help", "Print this message"),
getopts::optopt("", "resources-path", "Path to find static resources", "/home/servo/resources"),
getopts::optflag("", "sniff-mime-types" , "Enable MIME sniffing"),
);
let mut opts = Options::new();
opts.optflag("c", "cpu", "CPU painting (default)");
opts.optflag("g", "gpu", "GPU painting");
opts.optopt("o", "output", "Output file", "output.png");
opts.optopt("s", "size", "Size of tiles", "512");
opts.optopt("", "device-pixel-ratio", "Device pixels per px", "");
opts.optflag("e", "experimental", "Enable experimental web features");
opts.optopt("t", "threads", "Number of paint threads", "1");
opts.optflagopt("p", "profile", "Profiler flag and output interval", "10");
opts.optflagopt("m", "memory-profile", "Memory profiler flag and output interval", "10");
opts.optflag("x", "exit", "Exit after load flag");
opts.optopt("y", "layout-threads", "Number of threads to use for layout", "1");
opts.optflag("i", "nonincremental-layout", "Enable to turn off incremental layout.");
opts.optflag("", "no-ssl", "Disables ssl certificate verification.");
opts.optflagopt("", "userscripts",
"Uses userscripts in resources/user-agent-js, or a specified full path","");
opts.optmulti("", "user-stylesheet",
"A user stylesheet to be added to every document", "file.css");
opts.optflag("z", "headless", "Headless mode");
opts.optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure");
opts.optflagopt("", "devtools", "Start remote devtools server on port", "6000");
opts.optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000");
opts.optopt("", "resolution", "Set window resolution.", "800x600");
opts.optopt("u", "user-agent", "Set custom user agent string", "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)");
opts.optflag("M", "multiprocess", "Run in multiprocess mode");
opts.optopt("Z", "debug",
"A comma-separated string of debug options. Pass help to show available options.", "");
opts.optflag("h", "help", "Print this message");
opts.optopt("", "resources-path", "Path to find static resources", "/home/servo/resources");
opts.optflag("", "sniff-mime-types" , "Enable MIME sniffing");
let opt_match = match getopts::getopts(args, &opts) {
let opt_match = match opts.parse(args) {
Ok(m) => m,
Err(f) => args_fail(&f.to_string()),
};
@ -330,12 +334,12 @@ pub fn from_cmdline_args(args: &[String]) {
print_debug_usage(app_name)
}
let cwd = env::current_dir().unwrap();
let url = if opt_match.free.is_empty() {
print_usage(app_name, &opts);
args_fail("servo asks that you provide a URL")
} else {
let ref url = opt_match.free[0];
let cwd = env::current_dir().unwrap();
match Url::parse(url) {
Ok(url) => url,
Err(url::ParseError::RelativeUrlWithoutBase) => {
@ -407,6 +411,17 @@ pub fn from_cmdline_args(args: &[String]) {
}
};
let user_stylesheets = opt_match.opt_strs("user-stylesheet").iter().map(|filename| {
let path = cwd.join(filename);
let url = Url::from_file_path(&path).unwrap();
let mut contents = Vec::new();
File::open(path)
.unwrap_or_else(|err| args_fail(&format!("Couldnt open {}: {}", filename, err)))
.read_to_end(&mut contents)
.unwrap_or_else(|err| args_fail(&format!("Couldnt read {}: {}", filename, err)));
(contents, url)
}).collect();
let opts = Opts {
url: Some(url),
paint_threads: paint_threads,
@ -420,6 +435,7 @@ pub fn from_cmdline_args(args: &[String]) {
nonincremental_layout: nonincremental_layout,
nossl: nossl,
userscripts: opt_match.opt_default("userscripts", ""),
user_stylesheets: user_stylesheets,
output_file: opt_match.opt_str("o"),
replace_surrogates: debug_options.contains(&"replace-surrogates"),
gc_profile: debug_options.contains(&"gc-profile"),

4
servo/resources/ahem.css Normal file
View File

@ -0,0 +1,4 @@
@font-face {
font-family: Ahem;
src: url(ahem/AHEM____.TTF);
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1 @@
The files in this directory are copied from http://www.w3.org/Style/CSS/Test/Fonts/Ahem/

View File

@ -0,0 +1,36 @@
The Ahem font in this directory belongs to the public domain. In
jurisdictions that do not recognize public domain ownership of these
files, the following Creative Commons Zero declaration applies:
<http://labs.creativecommons.org/licenses/zero-waive/1.0/us/legalcode>
which is quoted below:
The person who has associated a work with this document (the "Work")
affirms that he or she (the "Affirmer") is the/an author or owner of
the Work. The Work may be any work of authorship, including a
database.
The Affirmer hereby fully, permanently and irrevocably waives and
relinquishes all of her or his copyright and related or neighboring
legal rights in the Work available under any federal or state law,
treaty or contract, including but not limited to moral rights,
publicity and privacy rights, rights protecting against unfair
competition and any rights protecting the extraction, dissemination
and reuse of data, whether such rights are present or future, vested
or contingent (the "Waiver"). The Affirmer makes the Waiver for the
benefit of the public at large and to the detriment of the Affirmer's
heirs or successors.
The Affirmer understands and intends that the Waiver has the effect
of eliminating and entirely removing from the Affirmer's control all
the copyright and related or neighboring legal rights previously held
by the Affirmer in the Work, to that extent making the Work freely
available to the public for any and all uses and purposes without
restriction of any kind, including commercial use and uses in media
and formats or by methods that have not yet been invented or
conceived. Should the Waiver for any reason be judged legally
ineffective in any jurisdiction, the Affirmer hereby grants a free,
full, permanent, irrevocable, nonexclusive and worldwide license for
all her or his copyright and related or neighboring legal rights in
the Work.

View File

@ -0,0 +1,30 @@
The Ahem font was developed by Todd Fahrner to help test writers
develop predictable tests. The font's em square is exactly square.
Its ascent and descent is exactly the size of the em square. This
means that the font's extent is exactly the same as its line-height,
meaning that it can be exactly aligned with padding, borders, margins,
and so forth.
The font's alphabetic baseline is 0.2em above its bottom, and 0.8em
below its top. The font has an x-height of 0.8em.
The font has four glyphs:
'X' U+0058 A square exactly 1em in height and width.
'p' U+0070 A rectangle exactly 0.2em high, 1em wide, and aligned so
that its top is flush with the baseline.
'É' U+00C9 A rectangle exactly 0.8em high, 1em wide, and aligned so
that its bottom is flush with the baseline.
' ' U+0020 A transparent space exactly 1em high and wide.
Most other US-ASCII characters in the font have the same glyph as X.
The Ahem font belongs to the public domain as described in COPYING.
Acknowledgements: The font was originally created by Todd Fahrner in
the late 90s, and was updated by Paul Nelson in the mid 2000s. The
changes were the introduction of x-height information to the OS/2
table and the addition of the space and non-breaking space glyphs.

View File

@ -19,6 +19,7 @@
extern crate png;
extern crate test;
extern crate url;
extern crate util;
use std::env;
use std::ffi::OsStr;
@ -257,6 +258,7 @@ fn capture(reftest: &Reftest, side: usize) -> (u32, u32, Vec<u8>) {
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(&reftest.servo_args[..])
.arg("--user-stylesheet").arg(util::resource_files::resources_dir_path().join("ahem.css"))
// Allows pixel perfect rendering of Ahem font and the HTML canvas for reftests.
.arg("-Z")
.arg("disable-text-aa,disable-canvas-aa")