Auto merge of #9293 - Ms2ger:reftests, r=SimonSapin
Remove the legacy reftest framework. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9293) <!-- Reviewable:end -->
|
@ -201,52 +201,11 @@ class MachCommands(CommandBase):
|
||||||
@Command('test-ref',
|
@Command('test-ref',
|
||||||
description='Run the reference tests',
|
description='Run the reference tests',
|
||||||
category='testing')
|
category='testing')
|
||||||
@CommandArgument('--kind', '-k', default=DEFAULT_RENDER_MODE,
|
@CommandArgument('params', default=None, nargs=argparse.REMAINDER)
|
||||||
help=HELP_RENDER_MODE)
|
def test_ref(self, params=None):
|
||||||
@CommandArgument('--release', '-r', action='store_true',
|
print("Ref tests have been replaced by web-platform-tests under "
|
||||||
help='Run with a release build of Servo')
|
"tests/wpt/mozilla/.")
|
||||||
@CommandArgument('--include', default=None, nargs='+',
|
return 0
|
||||||
help="Only run tests that match this pattern. If the "
|
|
||||||
"path to the ref test directory is included, it "
|
|
||||||
"will automatically be trimmed out.")
|
|
||||||
@CommandArgument(
|
|
||||||
'servo_params', default=None, nargs=argparse.REMAINDER,
|
|
||||||
help="Command-line arguments to be passed through to Servo")
|
|
||||||
def test_ref(self, kind=DEFAULT_RENDER_MODE, include=None, servo_params=None,
|
|
||||||
release=False):
|
|
||||||
self.ensure_bootstrapped()
|
|
||||||
self.ensure_built_tests(release=release)
|
|
||||||
assert kind is not None, 'kind cannot be None, see help'
|
|
||||||
|
|
||||||
kinds = ["cpu", "gpu"] if kind == 'both' else [kind]
|
|
||||||
test_path = path.join(self.context.topdir, "tests", "ref")
|
|
||||||
error = False
|
|
||||||
|
|
||||||
test_start = time()
|
|
||||||
for k in kinds:
|
|
||||||
print("Running %s reftests..." % k)
|
|
||||||
test_args = [k, test_path]
|
|
||||||
if include is not None:
|
|
||||||
ref_path = path.join("tests", "ref")
|
|
||||||
for name in include:
|
|
||||||
# Check to see if we were passed something leading with the
|
|
||||||
# path to the ref test directory, and trim it so that reftest
|
|
||||||
# knows how to filter it.
|
|
||||||
maybe_path = path.normpath(name)
|
|
||||||
if ref_path in maybe_path:
|
|
||||||
test_args.append(path.relpath(maybe_path, ref_path))
|
|
||||||
else:
|
|
||||||
test_args.append(name)
|
|
||||||
if servo_params is not None:
|
|
||||||
test_args += ["--"] + servo_params
|
|
||||||
ret = self.run_test("reftest", test_args, release=release)
|
|
||||||
error = error or ret != 0
|
|
||||||
elapsed = time() - test_start
|
|
||||||
|
|
||||||
print("Reference tests completed in %0.2fs" % elapsed)
|
|
||||||
|
|
||||||
if error:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
@Command('test-content',
|
@Command('test-content',
|
||||||
description='Run the content tests',
|
description='Run the content tests',
|
||||||
|
|
|
@ -19,8 +19,6 @@ import sys
|
||||||
from licenseck import licenses
|
from licenseck import licenses
|
||||||
|
|
||||||
filetypes_to_check = [".rs", ".rc", ".cpp", ".c", ".h", ".lock", ".py", ".toml", ".webidl"]
|
filetypes_to_check = [".rs", ".rc", ".cpp", ".c", ".h", ".lock", ".py", ".toml", ".webidl"]
|
||||||
reftest_dir = "./tests/ref"
|
|
||||||
reftest_filetype = ".list"
|
|
||||||
|
|
||||||
ignored_files = [
|
ignored_files = [
|
||||||
# Upstream
|
# Upstream
|
||||||
|
@ -62,10 +60,6 @@ def should_check(file_name):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def should_check_reftest(file_name):
|
|
||||||
return file_name.endswith(reftest_filetype)
|
|
||||||
|
|
||||||
|
|
||||||
EMACS_HEADER = "/* -*- Mode:"
|
EMACS_HEADER = "/* -*- Mode:"
|
||||||
VIM_HEADER = "/* vim:"
|
VIM_HEADER = "/* vim:"
|
||||||
MAX_LICENSE_LINESPAN = max(len(license.splitlines()) for license in licenses)
|
MAX_LICENSE_LINESPAN = max(len(license.splitlines()) for license in licenses)
|
||||||
|
@ -517,44 +511,6 @@ def collect_errors_for_files(files_to_check, checking_functions, line_checking_f
|
||||||
yield (filename,) + error
|
yield (filename,) + error
|
||||||
|
|
||||||
|
|
||||||
def check_reftest_order(files_to_check):
|
|
||||||
for file_name in files_to_check:
|
|
||||||
with open(file_name, "r") as fp:
|
|
||||||
split_lines = fp.read().splitlines()
|
|
||||||
lines = filter(lambda l: len(l) > 0 and l[0] != '#', split_lines)
|
|
||||||
for idx, line in enumerate(lines[:-1]):
|
|
||||||
next_line = lines[idx + 1]
|
|
||||||
current = get_reftest_names(line)
|
|
||||||
next = get_reftest_names(next_line)
|
|
||||||
if current is not None and next is not None and current > next:
|
|
||||||
yield (file_name, split_lines.index(next_line) + 1, "line not in alphabetical order")
|
|
||||||
|
|
||||||
|
|
||||||
def get_reftest_names(line):
|
|
||||||
tokens = line.split()
|
|
||||||
if len(tokens) == 3:
|
|
||||||
return tokens[1] + tokens[2]
|
|
||||||
if len(tokens) == 4:
|
|
||||||
return tokens[2] + tokens[3]
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_html_file_names_from_reftest_list(reftest_dir, file_name):
|
|
||||||
for line in open(os.path.join(reftest_dir, file_name), "r"):
|
|
||||||
for token in line.split():
|
|
||||||
if fnmatch.fnmatch(token, '*.html'):
|
|
||||||
yield os.path.join(reftest_dir, token)
|
|
||||||
|
|
||||||
|
|
||||||
def check_reftest_html_files_in_basic_list(reftest_dir):
|
|
||||||
basic_list_files = set(get_html_file_names_from_reftest_list(reftest_dir, "basic" + reftest_filetype))
|
|
||||||
|
|
||||||
for file_name in os.listdir(reftest_dir):
|
|
||||||
file_path = os.path.join(reftest_dir, file_name)
|
|
||||||
if fnmatch.fnmatch(file_path, '*.html') and file_path not in basic_list_files:
|
|
||||||
yield (file_path, "", "not found in basic.list")
|
|
||||||
|
|
||||||
|
|
||||||
def check_wpt_lint_errors():
|
def check_wpt_lint_errors():
|
||||||
wpt_working_dir = os.path.abspath(os.path.join(".", "tests", "wpt", "web-platform-tests"))
|
wpt_working_dir = os.path.abspath(os.path.join(".", "tests", "wpt", "web-platform-tests"))
|
||||||
site.addsitedir(wpt_working_dir)
|
site.addsitedir(wpt_working_dir)
|
||||||
|
@ -586,11 +542,6 @@ def scan(faster=False):
|
||||||
line_checking_functions = (check_license, check_by_line, check_toml, check_rust, check_spec)
|
line_checking_functions = (check_license, check_by_line, check_toml, check_rust, check_spec)
|
||||||
errors = collect_errors_for_files(files_to_check, checking_functions, line_checking_functions)
|
errors = collect_errors_for_files(files_to_check, checking_functions, line_checking_functions)
|
||||||
|
|
||||||
# reftest checks
|
|
||||||
reftest_to_check = filter(should_check_reftest, get_file_list(reftest_dir, faster))
|
|
||||||
r_errors = check_reftest_order(reftest_to_check)
|
|
||||||
not_found_in_basic_list_errors = check_reftest_html_files_in_basic_list(reftest_dir)
|
|
||||||
|
|
||||||
# wpt lint checks
|
# wpt lint checks
|
||||||
if faster:
|
if faster:
|
||||||
print "\033[93mUsing test-tidy \033[01m--faster\033[22m, skipping WPT lint\033[0m"
|
print "\033[93mUsing test-tidy \033[01m--faster\033[22m, skipping WPT lint\033[0m"
|
||||||
|
@ -599,7 +550,7 @@ def scan(faster=False):
|
||||||
wpt_lint_errors = check_wpt_lint_errors()
|
wpt_lint_errors = check_wpt_lint_errors()
|
||||||
|
|
||||||
# collect errors
|
# collect errors
|
||||||
errors = itertools.chain(errors, r_errors, not_found_in_basic_list_errors, wpt_lint_errors)
|
errors = itertools.chain(errors, wpt_lint_errors)
|
||||||
|
|
||||||
error = None
|
error = None
|
||||||
for error in errors:
|
for error in errors:
|
||||||
|
|
Before Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 171 B |
|
@ -1,8 +0,0 @@
|
||||||
# This file must be sorted alphabetically.
|
|
||||||
# Please run `./mach test-tidy` to check your changes.
|
|
||||||
|
|
||||||
# Should be == with expected failure:
|
|
||||||
fragment=top != ../html/acid2.html acid2_ref.html
|
|
||||||
|
|
||||||
# This file must be sorted alphabetically.
|
|
||||||
# Please run `./mach test-tidy` to check your changes.
|
|
|
@ -1,5 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: 'ahem';
|
|
||||||
font-size: 100px;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
body {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
Before Width: | Height: | Size: 510 B |
|
@ -1,48 +0,0 @@
|
||||||
/* http://meyerweb.com/eric/tools/css/reset/
|
|
||||||
v2.0 | 20110126
|
|
||||||
License: none (public domain)
|
|
||||||
*/
|
|
||||||
|
|
||||||
html, body, div, span, applet, object, iframe,
|
|
||||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
|
||||||
a, abbr, acronym, address, big, cite, code,
|
|
||||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
|
||||||
small, strike, strong, sub, sup, tt, var,
|
|
||||||
b, u, i, center,
|
|
||||||
dl, dt, dd, ol, ul, li,
|
|
||||||
fieldset, form, label, legend,
|
|
||||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
|
||||||
article, aside, canvas, details, embed,
|
|
||||||
figure, figcaption, footer, header, hgroup,
|
|
||||||
menu, nav, output, ruby, section, summary,
|
|
||||||
time, mark, audio, video {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
font-size: 100%;
|
|
||||||
font: inherit;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
/* HTML5 display-role reset for older browsers */
|
|
||||||
article, aside, details, figcaption, figure,
|
|
||||||
footer, header, hgroup, menu, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
ol, ul {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
blockquote, q {
|
|
||||||
quotes: none;
|
|
||||||
}
|
|
||||||
blockquote:before, blockquote:after,
|
|
||||||
q:before, q:after {
|
|
||||||
content: '';
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 253 B |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 86 KiB |
395
tests/reftest.rs
vendored
|
@ -1,395 +0,0 @@
|
||||||
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#![feature(fs_walk)]
|
|
||||||
#![feature(slice_patterns)]
|
|
||||||
#![feature(test)]
|
|
||||||
|
|
||||||
#[macro_use] extern crate bitflags;
|
|
||||||
extern crate image;
|
|
||||||
extern crate test;
|
|
||||||
extern crate url;
|
|
||||||
extern crate util;
|
|
||||||
|
|
||||||
use image::{DynamicImage, GenericImage, ImageFormat, RgbImage};
|
|
||||||
use std::env;
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::fs::{File, walk_dir};
|
|
||||||
use std::io::{self, Read, Result, Write};
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::process;
|
|
||||||
use std::process::{Command};
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
use test::run_tests_console;
|
|
||||||
use test::{AutoColor, DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn, ShouldPanic};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
bitflags!(
|
|
||||||
flags RenderMode: u32 {
|
|
||||||
const CPU_RENDERING = 0x00000001,
|
|
||||||
const GPU_RENDERING = 0x00000010,
|
|
||||||
const LINUX_TARGET = 0x00000100,
|
|
||||||
const MACOS_TARGET = 0x00001000,
|
|
||||||
const ANDROID_TARGET = 0x00010000
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
let mut parts = args[1..].split(|e| &**e == "--");
|
|
||||||
|
|
||||||
let harness_args = parts.next().unwrap(); // .split() is never empty
|
|
||||||
let servo_args = parts.next().unwrap_or(&[]);
|
|
||||||
|
|
||||||
let (render_mode_string, base_path, testnames) = match harness_args {
|
|
||||||
[ref render_mode_string, ref base_path, testnames..] =>
|
|
||||||
(render_mode_string, base_path, testnames),
|
|
||||||
_ => panic!("USAGE: cpu|gpu base_path [testname ...]"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut render_mode = match &**render_mode_string {
|
|
||||||
"cpu" => CPU_RENDERING,
|
|
||||||
"gpu" => GPU_RENDERING,
|
|
||||||
_ => panic!("First argument must specify cpu or gpu as rendering mode")
|
|
||||||
};
|
|
||||||
if cfg!(target_os = "linux") {
|
|
||||||
render_mode.insert(LINUX_TARGET);
|
|
||||||
}
|
|
||||||
if cfg!(target_os = "macos") {
|
|
||||||
render_mode.insert(MACOS_TARGET);
|
|
||||||
}
|
|
||||||
if cfg!(target_os = "android") {
|
|
||||||
render_mode.insert(ANDROID_TARGET);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut all_tests = vec!();
|
|
||||||
println!("Scanning {} for manifests\n", base_path);
|
|
||||||
|
|
||||||
for file in walk_dir(base_path).unwrap() {
|
|
||||||
let file = file.unwrap().path();
|
|
||||||
let maybe_extension = file.extension();
|
|
||||||
match maybe_extension {
|
|
||||||
Some(extension) => {
|
|
||||||
if extension == OsStr::new("list") && file.is_file() {
|
|
||||||
let len = all_tests.len();
|
|
||||||
let mut tests = parse_lists(&file, testnames, servo_args, render_mode, len);
|
|
||||||
println!("\t{} [{} tests]", file.display(), tests.len());
|
|
||||||
all_tests.append(&mut tests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let test_opts = TestOpts {
|
|
||||||
filter: None,
|
|
||||||
run_ignored: false,
|
|
||||||
logfile: None,
|
|
||||||
run_tests: true,
|
|
||||||
bench_benchmarks: false,
|
|
||||||
nocapture: false,
|
|
||||||
color: AutoColor,
|
|
||||||
};
|
|
||||||
|
|
||||||
match run(test_opts,
|
|
||||||
all_tests,
|
|
||||||
servo_args.iter().cloned().collect()) {
|
|
||||||
Ok(false) => process::exit(1), // tests failed
|
|
||||||
Err(_) => process::exit(2), // I/O-related failure
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(test_opts: TestOpts, all_tests: Vec<TestDescAndFn>,
|
|
||||||
servo_args: Vec<String>) -> io::Result<bool> {
|
|
||||||
// Verify that we're passing in valid servo arguments. Otherwise, servo
|
|
||||||
// will exit before we've run any tests, and it will appear to us as if
|
|
||||||
// all the tests are failing.
|
|
||||||
let mut command = Command::new(&servo_path());
|
|
||||||
command
|
|
||||||
.args(&servo_args)
|
|
||||||
.arg("-z")
|
|
||||||
.arg("about:blank");
|
|
||||||
|
|
||||||
let mut child = match command.spawn() {
|
|
||||||
Ok(p) => p,
|
|
||||||
Err(e) => panic!("failed to execute process: {}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Wait for the shell to launch or to fail
|
|
||||||
thread::sleep(Duration::from_secs(1));
|
|
||||||
child.kill().unwrap();
|
|
||||||
let output = try!(child.wait_with_output());
|
|
||||||
|
|
||||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
|
||||||
|
|
||||||
if stderr.contains("Unrecognized") {
|
|
||||||
println!("Servo: {}", stderr);
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
run_tests_console(&test_opts, all_tests)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
|
||||||
enum ReftestKind {
|
|
||||||
Same,
|
|
||||||
Different,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Reftest {
|
|
||||||
name: String,
|
|
||||||
kind: ReftestKind,
|
|
||||||
files: [PathBuf; 2],
|
|
||||||
id: usize,
|
|
||||||
servo_args: Vec<String>,
|
|
||||||
render_mode: RenderMode,
|
|
||||||
is_flaky: bool,
|
|
||||||
prefs: Vec<String>,
|
|
||||||
fragment_identifier: Option<String>,
|
|
||||||
resolution: Option<String>,
|
|
||||||
pixel_ratio: Option<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestLine<'a> {
|
|
||||||
conditions: &'a str,
|
|
||||||
kind: &'a str,
|
|
||||||
file_left: &'a str,
|
|
||||||
file_right: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_lists(file: &Path,
|
|
||||||
filters: &[String],
|
|
||||||
servo_args: &[String],
|
|
||||||
render_mode: RenderMode,
|
|
||||||
id_offset: usize)
|
|
||||||
-> Vec<TestDescAndFn> {
|
|
||||||
let mut tests = Vec::new();
|
|
||||||
let contents = {
|
|
||||||
let mut f = File::open(file).unwrap();
|
|
||||||
let mut contents = String::new();
|
|
||||||
f.read_to_string(&mut contents).unwrap();
|
|
||||||
contents
|
|
||||||
};
|
|
||||||
|
|
||||||
for line in contents.lines() {
|
|
||||||
// ignore comments or empty lines
|
|
||||||
if line.starts_with("#") || line.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let parts: Vec<&str> = line.split(' ').filter(|p| !p.is_empty()).collect();
|
|
||||||
|
|
||||||
let test_line = match parts.len() {
|
|
||||||
3 => TestLine {
|
|
||||||
conditions: "",
|
|
||||||
kind: parts[0],
|
|
||||||
file_left: parts[1],
|
|
||||||
file_right: parts[2],
|
|
||||||
},
|
|
||||||
4 => TestLine {
|
|
||||||
conditions: parts[0],
|
|
||||||
kind: parts[1],
|
|
||||||
file_left: parts[2],
|
|
||||||
file_right: parts[3],
|
|
||||||
},
|
|
||||||
_ => panic!("reftest line: '{}' doesn't match '[CONDITIONS] KIND LEFT RIGHT'", line),
|
|
||||||
};
|
|
||||||
|
|
||||||
let kind = match test_line.kind {
|
|
||||||
"==" => ReftestKind::Same,
|
|
||||||
"!=" => ReftestKind::Different,
|
|
||||||
part => panic!("reftest line: '{}' has invalid kind '{}'", line, part)
|
|
||||||
};
|
|
||||||
|
|
||||||
let base = env::current_dir().unwrap().join(file.parent().unwrap());
|
|
||||||
|
|
||||||
let file_left = base.join(test_line.file_left);
|
|
||||||
let file_right = base.join(test_line.file_right);
|
|
||||||
|
|
||||||
let conditions_list = test_line.conditions.split(',');
|
|
||||||
let mut flakiness = RenderMode::empty();
|
|
||||||
let mut prefs = vec![];
|
|
||||||
let mut fragment_identifier = None;
|
|
||||||
let mut resolution = None;
|
|
||||||
let mut pixel_ratio = None;
|
|
||||||
for condition in conditions_list {
|
|
||||||
match condition {
|
|
||||||
"flaky_cpu" => flakiness.insert(CPU_RENDERING),
|
|
||||||
"flaky_gpu" => flakiness.insert(GPU_RENDERING),
|
|
||||||
"flaky_linux" => flakiness.insert(LINUX_TARGET),
|
|
||||||
"flaky_macos" => flakiness.insert(MACOS_TARGET),
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
if condition.starts_with("prefs:\"") {
|
|
||||||
if let Some(joined) = condition.split("\"").nth(1) {
|
|
||||||
prefs.extend(joined.split(",").map(str::to_owned));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if condition.starts_with("fragment=") {
|
|
||||||
fragment_identifier = Some(condition["fragment=".len()..].to_string());
|
|
||||||
}
|
|
||||||
if condition.starts_with("resolution=") {
|
|
||||||
resolution = Some(condition["resolution=".len() ..].to_string());
|
|
||||||
}
|
|
||||||
if condition.starts_with("device-pixel-ratio=") {
|
|
||||||
pixel_ratio = Some(condition["device-pixel-ratio=".len() ..].to_string()
|
|
||||||
.parse().expect("Invalid device-pixel-ratio"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let reftest = Reftest {
|
|
||||||
name: format!("{} {} {}", test_line.file_left, test_line.kind, test_line.file_right),
|
|
||||||
kind: kind,
|
|
||||||
files: [file_left, file_right],
|
|
||||||
id: id_offset + tests.len(),
|
|
||||||
render_mode: render_mode,
|
|
||||||
servo_args: servo_args.to_vec(),
|
|
||||||
is_flaky: render_mode.intersects(flakiness),
|
|
||||||
prefs: prefs,
|
|
||||||
fragment_identifier: fragment_identifier,
|
|
||||||
resolution: resolution,
|
|
||||||
pixel_ratio: pixel_ratio,
|
|
||||||
};
|
|
||||||
|
|
||||||
if filters.is_empty() || filters.iter().any(|pattern| reftest.name.contains(pattern)) {
|
|
||||||
tests.push(make_test(reftest));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tests
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_test(reftest: Reftest) -> TestDescAndFn {
|
|
||||||
let name = reftest.name.clone();
|
|
||||||
TestDescAndFn {
|
|
||||||
desc: TestDesc {
|
|
||||||
name: DynTestName(name),
|
|
||||||
ignore: false,
|
|
||||||
should_panic: ShouldPanic::No,
|
|
||||||
},
|
|
||||||
testfn: DynTestFn(Box::new(move || {
|
|
||||||
check_reftest(reftest);
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn capture(reftest: &Reftest, side: usize) -> (u32, u32, Vec<u8>) {
|
|
||||||
let png_filename = format!("/tmp/servo-reftest-{:06}-{}.png", reftest.id, side);
|
|
||||||
let mut command = Command::new(&servo_path());
|
|
||||||
command
|
|
||||||
.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")
|
|
||||||
.args(&["-f", "-o"])
|
|
||||||
.arg(&png_filename)
|
|
||||||
.arg(&{
|
|
||||||
let mut url = Url::from_file_path(&*reftest.files[side]).unwrap();
|
|
||||||
url.fragment = reftest.fragment_identifier.clone();
|
|
||||||
url.to_string()
|
|
||||||
});
|
|
||||||
// CPU rendering is the default
|
|
||||||
if reftest.render_mode.contains(CPU_RENDERING) {
|
|
||||||
command.arg("-c");
|
|
||||||
}
|
|
||||||
if reftest.render_mode.contains(GPU_RENDERING) {
|
|
||||||
command.arg("-g");
|
|
||||||
}
|
|
||||||
for pref in &reftest.prefs {
|
|
||||||
command.arg("--pref");
|
|
||||||
command.arg(pref);
|
|
||||||
}
|
|
||||||
if let Some(ref resolution) = reftest.resolution {
|
|
||||||
command.arg("--resolution");
|
|
||||||
command.arg(resolution);
|
|
||||||
}
|
|
||||||
if let Some(pixel_ratio) = reftest.pixel_ratio {
|
|
||||||
command.arg("--device-pixel-ratio");
|
|
||||||
command.arg(pixel_ratio.to_string());
|
|
||||||
}
|
|
||||||
let (exit_status, stderr, stdout) = match command.output() {
|
|
||||||
Ok(output) => (output.status, output.stderr, output.stdout),
|
|
||||||
Err(e) => panic!("failed to execute process: {}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
if !stdout.is_empty() {
|
|
||||||
let stdout_filename = format!("/tmp/servo-reftest-{:06}-{}-stdout.txt", reftest.id, side);
|
|
||||||
let mut stdout_file = File::create(stdout_filename).unwrap();
|
|
||||||
stdout_file.write_all(&stdout[..]).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stderr.is_empty() {
|
|
||||||
let stderr_filename = format!("/tmp/servo-reftest-{:06}-{}-stderr.txt", reftest.id, side);
|
|
||||||
let mut stderr_file = File::create(stderr_filename).unwrap();
|
|
||||||
stderr_file.write_all(&stderr[..]).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert!(exit_status.success());
|
|
||||||
|
|
||||||
let image = match image::open(&png_filename) {
|
|
||||||
Ok(DynamicImage::ImageRgb8(image)) => image,
|
|
||||||
Ok(image) => image.to_rgb(),
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
|
||||||
(image.width(), image.height(), image.into_raw())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn servo_path() -> PathBuf {
|
|
||||||
let current_exe = env::current_exe().ok().expect("Could not locate current executable");
|
|
||||||
current_exe.parent().unwrap().join("servo")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_reftest(reftest: Reftest) {
|
|
||||||
let (left_width, left_height, left_bytes) = capture(&reftest, 0);
|
|
||||||
let (right_width, right_height, right_bytes) = capture(&reftest, 1);
|
|
||||||
|
|
||||||
// TODO(gw): This is a workaround for https://github.com/servo/servo/issues/7730
|
|
||||||
if !reftest.is_flaky {
|
|
||||||
assert_eq!(left_width, right_width);
|
|
||||||
assert_eq!(left_height, right_height);
|
|
||||||
|
|
||||||
let left_all_white = left_bytes.iter().all(|&p| p == 255);
|
|
||||||
let right_all_white = right_bytes.iter().all(|&p| p == 255);
|
|
||||||
|
|
||||||
if left_all_white && right_all_white {
|
|
||||||
panic!("Both renderings are empty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let pixels = left_bytes.iter().zip(right_bytes.iter()).map(|(&a, &b)| {
|
|
||||||
if a == b {
|
|
||||||
// White for correct
|
|
||||||
0xFF
|
|
||||||
} else {
|
|
||||||
// "1100" in the RGBA channel with an error for an incorrect value
|
|
||||||
// This results in some number of C0 and FFs, which is much more
|
|
||||||
// readable (and distinguishable) than the previous difference-wise
|
|
||||||
// scaling but does not require reconstructing the actual RGBA pixel.
|
|
||||||
0xC0
|
|
||||||
}
|
|
||||||
}).collect::<Vec<u8>>();
|
|
||||||
|
|
||||||
if pixels.iter().any(|&a| a < 255) {
|
|
||||||
let output = format!("/tmp/servo-reftest-{:06}-diff.png", reftest.id);
|
|
||||||
let mut file = File::create(&output).unwrap();
|
|
||||||
let img_buf = RgbImage::from_raw(left_width, left_height, pixels).expect("foo");
|
|
||||||
DynamicImage::ImageRgb8(img_buf).save(&mut file, ImageFormat::PNG).unwrap();
|
|
||||||
|
|
||||||
match (reftest.kind, reftest.is_flaky) {
|
|
||||||
(ReftestKind::Same, true) => println!("flaky test - rendering difference: {}", output),
|
|
||||||
(ReftestKind::Same, false) => panic!("rendering difference: {}", output),
|
|
||||||
(ReftestKind::Different, _) => {} // Result was different and that's what was expected
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
assert!(reftest.is_flaky || reftest.kind == ReftestKind::Same);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -151,6 +151,19 @@
|
||||||
"url": "/_mozilla/css/acid1_a.html"
|
"url": "/_mozilla/css/acid1_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/acid2-wrapper.html": [
|
||||||
|
{
|
||||||
|
"path": "css/acid2-wrapper.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/acid2_ref_broken.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"timeout": "long",
|
||||||
|
"url": "/_mozilla/css/acid2-wrapper.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/acid2_noscroll.html": [
|
"css/acid2_noscroll.html": [
|
||||||
{
|
{
|
||||||
"path": "css/acid2_noscroll.html",
|
"path": "css/acid2_noscroll.html",
|
||||||
|
@ -163,6 +176,18 @@
|
||||||
"url": "/_mozilla/css/acid2_noscroll.html"
|
"url": "/_mozilla/css/acid2_noscroll.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/acid2_ref.html": [
|
||||||
|
{
|
||||||
|
"path": "css/acid2_ref.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/acid2_ref_broken.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/acid2_ref.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/after_block_iteration.html": [
|
"css/after_block_iteration.html": [
|
||||||
{
|
{
|
||||||
"path": "css/after_block_iteration.html",
|
"path": "css/after_block_iteration.html",
|
||||||
|
@ -6194,6 +6219,19 @@
|
||||||
"url": "/_mozilla/css/acid1_a.html"
|
"url": "/_mozilla/css/acid1_a.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/acid2-wrapper.html": [
|
||||||
|
{
|
||||||
|
"path": "css/acid2-wrapper.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/acid2_ref_broken.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"timeout": "long",
|
||||||
|
"url": "/_mozilla/css/acid2-wrapper.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/acid2_noscroll.html": [
|
"css/acid2_noscroll.html": [
|
||||||
{
|
{
|
||||||
"path": "css/acid2_noscroll.html",
|
"path": "css/acid2_noscroll.html",
|
||||||
|
@ -6206,6 +6244,18 @@
|
||||||
"url": "/_mozilla/css/acid2_noscroll.html"
|
"url": "/_mozilla/css/acid2_noscroll.html"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"css/acid2_ref.html": [
|
||||||
|
{
|
||||||
|
"path": "css/acid2_ref.html",
|
||||||
|
"references": [
|
||||||
|
[
|
||||||
|
"/_mozilla/css/acid2_ref_broken.html",
|
||||||
|
"=="
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"url": "/_mozilla/css/acid2_ref.html"
|
||||||
|
}
|
||||||
|
],
|
||||||
"css/after_block_iteration.html": [
|
"css/after_block_iteration.html": [
|
||||||
{
|
{
|
||||||
"path": "css/after_block_iteration.html",
|
"path": "css/after_block_iteration.html",
|
||||||
|
|
3
tests/wpt/mozilla/meta/css/acid2-wrapper.html.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[acid2-wrapper.html]
|
||||||
|
type: reftest
|
||||||
|
disabled: https://github.com/servo/servo/issues/9310
|
3
tests/wpt/mozilla/meta/css/acid2_ref.html.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[acid2_ref.html]
|
||||||
|
type: reftest
|
||||||
|
expected: FAIL
|
15
tests/wpt/mozilla/tests/css/acid2-wrapper.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html class=reftest-wait>
|
||||||
|
<meta name=timeout content=long>
|
||||||
|
<link rel=match href=acid2_ref_broken.html>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
iframe {
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<iframe src="acid2.html#top" onload="document.documentElement.className = ''"></iframe>
|
150
tests/wpt/mozilla/tests/css/acid2.html
Executable file
|
@ -0,0 +1,150 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>The Second Acid Test</title>
|
||||||
|
<style type="text/css">
|
||||||
|
/* section numbers refer to CSS2.1 */
|
||||||
|
|
||||||
|
/* page setup */
|
||||||
|
html { font: 12px sans-serif; margin: 0; padding: 0; overflow: hidden; /* hides scrollbars on viewport, see 11.1.1:3 */ background: white; color: red; }
|
||||||
|
body { margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
/* introduction message */
|
||||||
|
.intro { font: 2em sans-serif; margin: 3.5em 2em; padding: 0.5em; border: solid thin; background: white; color: black; position: relative; z-index: 2; /* should cover the black and red bars that are fixed-positioned */ }
|
||||||
|
.intro * { font: inherit; margin: 0; padding: 0; }
|
||||||
|
.intro h1 { font-size: 1em; font-weight: bolder; margin: 0; padding: 0; }
|
||||||
|
.intro :link { color: blue; }
|
||||||
|
.intro :visited { color: purple; }
|
||||||
|
|
||||||
|
/* picture setup */
|
||||||
|
#top { margin: 100em 3em 0; padding: 2em 0 0 .5em; text-align: left; font: 2em/24px sans-serif; color: navy; white-space: pre; } /* "Hello World!" text */
|
||||||
|
.picture { position: relative; border: 1em solid transparent; margin: 0 0 100em 3em; } /* containing block for face */
|
||||||
|
.picture { background: red; } /* overridden by preferred stylesheet below */
|
||||||
|
|
||||||
|
/* top line of face (scalp): fixed positioning and min/max height/width */
|
||||||
|
.picture p { position: fixed; margin: 0; padding: 0; border: 0; top: 9em; left: 11em; width: 140%; max-width: 4em; height: 8px; min-height: 1em; max-height: 2mm; /* min-height overrides max-height, see 10.7 */ background: black; border-bottom: 0.5em yellow solid; }
|
||||||
|
|
||||||
|
/* bits that shouldn't be part of the top line (and shouldn't be visible at all): HTML parsing, "+" combinator, stacking order */
|
||||||
|
.picture p.bad { border-bottom: red solid; /* shouldn't matter, because the "p + table + p" rule below should match it too, thus hiding it */ }
|
||||||
|
.picture p + p { background: maroon; z-index: 1; } /* shouldn't match anything */
|
||||||
|
.picture p + table + p { margin-top: 3em; /* should end up under the absolutely positioned table below, and thus not be visible */ }
|
||||||
|
|
||||||
|
/* second line of face: attribute selectors, float positioning */
|
||||||
|
[class~=one].first.one { position: absolute; top: 0; margin: 36px 0 0 60px; padding: 0; border: black 2em; border-style: none solid; /* shrink wraps around float */ }
|
||||||
|
[class~=one][class~=first] [class=second\ two][class="second two"] { float: right; width: 48px; height: 12px; background: yellow; margin: 0; padding: 0; } /* only content of abs pos block */
|
||||||
|
|
||||||
|
/* third line of face: width and overflow */
|
||||||
|
.forehead { margin: 4em; width: 8em; border-left: solid black 1em; border-right: solid black 1em; background: red url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR42mP4%2F58BAAT%2FAf9jgNErAAAAAElFTkSuQmCC); /* that's a 1x1 yellow pixel PNG */ }
|
||||||
|
.forehead * { width: 12em; line-height: 1em; }
|
||||||
|
|
||||||
|
/* class selectors headache */
|
||||||
|
.two.error.two { background: maroon; } /* shouldn't match */
|
||||||
|
.forehead.error.forehead { background: red; } /* shouldn't match */
|
||||||
|
[class=second two] { background: red; } /* this should be ignored (invalid selector -- grammar says it only accepts IDENTs or STRINGs) */
|
||||||
|
|
||||||
|
/* fourth and fifth lines of face, with eyes: paint order test (see appendix E) and fixed backgrounds */
|
||||||
|
/* the two images are identical: 2-by-2 squares with the top left
|
||||||
|
and bottom right pixels set to yellow and the other two set to
|
||||||
|
transparent. Since they are offset by one pixel from each other,
|
||||||
|
the second one paints exactly over the transparent parts of the
|
||||||
|
first one, thus creating a solid yellow block. */
|
||||||
|
.eyes { position: absolute; top: 5em; left: 3em; margin: 0; padding: 0; background: red; }
|
||||||
|
#eyes-a { height: 0; line-height: 2em; text-align: right; } /* contents should paint top-most because they're inline */
|
||||||
|
#eyes-a object { display: inline; vertical-align: bottom; }
|
||||||
|
#eyes-a object[type] { width: 7.5em; height: 2.5em; } /* should have no effect since that object should fallback to being inline (height/width don't apply to inlines) */
|
||||||
|
#eyes-a object object object { border-right: solid 1em black; padding: 0 12px 0 11px; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABnRSTlMAAAAAAABupgeRAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAAEUlEQVR42mP4%2F58BCv7%2FZwAAHfAD%2FabwPj4AAAAASUVORK5CYII%3D) fixed 1px 0; }
|
||||||
|
#eyes-b { float: left; width: 10em; height: 2em; background: fixed url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAABnRSTlMAAAAAAABupgeRAAAABmJLR0QA%2FwD%2FAP%2BgvaeTAAAAEUlEQVR42mP4%2F58BCv7%2FZwAAHfAD%2FabwPj4AAAAASUVORK5CYII%3D); border-left: solid 1em black; border-right: solid 1em red; } /* should paint in the middle layer because it is a float */
|
||||||
|
#eyes-c { display: block; background: red; border-left: 2em solid yellow; width: 10em; height: 2em; } /* should paint bottom most because it is a block */
|
||||||
|
|
||||||
|
/* lines six to nine, with nose: auto margins */
|
||||||
|
.nose { float: left; margin: -2em 2em -1em; border: solid 1em black; border-top: 0; min-height: 80%; height: 60%; max-height: 3em; /* percentages become auto (see 10.5 and 10.7) and intrinsic height is more than 3em, so 3em wins */ padding: 0; width: 12em; }
|
||||||
|
.nose > div { padding: 1em 1em 3em; height: 0; background: yellow; }
|
||||||
|
.nose div div { width: 2em; height: 2em; background: red; margin: auto; }
|
||||||
|
.nose :hover div { border-color: blue; }
|
||||||
|
.nose div:hover :before { border-bottom-color: inherit; }
|
||||||
|
.nose div:hover :after { border-top-color: inherit; }
|
||||||
|
.nose div div:before { display: block; border-style: none solid solid; border-color: red yellow black yellow; border-width: 1em; content: ''; height: 0; }
|
||||||
|
.nose div :after { display: block; border-style: solid solid none; border-color: black yellow red yellow; border-width: 1em; content: ''; height: 0; }
|
||||||
|
|
||||||
|
/* between lines nine and ten: margin collapsing with 'float' and 'clear' */
|
||||||
|
.empty { margin: 6.25em; height: 10%; /* computes to auto which makes it empty per 8.3.1:7 (own margins) */ }
|
||||||
|
.empty div { margin: 0 2em -6em 4em; }
|
||||||
|
.smile { margin: 5em 3em; clear: both; /* clearance is negative (see 8.3.1 and 9.5.1) */ }
|
||||||
|
|
||||||
|
/* line ten and eleven: containing block for abs pos */
|
||||||
|
.smile div { margin-top: 0.25em; background: black; width: 12em; height: 2em; position: relative; bottom: -1em; }
|
||||||
|
.smile div div { position: absolute; top: 0; right: 1em; width: auto; height: 0; margin: 0; border: yellow solid 1em; }
|
||||||
|
|
||||||
|
/* smile (over lines ten and eleven): backgrounds behind borders, inheritance of 'float', nested floats, negative heights */
|
||||||
|
.smile div div span { display: inline; margin: -1em 0 0 0; border: solid 1em transparent; border-style: none solid; float: right; background: black; height: 1em; }
|
||||||
|
.smile div div span em { float: inherit; border-top: solid yellow 1em; border-bottom: solid black 1em; } /* zero-height block; width comes from (zero-height) child. */
|
||||||
|
.smile div div span em strong { width: 6em; display: block; margin-bottom: -1em; /* should have no effect, since parent has top&bottom borders, so this margin doesn't collapse */ }
|
||||||
|
|
||||||
|
/* line twelve: line-height */
|
||||||
|
.chin { margin: -4em 4em 0; width: 8em; line-height: 1em; border-left: solid 1em black; border-right: solid 1em black; background: yellow url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAFSDNYfAAAAaklEQVR42u3XQQrAIAwAQeP%2F%2F6wf8CJBJTK9lnQ7FpHGaOurt1I34nfH9pMMZAZ8BwMGEvvh%2BBsJCAgICLwIOA8EBAQEBAQEBAQEBK79H5RfIQAAAAAAAAAAAAAAAAAAAAAAAAAAAID%2FABMSqAfj%2FsLmvAAAAABJRU5ErkJggg%3D%3D) /* 64x64 red square */ no-repeat fixed /* shouldn't be visible unless the smiley is moved to the top left of the viewport */; }
|
||||||
|
.chin div { display: inline; font: 2px/4px serif; }
|
||||||
|
|
||||||
|
/* line thirteen: cascade and selector tests */
|
||||||
|
.parser-container div { color: maroon; border: solid; color: orange; } /* setup */
|
||||||
|
div.parser-container * { border-color: black; /* overrides (implied) border-color on previous line */ } /* setup */
|
||||||
|
* div.parser { border-width: 0 2em; /* overrides (implied) declarations on earlier line */ } /* setup */
|
||||||
|
|
||||||
|
/* line thirteen continued: parser tests */
|
||||||
|
.parser { /* comment parsing test -- comment ends before the end of this line, the backslash should have no effect: \*/ }
|
||||||
|
.parser { margin: 0 5em 1em; padding: 0 1em; width: 2em; height: 1em; error: \}; background: yellow; } /* setup with parsing test */
|
||||||
|
* html .parser { background: gray; }
|
||||||
|
\.parser { padding: 2em; }
|
||||||
|
.parser { m\argin: 2em; };
|
||||||
|
.parser { height: 3em; }
|
||||||
|
.parser { width: 200; }
|
||||||
|
.parser { border: 5em solid red ! error; }
|
||||||
|
.parser { background: red pink; }
|
||||||
|
|
||||||
|
/* line fourteen (last line of face): table */
|
||||||
|
ul { display: table; padding: 0; margin: -1em 7em 0; background: red; }
|
||||||
|
ul li { padding: 0; margin: 0; }
|
||||||
|
ul li.first-part { display: table-cell; height: 1em; width: 1em; background: black; }
|
||||||
|
ul li.second-part { display: table; height: 1em; width: 1em; background: black; } /* anonymous table cell wraps around this */
|
||||||
|
ul li.third-part { display: table-cell; height: 0.5em; /* gets stretched to fit row */ width: 1em; background: black; }
|
||||||
|
ul li.fourth-part { list-style: none; height: 1em; width: 1em; background: black; } /* anonymous table cell wraps around this */
|
||||||
|
|
||||||
|
/* bits that shouldn't appear: inline alignment in cells */
|
||||||
|
.image-height-test { height: 10px; overflow: hidden; font: 20em serif; } /* only the area between the top of the line box and the top of the image should be visible */
|
||||||
|
table { margin: 0; border-spacing: 0; }
|
||||||
|
td { padding: 0; }
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<link rel="appendix stylesheet" href="data:text/css,.picture%20%7B%20background%3A%20none%3B%20%7D"> <!-- this stylesheet should be applied by default -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="intro">
|
||||||
|
<h1>Standards compliant?</h1>
|
||||||
|
<p><a href="#top">Take The Acid2 Test</a> and compare it to <a
|
||||||
|
href="reference.html">the reference rendering</a>.</p>
|
||||||
|
</div>
|
||||||
|
<h2 id="top">Hello World!</h2>
|
||||||
|
<div class="picture">
|
||||||
|
<p><table><tr><td></table><p class="bad"> <!-- <table> closes <p> per the HTML4 DTD -->
|
||||||
|
<blockquote class="first one"><address class="second two"></address></blockquote>
|
||||||
|
<div class="forehead"><div> </div></div>
|
||||||
|
<div class="eyes"><div id="eyes-a"><object data="data:application/x-unknown,ERROR"><object data="http://www.damowmow.com/404/" type="text/html"><object data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC">ERROR</object></object></object></div><div id="eyes-b"></div><div id="eyes-c"></div></div> <!-- that's a PNG with 8bit alpha containing two eyes -->
|
||||||
|
<div class="nose"><div><div></div></div></div>
|
||||||
|
<div class="empty"><div></div></div>
|
||||||
|
<div class="smile"><div><div><span><em><strong></strong></em></span></div></div></div>
|
||||||
|
<div class="chin"><div> </div></div>
|
||||||
|
<div class="parser-container"><div class="parser"><!-- ->ERROR<!- --></div></div> <!-- two dashes is what delimits a comment, so the text "->ERROR<!-" earlier on this line is actually part of a comment -->
|
||||||
|
<ul>
|
||||||
|
<li class="first-part"></li>
|
||||||
|
<li class="second-part"></li>
|
||||||
|
<li class="third-part"></li>
|
||||||
|
<li class="fourth-part"></li>
|
||||||
|
</ul>
|
||||||
|
<div class="image-height-test"><table><tr><td><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAFSDNYfAAAAaklEQVR42u3XQQrAIAwAQeP%2F%2F6wf8CJBJTK9lnQ7FpHGaOurt1I34nfH9pMMZAZ8BwMGEvvh%2BBsJCAgICLwIOA8EBAQEBAQEBAQEBK79H5RfIQAAAAAAAAAAAAAAAAAAAAAAAAAAAID%2FABMSqAfj%2FsLmvAAAAABJRU5ErkJggg%3D%3D" alt=""></td></tr></table></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// window.scroll(0, 2684);
|
||||||
|
// setInterval(() => { console.log(window.scrollY); window.scroll(0, 2684);
|
||||||
|
//}, 10);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -2,6 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>The Second Acid Test (Reference Rendering)</title>
|
<title>The Second Acid Test (Reference Rendering)</title>
|
||||||
|
<link rel=match href=acid2_ref_broken.html>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
html { margin: 0; padding: 0; border: 0; overflow: hidden; background: white; }
|
html { margin: 0; padding: 0; border: 0; overflow: hidden; background: white; }
|
||||||
body { margin: 0; padding: 0; border: 0; }
|
body { margin: 0; padding: 0; border: 0; }
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |