mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
auto merge of #3670 : kmcallister/servo/h5e-take2, r=jdm
r? @Ms2ger, @jdm The parser is now a JS-managed object and we use hooks in html5ever to trace its internal state. This should be memory-safe even if arbitrary JavaScript can run during a parse. Please let me know if you think of a reason it wouldn't be! I think the likely outcome of a garbage collection during parsing is a dynamic `RefCell` borrow failure, but I'm going to look into that after this lands. It should be safe to trace the parser while it's mutably borrowed, as long as it's not shared between threads, so we can probably switch to `UnsafeCell`.
This commit is contained in:
commit
8d3b107568
23 changed files with 957 additions and 317 deletions
62
Cargo.lock
generated
62
Cargo.lock
generated
|
@ -223,6 +223,23 @@ name = "harfbuzz"
|
|||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6"
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f"
|
||||
dependencies = [
|
||||
"html5ever_macros 0.0.0 (git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f)",
|
||||
"phf 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"phf_mac 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever_macros"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.1.0-pre"
|
||||
|
@ -232,22 +249,6 @@ dependencies = [
|
|||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hubbub"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b"
|
||||
dependencies = [
|
||||
"hubbub-sys 0.1.2 (git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hubbub-sys"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213"
|
||||
dependencies = [
|
||||
"parserutils-sys 0.1.1 (git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io_surface"
|
||||
version = "0.1.0"
|
||||
|
@ -291,8 +292,8 @@ dependencies = [
|
|||
"plugins 0.0.1",
|
||||
"script 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"style 0.0.1",
|
||||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
"util 0.0.1",
|
||||
|
@ -355,11 +356,6 @@ name = "openssl"
|
|||
version = "0.0.0"
|
||||
source = "git+https://github.com/sfackler/rust-openssl.git#a495465b75ffb18ff2303c5a11a103e00a15a13d"
|
||||
|
||||
[[package]]
|
||||
name = "parserutils-sys"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.0.0"
|
||||
|
@ -397,15 +393,15 @@ dependencies = [
|
|||
"encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom#b001a76e907befaae1d0d6dd259418a22092da86)",
|
||||
"gfx 0.0.1",
|
||||
"html5ever 0.0.0 (git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f)",
|
||||
"http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#5e9b063b36028a5b40a417c661ee5c628b594be9)",
|
||||
"hubbub 0.1.0 (git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b)",
|
||||
"js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)",
|
||||
"msg 0.0.1",
|
||||
"net 0.0.1",
|
||||
"plugins 0.0.1",
|
||||
"script_traits 0.0.1",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"style 0.0.1",
|
||||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
"util 0.0.1",
|
||||
|
@ -446,17 +442,17 @@ source = "git+https://github.com/servo/rust-stb-image#f5022de4ad6bb474a03493d1f2
|
|||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98"
|
||||
source = "git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb"
|
||||
dependencies = [
|
||||
"phf 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"phf_mac 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache_macros"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98"
|
||||
source = "git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb"
|
||||
dependencies = [
|
||||
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb9381d819edff80e360)",
|
||||
]
|
||||
|
@ -470,8 +466,8 @@ dependencies = [
|
|||
"geom 0.1.0 (git+https://github.com/servo/rust-geom#b001a76e907befaae1d0d6dd259418a22092da86)",
|
||||
"lazy_static 0.1.0 (git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb9381d819edff80e360)",
|
||||
"plugins 0.0.1",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
@ -494,8 +490,8 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"azure 0.1.0 (git+https://github.com/servo/rust-azure#b357751c04a89a87e6ef1f0cebe5f20957dd112d)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom#b001a76e907befaae1d0d6dd259418a22092da86)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#124b891ebb4564743068f99aaeb0e154de343efb)",
|
||||
"task_info 0.0.1",
|
||||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
]
|
||||
|
|
|
@ -42,8 +42,9 @@ git = "https://github.com/servo/rust-cssparser"
|
|||
[dependencies.geom]
|
||||
git = "https://github.com/servo/rust-geom"
|
||||
|
||||
[dependencies.hubbub]
|
||||
git = "https://github.com/servo/rust-hubbub"
|
||||
[dependencies.html5ever]
|
||||
git = "https://github.com/servo/html5ever"
|
||||
branch = "servo"
|
||||
|
||||
[dependencies.encoding]
|
||||
git = "https://github.com/lifthrasiir/rust-encoding"
|
||||
|
|
|
@ -42,7 +42,6 @@ use std::collections::hashmap::HashMap;
|
|||
use collections::hash::Hash;
|
||||
use style::PropertyDeclarationBlock;
|
||||
use std::comm::{Receiver, Sender};
|
||||
use hubbub::hubbub::QuirksMode;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use js::rust::Cx;
|
||||
use http::headers::response::HeaderCollection as ResponseHeaderCollection;
|
||||
|
@ -55,7 +54,9 @@ use servo_msg::constellation_msg::ConstellationChan;
|
|||
use servo_util::smallvec::{SmallVec1, SmallVec};
|
||||
use servo_util::str::LengthOrPercentageOrAuto;
|
||||
use layout_interface::{LayoutRPC, LayoutChan};
|
||||
use dom::node::{Node, TrustedNodeAddress};
|
||||
use dom::bindings::utils::WindowProxyHandler;
|
||||
use html5ever::tree_builder::QuirksMode;
|
||||
|
||||
impl<T: Reflectable> JSTraceable for JS<T> {
|
||||
fn trace(&self, trc: *mut JSTracer) {
|
||||
|
@ -207,6 +208,7 @@ untraceable!(ConstellationChan)
|
|||
untraceable!(LayoutChan)
|
||||
untraceable!(WindowProxyHandler)
|
||||
untraceable!(UntrustedNodeAddress)
|
||||
untraceable!(LengthOrPercentageOrAuto)
|
||||
|
||||
impl<'a> JSTraceable for &'a str {
|
||||
#[inline]
|
||||
|
@ -236,5 +238,12 @@ impl JSTraceable for Box<LayoutRPC+'static> {
|
|||
}
|
||||
}
|
||||
|
||||
untraceable!(LengthOrPercentageOrAuto)
|
||||
|
||||
impl JSTraceable for TrustedNodeAddress {
|
||||
fn trace(&self, s: *mut JSTracer) {
|
||||
let TrustedNodeAddress(addr) = *self;
|
||||
let node = addr as *const Node;
|
||||
unsafe {
|
||||
JS::from_raw(node).trace(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,12 +52,12 @@ use dom::range::Range;
|
|||
use dom::treewalker::TreeWalker;
|
||||
use dom::uievent::UIEvent;
|
||||
use dom::window::{Window, WindowHelpers};
|
||||
use html::hubbub_html_parser::build_element_from_tag;
|
||||
use hubbub::hubbub::{QuirksMode, NoQuirks, LimitedQuirks, FullQuirks};
|
||||
use parse::html::build_element_from_tag;
|
||||
use servo_util::namespace;
|
||||
use servo_util::str::{DOMString, split_html_space_chars};
|
||||
|
||||
use string_cache::Atom;
|
||||
use html5ever::tree_builder::{QuirksMode, NoQuirks, LimitedQuirks, Quirks};
|
||||
use string_cache::{Atom, QualName};
|
||||
use url::Url;
|
||||
|
||||
use std::collections::hashmap::HashMap;
|
||||
|
@ -426,7 +426,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
|||
fn CompatMode(self) -> DOMString {
|
||||
match self.quirks_mode.get() {
|
||||
LimitedQuirks | NoQuirks => "CSS1Compat".to_string(),
|
||||
FullQuirks => "BackCompat".to_string()
|
||||
Quirks => "BackCompat".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,7 +492,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
|||
return Err(InvalidCharacter);
|
||||
}
|
||||
let local_name = local_name.as_slice().to_ascii_lower();
|
||||
Ok(build_element_from_tag(local_name, ns!(HTML), None, self))
|
||||
let name = QualName::new(ns!(HTML), Atom::from_slice(local_name.as_slice()));
|
||||
Ok(build_element_from_tag(name, None, self))
|
||||
}
|
||||
|
||||
// http://dom.spec.whatwg.org/#dom-document-createelementns
|
||||
|
@ -512,9 +513,9 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
|||
QName => {}
|
||||
}
|
||||
|
||||
let (prefix_from_qname,
|
||||
local_name_from_qname) = get_attribute_parts(qualified_name.as_slice());
|
||||
match (&ns, prefix_from_qname.clone(), local_name_from_qname.as_slice()) {
|
||||
let (prefix_from_qname, local_name_from_qname)
|
||||
= get_attribute_parts(qualified_name.as_slice());
|
||||
match (&ns, prefix_from_qname, local_name_from_qname) {
|
||||
// throw if prefix is not null and namespace is null
|
||||
(&ns!(""), Some(_), _) => {
|
||||
debug!("Namespace can't be null with a non-null prefix");
|
||||
|
@ -536,8 +537,8 @@ impl<'a> DocumentMethods for JSRef<'a, Document> {
|
|||
}
|
||||
|
||||
if ns == ns!(HTML) {
|
||||
Ok(build_element_from_tag(local_name_from_qname.to_string(), ns,
|
||||
prefix_from_qname.map(|s| s.to_string()), self))
|
||||
let name = QualName::new(ns!(HTML), Atom::from_slice(local_name_from_qname));
|
||||
Ok(build_element_from_tag(name, prefix_from_qname.map(|s| s.to_string()), self))
|
||||
} else {
|
||||
Ok(Element::new(local_name_from_qname.to_string(), ns,
|
||||
prefix_from_qname.map(|s| s.to_string()), self))
|
||||
|
|
|
@ -42,7 +42,7 @@ use servo_util::str::{DOMString, LengthOrPercentageOrAuto};
|
|||
use std::ascii::StrAsciiExt;
|
||||
use std::default::Default;
|
||||
use std::mem;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use string_cache::{Atom, Namespace, QualName};
|
||||
use url::UrlParser;
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -397,9 +397,8 @@ pub trait AttributeHandlers {
|
|||
fn get_attributes(self, local_name: &Atom)
|
||||
-> Vec<Temporary<Attr>>;
|
||||
fn set_attribute_from_parser(self,
|
||||
local_name: Atom,
|
||||
name: QualName,
|
||||
value: DOMString,
|
||||
namespace: Namespace,
|
||||
prefix: Option<DOMString>);
|
||||
fn set_attribute(self, name: &Atom, value: AttrValue);
|
||||
fn do_set_attribute(self, local_name: Atom, value: AttrValue,
|
||||
|
@ -445,19 +444,24 @@ impl<'a> AttributeHandlers for JSRef<'a, Element> {
|
|||
}
|
||||
|
||||
fn set_attribute_from_parser(self,
|
||||
local_name: Atom,
|
||||
qname: QualName,
|
||||
value: DOMString,
|
||||
namespace: Namespace,
|
||||
prefix: Option<DOMString>) {
|
||||
// Don't set if the attribute already exists, so we can handle add_attrs_if_missing
|
||||
if self.attrs.borrow().iter().map(|attr| attr.root())
|
||||
.any(|a| *a.local_name() == qname.local && *a.namespace() == qname.ns) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = match prefix {
|
||||
None => local_name.clone(),
|
||||
None => qname.local.clone(),
|
||||
Some(ref prefix) => {
|
||||
let name = format!("{:s}:{:s}", *prefix, local_name.as_slice());
|
||||
let name = format!("{:s}:{:s}", *prefix, qname.local.as_slice());
|
||||
Atom::from_slice(name.as_slice())
|
||||
},
|
||||
};
|
||||
let value = self.parse_attribute(&namespace, &local_name, value);
|
||||
self.do_set_attribute(local_name, value, name, namespace, prefix, |_| false)
|
||||
let value = self.parse_attribute(&qname.ns, &qname.local, value);
|
||||
self.do_set_attribute(qname.local, value, name, qname.ns, prefix, |_| false)
|
||||
}
|
||||
|
||||
fn set_attribute(self, name: &Atom, value: AttrValue) {
|
||||
|
|
|
@ -44,9 +44,9 @@ use dom::text::Text;
|
|||
use dom::virtualmethods::{VirtualMethods, vtable_for};
|
||||
use dom::window::Window;
|
||||
use geom::rect::Rect;
|
||||
use html::hubbub_html_parser::build_element_from_tag;
|
||||
use parse::html::build_element_from_tag;
|
||||
use layout_interface::{ContentBoxResponse, ContentBoxesResponse, LayoutRPC,
|
||||
LayoutChan, ReapLayoutDataMsg, TrustedNodeAddress};
|
||||
LayoutChan, ReapLayoutDataMsg};
|
||||
use devtools_traits::NodeInfo;
|
||||
use script_traits::UntrustedNodeAddress;
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -56,7 +56,7 @@ use style::{parse_selector_list_from_str, matches};
|
|||
use js::jsapi::{JSContext, JSObject, JSTracer, JSRuntime};
|
||||
use js::jsfriendapi;
|
||||
use libc;
|
||||
use libc::uintptr_t;
|
||||
use libc::{uintptr_t, c_void};
|
||||
use std::cell::{Cell, RefCell, Ref, RefMut};
|
||||
use std::default::Default;
|
||||
use std::iter::{Map, Filter};
|
||||
|
@ -65,6 +65,7 @@ use style;
|
|||
use style::ComputedValues;
|
||||
use sync::Arc;
|
||||
use uuid;
|
||||
use string_cache::QualName;
|
||||
|
||||
//
|
||||
// The basic Node structure
|
||||
|
@ -1530,8 +1531,12 @@ impl Node {
|
|||
},
|
||||
ElementNodeTypeId(..) => {
|
||||
let element: JSRef<Element> = ElementCast::to_ref(node).unwrap();
|
||||
let element = build_element_from_tag(element.local_name().as_slice().to_string(),
|
||||
element.namespace().clone(), Some(element.prefix().as_slice().to_string()), *document);
|
||||
let name = QualName {
|
||||
ns: element.namespace().clone(),
|
||||
local: element.local_name().clone()
|
||||
};
|
||||
let element = build_element_from_tag(name,
|
||||
Some(element.prefix().as_slice().to_string()), *document);
|
||||
NodeCast::from_temporary(element)
|
||||
},
|
||||
TextNodeTypeId => {
|
||||
|
@ -2159,6 +2164,13 @@ impl Reflectable for Node {
|
|||
}
|
||||
}
|
||||
|
||||
/// The address of a node known to be valid. These are sent from script to layout,
|
||||
/// and are also used in the HTML parser interface.
|
||||
|
||||
#[allow(raw_pointer_deriving)]
|
||||
#[deriving(Clone, PartialEq, Eq)]
|
||||
pub struct TrustedNodeAddress(pub *const c_void);
|
||||
|
||||
pub fn document_from_node<T: NodeBase+Reflectable>(derived: JSRef<T>) -> Temporary<Document> {
|
||||
let node: JSRef<Node> = NodeCast::from_ref(derived);
|
||||
node.owner_doc()
|
||||
|
|
105
components/script/dom/servohtmlparser.rs
Normal file
105
components/script/dom/servohtmlparser.rs
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! The bulk of the HTML parser integration is in `script::parse::html`.
|
||||
//! This module is mostly about its interaction with DOM memory management.
|
||||
|
||||
use dom::bindings::codegen::Bindings::ServoHTMLParserBinding;
|
||||
use dom::bindings::global;
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::bindings::js::{JS, JSRef, Temporary};
|
||||
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
|
||||
use dom::node::TrustedNodeAddress;
|
||||
use dom::document::Document;
|
||||
use parse::html::JSMessage;
|
||||
|
||||
use std::default::Default;
|
||||
use std::cell::RefCell;
|
||||
use url::Url;
|
||||
use js::jsapi::JSTracer;
|
||||
use html5ever::tokenizer;
|
||||
use html5ever::tree_builder;
|
||||
use html5ever::tree_builder::{TreeBuilder, TreeBuilderOpts};
|
||||
|
||||
#[must_root]
|
||||
#[jstraceable]
|
||||
pub struct Sink {
|
||||
pub js_chan: Sender<JSMessage>,
|
||||
pub base_url: Option<Url>,
|
||||
pub document: JS<Document>,
|
||||
}
|
||||
|
||||
pub type Tokenizer = tokenizer::Tokenizer<TreeBuilder<TrustedNodeAddress, Sink>>;
|
||||
|
||||
// NB: JSTraceable is *not* auto-derived.
|
||||
// You must edit the impl below if you add fields!
|
||||
#[must_root]
|
||||
#[privatize]
|
||||
pub struct ServoHTMLParser {
|
||||
reflector_: Reflector,
|
||||
tokenizer: RefCell<Tokenizer>,
|
||||
}
|
||||
|
||||
impl ServoHTMLParser {
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(js_chan: Sender<JSMessage>, base_url: Option<Url>, document: JSRef<Document>)
|
||||
-> Temporary<ServoHTMLParser> {
|
||||
let window = document.window().root();
|
||||
let sink = Sink {
|
||||
js_chan: js_chan,
|
||||
base_url: base_url,
|
||||
document: JS::from_rooted(document),
|
||||
};
|
||||
|
||||
let tb = TreeBuilder::new(sink, TreeBuilderOpts {
|
||||
ignore_missing_rules: true,
|
||||
.. Default::default()
|
||||
});
|
||||
|
||||
let tok = tokenizer::Tokenizer::new(tb, Default::default());
|
||||
|
||||
let parser = ServoHTMLParser {
|
||||
reflector_: Reflector::new(),
|
||||
tokenizer: RefCell::new(tok),
|
||||
};
|
||||
|
||||
reflect_dom_object(box parser, &global::Window(*window), ServoHTMLParserBinding::Wrap)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn tokenizer<'a>(&'a self) -> &'a RefCell<Tokenizer> {
|
||||
&self.tokenizer
|
||||
}
|
||||
}
|
||||
|
||||
impl Reflectable for ServoHTMLParser {
|
||||
fn reflector<'a>(&'a self) -> &'a Reflector {
|
||||
&self.reflector_
|
||||
}
|
||||
}
|
||||
|
||||
struct Tracer {
|
||||
trc: *mut JSTracer,
|
||||
}
|
||||
|
||||
impl tree_builder::Tracer<TrustedNodeAddress> for Tracer {
|
||||
fn trace_handle(&self, node: TrustedNodeAddress) {
|
||||
node.trace(self.trc);
|
||||
}
|
||||
}
|
||||
|
||||
impl JSTraceable for ServoHTMLParser {
|
||||
fn trace(&self, trc: *mut JSTracer) {
|
||||
let tracer = Tracer {
|
||||
trc: trc,
|
||||
};
|
||||
let tracer = &tracer as &tree_builder::Tracer<TrustedNodeAddress>;
|
||||
|
||||
self.reflector_.trace(trc);
|
||||
let tokenizer = self.tokenizer.borrow();
|
||||
let tree_builder = tokenizer.sink();
|
||||
tree_builder.trace_handles(tracer);
|
||||
tree_builder.sink().trace(trc);
|
||||
}
|
||||
}
|
9
components/script/dom/webidls/ServoHTMLParser.webidl
Normal file
9
components/script/dom/webidls/ServoHTMLParser.webidl
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// FIXME: find a better way to hide this from content (#3688)
|
||||
[NoInterfaceObject]
|
||||
interface ServoHTMLParser {
|
||||
};
|
|
@ -6,14 +6,10 @@
|
|||
/// coupling between these two components, and enables the DOM to be placed in a separate crate
|
||||
/// from layout.
|
||||
|
||||
use dom::bindings::js::JS;
|
||||
use dom::bindings::trace::JSTraceable;
|
||||
use dom::node::{Node, LayoutDataRef};
|
||||
use dom::node::LayoutDataRef;
|
||||
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use js::jsapi::JSTracer;
|
||||
use libc::c_void;
|
||||
use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel, UntrustedNodeAddress};
|
||||
use servo_msg::constellation_msg::WindowSizeData;
|
||||
use servo_util::geometry::Au;
|
||||
|
@ -23,6 +19,8 @@ use std::owned::BoxAny;
|
|||
use style::Stylesheet;
|
||||
use url::Url;
|
||||
|
||||
pub use dom::node::TrustedNodeAddress;
|
||||
|
||||
/// Asynchronous messages that script can send to layout.
|
||||
pub enum Msg {
|
||||
/// Adds the given stylesheet to the document.
|
||||
|
@ -70,20 +68,6 @@ pub trait LayoutRPC {
|
|||
fn mouse_over(&self, node: TrustedNodeAddress, point: Point2D<f32>) -> Result<MouseOverResponse, ()>;
|
||||
}
|
||||
|
||||
/// The address of a node known to be valid. These must only be sent from content -> layout,
|
||||
/// because we do not trust layout.
|
||||
pub struct TrustedNodeAddress(pub *const c_void);
|
||||
|
||||
impl JSTraceable for TrustedNodeAddress {
|
||||
fn trace(&self, s: *mut JSTracer) {
|
||||
let TrustedNodeAddress(addr) = *self;
|
||||
let node = addr as *const Node;
|
||||
unsafe {
|
||||
JS::from_raw(node).trace(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ContentBoxResponse(pub Rect<Au>);
|
||||
pub struct ContentBoxesResponse(pub Vec<Rect<Au>>);
|
||||
pub struct HitTestResponse(pub UntrustedNodeAddress);
|
||||
|
|
|
@ -20,7 +20,7 @@ extern crate devtools_traits;
|
|||
extern crate cssparser;
|
||||
extern crate collections;
|
||||
extern crate geom;
|
||||
extern crate hubbub;
|
||||
extern crate html5ever;
|
||||
extern crate encoding;
|
||||
extern crate http;
|
||||
extern crate js;
|
||||
|
@ -191,6 +191,7 @@ pub mod dom {
|
|||
pub mod progressevent;
|
||||
pub mod range;
|
||||
pub mod screen;
|
||||
pub mod servohtmlparser;
|
||||
pub mod text;
|
||||
pub mod treewalker;
|
||||
pub mod uievent;
|
||||
|
@ -210,9 +211,8 @@ pub mod dom {
|
|||
pub mod testbinding;
|
||||
}
|
||||
|
||||
/// Parsers for HTML and CSS.
|
||||
pub mod html {
|
||||
pub mod hubbub_html_parser;
|
||||
pub mod parse {
|
||||
pub mod html;
|
||||
}
|
||||
|
||||
pub mod layout_interface;
|
||||
|
|
521
components/script/parse/html.rs
Normal file
521
components/script/parse/html.rs
Normal file
|
@ -0,0 +1,521 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::attr::AttrHelpers;
|
||||
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
|
||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLScriptElementCast};
|
||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
|
||||
use dom::document::{Document, DocumentHelpers};
|
||||
use dom::element::{AttributeHandlers, ElementHelpers};
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
|
||||
use dom::htmlformelement::HTMLFormElement;
|
||||
use dom::htmlscriptelement::HTMLScriptElementHelpers;
|
||||
use dom::node::{Node, NodeHelpers, TrustedNodeAddress};
|
||||
use dom::servohtmlparser;
|
||||
use dom::servohtmlparser::ServoHTMLParser;
|
||||
use dom::types::*;
|
||||
use page::Page;
|
||||
|
||||
use encoding::all::UTF_8;
|
||||
use encoding::types::{Encoding, DecodeReplace};
|
||||
|
||||
use servo_net::resource_task::{Load, LoadData, Payload, Done, ResourceTask, load_whole_resource};
|
||||
use servo_msg::constellation_msg::LoadData as MsgLoadData;
|
||||
use servo_util::task::spawn_named;
|
||||
use servo_util::str::DOMString;
|
||||
use std::ascii::StrAsciiExt;
|
||||
use std::comm::{channel, Sender, Receiver};
|
||||
use std::str::MaybeOwned;
|
||||
use url::{Url, UrlParser};
|
||||
use http::headers::HeaderEnum;
|
||||
use time;
|
||||
use html5ever::Attribute;
|
||||
use html5ever::tree_builder::{TreeSink, QuirksMode, NodeOrText, AppendNode, AppendText};
|
||||
use string_cache::QualName;
|
||||
|
||||
pub struct JSFile {
|
||||
pub data: String,
|
||||
pub url: Option<Url>,
|
||||
}
|
||||
|
||||
pub type JSResult = Vec<JSFile>;
|
||||
|
||||
pub enum HTMLInput {
|
||||
InputString(String),
|
||||
InputUrl(Url),
|
||||
}
|
||||
|
||||
pub enum JSMessage {
|
||||
JSTaskNewFile(Url),
|
||||
JSTaskNewInlineScript(String, Option<Url>),
|
||||
JSTaskExit
|
||||
}
|
||||
|
||||
/// Messages generated by the HTML parser upon discovery of additional resources
|
||||
pub enum HtmlDiscoveryMessage {
|
||||
HtmlDiscoveredScript(JSResult)
|
||||
}
|
||||
|
||||
pub struct HtmlParserResult {
|
||||
pub discovery_port: Receiver<HtmlDiscoveryMessage>,
|
||||
}
|
||||
|
||||
fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>,
|
||||
from_parent: Receiver<JSMessage>,
|
||||
resource_task: ResourceTask) {
|
||||
let mut result_vec = vec!();
|
||||
|
||||
loop {
|
||||
match from_parent.recv_opt() {
|
||||
Ok(JSTaskNewFile(url)) => {
|
||||
match load_whole_resource(&resource_task, url.clone()) {
|
||||
Err(_) => {
|
||||
error!("error loading script {:s}", url.serialize());
|
||||
}
|
||||
Ok((metadata, bytes)) => {
|
||||
let decoded = UTF_8.decode(bytes.as_slice(), DecodeReplace).unwrap();
|
||||
result_vec.push(JSFile {
|
||||
data: decoded.to_string(),
|
||||
url: Some(metadata.final_url),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(JSTaskNewInlineScript(data, url)) => {
|
||||
result_vec.push(JSFile { data: data, url: url });
|
||||
}
|
||||
Ok(JSTaskExit) | Err(()) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(to_parent.send_opt(HtmlDiscoveredScript(result_vec)).is_ok());
|
||||
}
|
||||
|
||||
// Parses an RFC 2616 compliant date/time string, and returns a localized
|
||||
// date/time string in a format suitable for document.lastModified.
|
||||
fn parse_last_modified(timestamp: &str) -> String {
|
||||
let format = "%m/%d/%Y %H:%M:%S";
|
||||
|
||||
// RFC 822, updated by RFC 1123
|
||||
match time::strptime(timestamp, "%a, %d %b %Y %T %Z") {
|
||||
Ok(t) => return t.to_local().strftime(format),
|
||||
Err(_) => ()
|
||||
}
|
||||
|
||||
// RFC 850, obsoleted by RFC 1036
|
||||
match time::strptime(timestamp, "%A, %d-%b-%y %T %Z") {
|
||||
Ok(t) => return t.to_local().strftime(format),
|
||||
Err(_) => ()
|
||||
}
|
||||
|
||||
// ANSI C's asctime() format
|
||||
match time::strptime(timestamp, "%c") {
|
||||
Ok(t) => t.to_local().strftime(format),
|
||||
Err(_) => String::from_str("")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_element_from_tag(name: QualName,
|
||||
prefix: Option<DOMString>,
|
||||
document: JSRef<Document>) -> Temporary<Element> {
|
||||
if name.ns != ns!(HTML) {
|
||||
return Element::new(name.local.as_slice().to_string(), name.ns, None, document);
|
||||
}
|
||||
|
||||
macro_rules! make(
|
||||
($ctor:ident $(, $arg:expr)*) => ({
|
||||
let obj = $ctor::new(name.local.as_slice().to_string(), prefix, document $(, $arg)*);
|
||||
ElementCast::from_temporary(obj)
|
||||
})
|
||||
)
|
||||
|
||||
// This is a big match, and the IDs for inline-interned atoms are not very structured.
|
||||
// Perhaps we should build a perfect hash from those IDs instead.
|
||||
match name.local {
|
||||
atom!("a") => make!(HTMLAnchorElement),
|
||||
atom!("abbr") => make!(HTMLElement),
|
||||
atom!("acronym") => make!(HTMLElement),
|
||||
atom!("address") => make!(HTMLElement),
|
||||
atom!("applet") => make!(HTMLAppletElement),
|
||||
atom!("area") => make!(HTMLAreaElement),
|
||||
atom!("article") => make!(HTMLElement),
|
||||
atom!("aside") => make!(HTMLElement),
|
||||
atom!("audio") => make!(HTMLAudioElement),
|
||||
atom!("b") => make!(HTMLElement),
|
||||
atom!("base") => make!(HTMLBaseElement),
|
||||
atom!("bdi") => make!(HTMLElement),
|
||||
atom!("bdo") => make!(HTMLElement),
|
||||
atom!("bgsound") => make!(HTMLElement),
|
||||
atom!("big") => make!(HTMLElement),
|
||||
atom!("blockquote") => make!(HTMLElement),
|
||||
atom!("body") => make!(HTMLBodyElement),
|
||||
atom!("br") => make!(HTMLBRElement),
|
||||
atom!("button") => make!(HTMLButtonElement),
|
||||
atom!("canvas") => make!(HTMLCanvasElement),
|
||||
atom!("caption") => make!(HTMLTableCaptionElement),
|
||||
atom!("center") => make!(HTMLElement),
|
||||
atom!("cite") => make!(HTMLElement),
|
||||
atom!("code") => make!(HTMLElement),
|
||||
atom!("col") => make!(HTMLTableColElement),
|
||||
atom!("colgroup") => make!(HTMLTableColElement),
|
||||
atom!("data") => make!(HTMLDataElement),
|
||||
atom!("datalist") => make!(HTMLDataListElement),
|
||||
atom!("dd") => make!(HTMLElement),
|
||||
atom!("del") => make!(HTMLModElement),
|
||||
atom!("details") => make!(HTMLElement),
|
||||
atom!("dfn") => make!(HTMLElement),
|
||||
atom!("dir") => make!(HTMLDirectoryElement),
|
||||
atom!("div") => make!(HTMLDivElement),
|
||||
atom!("dl") => make!(HTMLDListElement),
|
||||
atom!("dt") => make!(HTMLElement),
|
||||
atom!("em") => make!(HTMLElement),
|
||||
atom!("embed") => make!(HTMLEmbedElement),
|
||||
atom!("fieldset") => make!(HTMLFieldSetElement),
|
||||
atom!("figcaption") => make!(HTMLElement),
|
||||
atom!("figure") => make!(HTMLElement),
|
||||
atom!("font") => make!(HTMLFontElement),
|
||||
atom!("footer") => make!(HTMLElement),
|
||||
atom!("form") => make!(HTMLFormElement),
|
||||
atom!("frame") => make!(HTMLFrameElement),
|
||||
atom!("frameset") => make!(HTMLFrameSetElement),
|
||||
atom!("h1") => make!(HTMLHeadingElement, Heading1),
|
||||
atom!("h2") => make!(HTMLHeadingElement, Heading2),
|
||||
atom!("h3") => make!(HTMLHeadingElement, Heading3),
|
||||
atom!("h4") => make!(HTMLHeadingElement, Heading4),
|
||||
atom!("h5") => make!(HTMLHeadingElement, Heading5),
|
||||
atom!("h6") => make!(HTMLHeadingElement, Heading6),
|
||||
atom!("head") => make!(HTMLHeadElement),
|
||||
atom!("header") => make!(HTMLElement),
|
||||
atom!("hgroup") => make!(HTMLElement),
|
||||
atom!("hr") => make!(HTMLHRElement),
|
||||
atom!("html") => make!(HTMLHtmlElement),
|
||||
atom!("i") => make!(HTMLElement),
|
||||
atom!("iframe") => make!(HTMLIFrameElement),
|
||||
atom!("img") => make!(HTMLImageElement),
|
||||
atom!("input") => make!(HTMLInputElement),
|
||||
atom!("ins") => make!(HTMLModElement),
|
||||
atom!("isindex") => make!(HTMLElement),
|
||||
atom!("kbd") => make!(HTMLElement),
|
||||
atom!("label") => make!(HTMLLabelElement),
|
||||
atom!("legend") => make!(HTMLLegendElement),
|
||||
atom!("li") => make!(HTMLLIElement),
|
||||
atom!("link") => make!(HTMLLinkElement),
|
||||
atom!("main") => make!(HTMLElement),
|
||||
atom!("map") => make!(HTMLMapElement),
|
||||
atom!("mark") => make!(HTMLElement),
|
||||
atom!("marquee") => make!(HTMLElement),
|
||||
atom!("meta") => make!(HTMLMetaElement),
|
||||
atom!("meter") => make!(HTMLMeterElement),
|
||||
atom!("nav") => make!(HTMLElement),
|
||||
atom!("nobr") => make!(HTMLElement),
|
||||
atom!("noframes") => make!(HTMLElement),
|
||||
atom!("noscript") => make!(HTMLElement),
|
||||
atom!("object") => make!(HTMLObjectElement),
|
||||
atom!("ol") => make!(HTMLOListElement),
|
||||
atom!("optgroup") => make!(HTMLOptGroupElement),
|
||||
atom!("option") => make!(HTMLOptionElement),
|
||||
atom!("output") => make!(HTMLOutputElement),
|
||||
atom!("p") => make!(HTMLParagraphElement),
|
||||
atom!("param") => make!(HTMLParamElement),
|
||||
atom!("pre") => make!(HTMLPreElement),
|
||||
atom!("progress") => make!(HTMLProgressElement),
|
||||
atom!("q") => make!(HTMLQuoteElement),
|
||||
atom!("rp") => make!(HTMLElement),
|
||||
atom!("rt") => make!(HTMLElement),
|
||||
atom!("ruby") => make!(HTMLElement),
|
||||
atom!("s") => make!(HTMLElement),
|
||||
atom!("samp") => make!(HTMLElement),
|
||||
atom!("script") => make!(HTMLScriptElement),
|
||||
atom!("section") => make!(HTMLElement),
|
||||
atom!("select") => make!(HTMLSelectElement),
|
||||
atom!("small") => make!(HTMLElement),
|
||||
atom!("source") => make!(HTMLSourceElement),
|
||||
atom!("spacer") => make!(HTMLElement),
|
||||
atom!("span") => make!(HTMLSpanElement),
|
||||
atom!("strike") => make!(HTMLElement),
|
||||
atom!("strong") => make!(HTMLElement),
|
||||
atom!("style") => make!(HTMLStyleElement),
|
||||
atom!("sub") => make!(HTMLElement),
|
||||
atom!("summary") => make!(HTMLElement),
|
||||
atom!("sup") => make!(HTMLElement),
|
||||
atom!("table") => make!(HTMLTableElement),
|
||||
atom!("tbody") => make!(HTMLTableSectionElement),
|
||||
atom!("td") => make!(HTMLTableDataCellElement),
|
||||
atom!("template") => make!(HTMLTemplateElement),
|
||||
atom!("textarea") => make!(HTMLTextAreaElement),
|
||||
atom!("th") => make!(HTMLTableHeaderCellElement),
|
||||
atom!("time") => make!(HTMLTimeElement),
|
||||
atom!("title") => make!(HTMLTitleElement),
|
||||
atom!("tr") => make!(HTMLTableRowElement),
|
||||
atom!("tt") => make!(HTMLElement),
|
||||
atom!("track") => make!(HTMLTrackElement),
|
||||
atom!("u") => make!(HTMLElement),
|
||||
atom!("ul") => make!(HTMLUListElement),
|
||||
atom!("var") => make!(HTMLElement),
|
||||
atom!("video") => make!(HTMLVideoElement),
|
||||
atom!("wbr") => make!(HTMLElement),
|
||||
_ => make!(HTMLUnknownElement),
|
||||
}
|
||||
}
|
||||
|
||||
trait SinkHelpers {
|
||||
fn get_or_create(&self, child: NodeOrText<TrustedNodeAddress>) -> Temporary<Node>;
|
||||
}
|
||||
|
||||
impl SinkHelpers for servohtmlparser::Sink {
|
||||
fn get_or_create(&self, child: NodeOrText<TrustedNodeAddress>) -> Temporary<Node> {
|
||||
match child {
|
||||
AppendNode(n) => Temporary::new(unsafe { JS::from_trusted_node_address(n) }),
|
||||
AppendText(t) => {
|
||||
let doc = self.document.root();
|
||||
let text = Text::new(t, *doc);
|
||||
NodeCast::from_temporary(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TreeSink<TrustedNodeAddress> for servohtmlparser::Sink {
|
||||
fn get_document(&mut self) -> TrustedNodeAddress {
|
||||
let doc = self.document.root();
|
||||
let node: JSRef<Node> = NodeCast::from_ref(*doc);
|
||||
node.to_trusted_node_address()
|
||||
}
|
||||
|
||||
fn same_node(&self, x: TrustedNodeAddress, y: TrustedNodeAddress) -> bool {
|
||||
x == y
|
||||
}
|
||||
|
||||
fn elem_name(&self, target: TrustedNodeAddress) -> QualName {
|
||||
let node: Root<Node> = unsafe { JS::from_trusted_node_address(target).root() };
|
||||
let elem: JSRef<Element> = ElementCast::to_ref(*node)
|
||||
.expect("tried to get name of non-Element in HTML parsing");
|
||||
QualName {
|
||||
ns: elem.get_namespace().clone(),
|
||||
local: elem.get_local_name().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>)
|
||||
-> TrustedNodeAddress {
|
||||
let doc = self.document.root();
|
||||
let elem = build_element_from_tag(name, None, *doc).root();
|
||||
|
||||
for attr in attrs.into_iter() {
|
||||
elem.set_attribute_from_parser(attr.name, attr.value, None);
|
||||
}
|
||||
|
||||
let node: JSRef<Node> = NodeCast::from_ref(*elem);
|
||||
node.to_trusted_node_address()
|
||||
}
|
||||
|
||||
fn create_comment(&mut self, text: String) -> TrustedNodeAddress {
|
||||
let doc = self.document.root();
|
||||
let comment = Comment::new(text, *doc);
|
||||
let node: Root<Node> = NodeCast::from_temporary(comment).root();
|
||||
node.to_trusted_node_address()
|
||||
}
|
||||
|
||||
fn append_before_sibling(&mut self,
|
||||
sibling: TrustedNodeAddress,
|
||||
new_node: NodeOrText<TrustedNodeAddress>) -> Result<(), NodeOrText<TrustedNodeAddress>> {
|
||||
// If there is no parent, return the node to the parser.
|
||||
let sibling: Root<Node> = unsafe { JS::from_trusted_node_address(sibling).root() };
|
||||
let parent = match sibling.parent_node() {
|
||||
Some(p) => p.root(),
|
||||
None => return Err(new_node),
|
||||
};
|
||||
|
||||
let child = self.get_or_create(new_node).root();
|
||||
assert!(parent.InsertBefore(*child, Some(*sibling)).is_ok());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_error(&mut self, msg: MaybeOwned<'static>) {
|
||||
error!("Parse error: {:s}", msg);
|
||||
}
|
||||
|
||||
fn set_quirks_mode(&mut self, mode: QuirksMode) {
|
||||
let doc = self.document.root();
|
||||
doc.set_quirks_mode(mode);
|
||||
}
|
||||
|
||||
fn append(&mut self, parent: TrustedNodeAddress, child: NodeOrText<TrustedNodeAddress>) {
|
||||
let parent: Root<Node> = unsafe { JS::from_trusted_node_address(parent).root() };
|
||||
let child = self.get_or_create(child).root();
|
||||
|
||||
// FIXME(#3701): Use a simpler algorithm and merge adjacent text nodes
|
||||
assert!(parent.AppendChild(*child).is_ok());
|
||||
}
|
||||
|
||||
fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String) {
|
||||
let doc = self.document.root();
|
||||
let doc_node: JSRef<Node> = NodeCast::from_ref(*doc);
|
||||
let doctype = DocumentType::new(name, Some(public_id), Some(system_id), *doc);
|
||||
let node: Root<Node> = NodeCast::from_temporary(doctype).root();
|
||||
|
||||
assert!(doc_node.AppendChild(*node).is_ok());
|
||||
}
|
||||
|
||||
fn add_attrs_if_missing(&mut self, target: TrustedNodeAddress, attrs: Vec<Attribute>) {
|
||||
let node: Root<Node> = unsafe { JS::from_trusted_node_address(target).root() };
|
||||
let elem: JSRef<Element> = ElementCast::to_ref(*node)
|
||||
.expect("tried to set attrs on non-Element in HTML parsing");
|
||||
for attr in attrs.into_iter() {
|
||||
elem.set_attribute_from_parser(attr.name, attr.value, None);
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_from_parent(&mut self, _target: TrustedNodeAddress) {
|
||||
error!("remove_from_parent not implemented!");
|
||||
}
|
||||
|
||||
fn mark_script_already_started(&mut self, _node: TrustedNodeAddress) {
|
||||
error!("mark_script_already_started not implemented!");
|
||||
}
|
||||
|
||||
fn complete_script(&mut self, node: TrustedNodeAddress) {
|
||||
let node: Root<Node> = unsafe { JS::from_trusted_node_address(node).root() };
|
||||
let script: Option<JSRef<HTMLScriptElement>> =
|
||||
HTMLScriptElementCast::to_ref(*node);
|
||||
let script = match script {
|
||||
Some(script) if script.is_javascript() => script,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let script_element: JSRef<Element> = ElementCast::from_ref(script);
|
||||
match script_element.get_attribute(ns!(""), &atom!("src")).root() {
|
||||
Some(src) => {
|
||||
debug!("found script: {:s}", src.deref().Value());
|
||||
let mut url_parser = UrlParser::new();
|
||||
match self.base_url {
|
||||
None => (),
|
||||
Some(ref base_url) => {
|
||||
url_parser.base_url(base_url);
|
||||
}
|
||||
};
|
||||
match url_parser.parse(src.deref().value().as_slice()) {
|
||||
Ok(new_url) => self.js_chan.send(JSTaskNewFile(new_url)),
|
||||
Err(e) => debug!("Parsing url {:s} failed: {:?}", src.deref().Value(), e)
|
||||
};
|
||||
}
|
||||
None => {
|
||||
let scriptnode: JSRef<Node> = NodeCast::from_ref(script);
|
||||
let data = Node::collect_text_contents(scriptnode.children());
|
||||
debug!("script data = {:?}", data);
|
||||
self.js_chan.send(JSTaskNewInlineScript(data, self.base_url.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The url from msg_load_data is ignored here
|
||||
pub fn parse_html(page: &Page,
|
||||
document: JSRef<Document>,
|
||||
input: HTMLInput,
|
||||
resource_task: ResourceTask,
|
||||
msg_load_data: Option<MsgLoadData>)
|
||||
-> HtmlParserResult {
|
||||
// Spawn a JS parser to receive JavaScript.
|
||||
let (discovery_chan, discovery_port) = channel();
|
||||
let resource_task2 = resource_task.clone();
|
||||
let js_result_chan = discovery_chan.clone();
|
||||
let (js_chan, js_msg_port) = channel();
|
||||
spawn_named("parse_html:js", proc() {
|
||||
js_script_listener(js_result_chan, js_msg_port, resource_task2.clone());
|
||||
});
|
||||
|
||||
let (base_url, load_response) = match input {
|
||||
InputUrl(ref url) => {
|
||||
// Wait for the LoadResponse so that the parser knows the final URL.
|
||||
let (input_chan, input_port) = channel();
|
||||
let mut load_data = LoadData::new(url.clone());
|
||||
msg_load_data.map(|m| {
|
||||
load_data.headers = m.headers;
|
||||
load_data.method = m.method;
|
||||
load_data.data = m.data;
|
||||
});
|
||||
resource_task.send(Load(load_data, input_chan));
|
||||
|
||||
let load_response = input_port.recv();
|
||||
|
||||
debug!("Fetched page; metadata is {:?}", load_response.metadata);
|
||||
|
||||
load_response.metadata.headers.as_ref().map(|headers| {
|
||||
let header = headers.iter().find(|h|
|
||||
h.header_name().as_slice().to_ascii_lower() == "last-modified".to_string()
|
||||
);
|
||||
|
||||
match header {
|
||||
Some(h) => document.set_last_modified(
|
||||
parse_last_modified(h.header_value().as_slice())),
|
||||
None => {},
|
||||
};
|
||||
});
|
||||
|
||||
let base_url = load_response.metadata.final_url.clone();
|
||||
|
||||
{
|
||||
// Store the final URL before we start parsing, so that DOM routines
|
||||
// (e.g. HTMLImageElement::update_image) can resolve relative URLs
|
||||
// correctly.
|
||||
*page.mut_url() = Some((base_url.clone(), true));
|
||||
}
|
||||
|
||||
(Some(base_url), Some(load_response))
|
||||
},
|
||||
InputString(_) => {
|
||||
match *page.url() {
|
||||
Some((ref page_url, _)) => (Some(page_url.clone()), None),
|
||||
None => (None, None),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let parser = ServoHTMLParser::new(js_chan.clone(), base_url.clone(), document).root();
|
||||
let parser: JSRef<ServoHTMLParser> = *parser;
|
||||
|
||||
match input {
|
||||
InputString(s) => {
|
||||
parser.tokenizer().borrow_mut().feed(s);
|
||||
}
|
||||
InputUrl(url) => {
|
||||
let load_response = load_response.unwrap();
|
||||
match load_response.metadata.content_type {
|
||||
Some((ref t, _)) if t.as_slice().eq_ignore_ascii_case("image") => {
|
||||
let page = format!("<html><body><img src='{:s}' /></body></html>", base_url.as_ref().unwrap().serialize());
|
||||
parser.tokenizer().borrow_mut().feed(page);
|
||||
},
|
||||
_ => {
|
||||
for msg in load_response.progress_port.iter() {
|
||||
match msg {
|
||||
Payload(data) => {
|
||||
// FIXME: use Vec<u8> (html5ever #34)
|
||||
let data = String::from_utf8(data).unwrap();
|
||||
parser.tokenizer().borrow_mut().feed(data);
|
||||
}
|
||||
Done(Err(err)) => {
|
||||
fail!("Failed to load page URL {:s}, error: {:s}", url.serialize(), err);
|
||||
}
|
||||
Done(Ok(())) => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser.tokenizer().borrow_mut().end();
|
||||
|
||||
debug!("finished parsing");
|
||||
js_chan.send(JSTaskExit);
|
||||
|
||||
HtmlParserResult {
|
||||
discovery_port: discovery_port,
|
||||
}
|
||||
}
|
|
@ -27,8 +27,7 @@ use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
|
|||
use dom::window::{Window, WindowHelpers};
|
||||
use dom::worker::{Worker, TrustedWorkerAddress};
|
||||
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
|
||||
use html::hubbub_html_parser::{InputString, InputUrl, HtmlParserResult, HtmlDiscoveredScript};
|
||||
use html::hubbub_html_parser;
|
||||
use parse::html::{InputString, InputUrl, HtmlParserResult, HtmlDiscoveredScript, parse_html};
|
||||
use layout_interface::{ScriptLayoutChan, LayoutChan, ReflowForDisplay};
|
||||
use layout_interface;
|
||||
use page::{Page, IterablePage, Frame};
|
||||
|
@ -781,16 +780,9 @@ impl ScriptTask {
|
|||
// Parse HTML.
|
||||
//
|
||||
// Note: We can parse the next document in parallel with any previous documents.
|
||||
let html_parsing_result =
|
||||
hubbub_html_parser::parse_html(&*page,
|
||||
*document,
|
||||
parser_input,
|
||||
self.resource_task.clone(),
|
||||
Some(load_data));
|
||||
|
||||
let HtmlParserResult {
|
||||
discovery_port
|
||||
} = html_parsing_result;
|
||||
let HtmlParserResult { discovery_port }
|
||||
= parse_html(&*page, *document, parser_input, self.resource_task.clone(),
|
||||
Some(load_data));
|
||||
|
||||
{
|
||||
// Create the root frame.
|
||||
|
|
40
ports/cef/Cargo.lock
generated
40
ports/cef/Cargo.lock
generated
|
@ -234,6 +234,23 @@ name = "harfbuzz"
|
|||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-harfbuzz#ad520942cc17232e1a40cdd8a99c2905623d35f6"
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f"
|
||||
dependencies = [
|
||||
"html5ever_macros 0.0.0 (git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f)",
|
||||
"phf 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"phf_mac 0.0.0 (git+https://github.com/sfackler/rust-phf#06254fdde7708630a6397c41c6c17ef81a4b66a0)",
|
||||
"string_cache 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
"string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache#97754929f38d93f6728d1f0acce8107648420e98)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "html5ever_macros"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.1.0-pre"
|
||||
|
@ -243,22 +260,6 @@ dependencies = [
|
|||
"url 0.1.0 (git+https://github.com/servo/rust-url#29f70a47230c2aa736e263977247c786e0b2c243)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hubbub"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b"
|
||||
dependencies = [
|
||||
"hubbub-sys 0.1.2 (git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hubbub-sys"
|
||||
version = "0.1.2"
|
||||
source = "git+https://github.com/servo/libhubbub#6d09893991dedc616b264058442a304c03842213"
|
||||
dependencies = [
|
||||
"parserutils-sys 0.1.1 (git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io_surface"
|
||||
version = "0.1.0"
|
||||
|
@ -366,11 +367,6 @@ name = "openssl"
|
|||
version = "0.0.0"
|
||||
source = "git+https://github.com/sfackler/rust-openssl.git#a495465b75ffb18ff2303c5a11a103e00a15a13d"
|
||||
|
||||
[[package]]
|
||||
name = "parserutils-sys"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/servo/libparserutils#651b636ba1214bceeb0907adb1eab60efe0d4598"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.0.0"
|
||||
|
@ -408,8 +404,8 @@ dependencies = [
|
|||
"encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#28eafb604a92c7786685b46c0fc02682ba3ab265)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom#b001a76e907befaae1d0d6dd259418a22092da86)",
|
||||
"gfx 0.0.1",
|
||||
"html5ever 0.0.0 (git+https://github.com/servo/html5ever?ref=servo#0bdd6087dc8df6a92c96e1859bbb4ebbb0be7c1f)",
|
||||
"http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#5e9b063b36028a5b40a417c661ee5c628b594be9)",
|
||||
"hubbub 0.1.0 (git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b)",
|
||||
"js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)",
|
||||
"msg 0.0.1",
|
||||
"net 0.0.1",
|
||||
|
|
|
@ -176,3 +176,4 @@ fragment=top != ../html/acid2.html acid2_ref.html
|
|||
== legacy_td_width_attribute_a.html legacy_td_width_attribute_ref.html
|
||||
== box_sizing_sanity_check_a.html box_sizing_sanity_check_ref.html
|
||||
== inline_block_overflow_hidden_a.html inline_block_overflow_hidden_ref.html
|
||||
== issue-1324.html issue-1324-ref.html
|
||||
|
|
1
tests/ref/issue-1324-ref.html
Normal file
1
tests/ref/issue-1324-ref.html
Normal file
|
@ -0,0 +1 @@
|
|||
<!doctype html><p>Test</p>
|
1
tests/ref/issue-1324.html
Normal file
1
tests/ref/issue-1324.html
Normal file
|
@ -0,0 +1 @@
|
|||
<!doctype html><p>Test
|
|
@ -1,5 +1,3 @@
|
|||
[open-url-encoding.htm]
|
||||
type: testharness
|
||||
[XMLHttpRequest: open() - URL encoding]
|
||||
expected: FAIL
|
||||
|
||||
expected: TIMEOUT
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[send-content-type-string.htm]
|
||||
type: testharness
|
||||
expected: TIMEOUT
|
|
@ -108,15 +108,3 @@
|
|||
[parent is picture, previous source has type removed]
|
||||
expected: FAIL
|
||||
|
||||
[ancestor picture has a source removed]
|
||||
expected: FAIL
|
||||
|
||||
[ancestor picture; previous sibling source removed]
|
||||
expected: FAIL
|
||||
|
||||
[src on previous sibling source set]
|
||||
expected: FAIL
|
||||
|
||||
[class on previous sibling source set]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
["\\n\\ndata:,a\\n\\n1x\\n\\n"]
|
||||
expected: FAIL
|
||||
|
||||
["\xef\xbf\xbd\xef\xbf\xbddata:,a\xef\xbf\xbd\xef\xbf\xbd1x\xef\xbf\xbd\xef\xbf\xbd"]
|
||||
expected: FAIL
|
||||
|
||||
["\\f\\fdata:,a\\f\\f1x\\f\\f"]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -267,9 +264,6 @@
|
|||
["data:,a 0X1w"]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\xef\xbf\xbdw" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\xc2\xa0w" (trailing U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -327,9 +321,6 @@
|
|||
["data:,a 1\xef\xbb\xbfw" (trailing U+FEFF)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \xef\xbf\xbd1w" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \xc2\xa01w" (leading U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -423,9 +414,6 @@
|
|||
["data:,a 0X1x"]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\xef\xbf\xbdx" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\xc2\xa0x" (trailing U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -483,9 +471,6 @@
|
|||
["data:,a 1\xef\xbb\xbfx" (trailing U+FEFF)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \xef\xbf\xbd1x" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \xc2\xa01x" (leading U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -573,9 +558,6 @@
|
|||
["data:,a 0X1h"]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w 1\xef\xbf\xbdh" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w 1\xc2\xa0h" (trailing U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -633,9 +615,6 @@
|
|||
["data:,a 1w 1\xef\xbb\xbfh" (trailing U+FEFF)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w \xef\xbf\xbd1h" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w \xc2\xa01h" (leading U+00A0)]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -693,3 +672,36 @@
|
|||
["data:,a 1w \xef\xbb\xbf1h" (leading U+FEFF)]
|
||||
expected: FAIL
|
||||
|
||||
["\\v\\vdata:,a\\v\\v1x\\v\\v"]
|
||||
expected: FAIL
|
||||
|
||||
["\\r\\rdata:,a\\r\\r1x\\r\\r"]
|
||||
expected: FAIL
|
||||
|
||||
["\\x0e\\x0edata:,a\\x0e\\x0e1x\\x0e\\x0e"]
|
||||
expected: FAIL
|
||||
|
||||
["\\x0f\\x0fdata:,a\\x0f\\x0f1x\\x0f\\x0f"]
|
||||
expected: FAIL
|
||||
|
||||
["\\x10\\x10data:,a\\x10\\x101x\\x10\\x10"]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\\x01w" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \\x011w" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1\\x01x" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a \\x011x" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w 1\\x01h" (trailing U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
["data:,a 1w \\x011h" (leading U+0001)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -66,168 +66,9 @@
|
|||
[<picture></picture><span></span><source srcset="data:,b"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><svg></svg><source srcset="data:,b"></source><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><svg></svg><source srcset="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><svg></svg><!--<font face> tag breaks out of svg--><font face=""></font><source srcset="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><img src="data:,a"><img src="data:,b" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source>]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source src="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset=", ,">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b 1x 1x">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and (min-width:0)">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and !">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and (!)">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (min-width:0)">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (max-width:0)">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and !">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (!)">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all, !">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media=",">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=" ">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=" image/gif">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif ">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings=">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings=foobar">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/png">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/jpeg">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/svg+xml">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/x-icon">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/xml">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/html">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/plain">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/css">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/mp4">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/ogg">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/webm">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="unknown/unknown">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="application/octet-stream">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="application/x-shockwave-flash">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image\\gif">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="gif">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=".gif">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="*">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="*/*">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/*">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=",">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif, image/png">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif image/png">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/foobarbaz">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><img src="data:,a" data-expect="data:,a">foo]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -249,12 +90,177 @@
|
|||
[<picture></picture><img data-expect=""><source srcset="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><span></span><source srcset="data:,b">]
|
||||
[<picture></picture><svg></svg><source srcset="data:,b"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b">]
|
||||
[<picture></picture><svg></svg><source srcset="data:,b"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media=", all">]
|
||||
[<picture></picture><svg></svg><font></font><source srcset="data:,b"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><svg></svg><!--<font face> tag breaks out of svg--><font face=""></font><source srcset="data:,b"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source src="data:,b"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset=""><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset=", ,"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b 1x 1x"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media=""><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and (min-width:0)"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and !"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all and (!)"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (min-width:0)"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (max-width:0)"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and !"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="not all and (!)"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media="all, !"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media=","><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" media=", all"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=""><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=" "><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=" image/gif"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif "><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings="><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif;encodings=foobar"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/png"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/jpeg"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/svg+xml"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/x-icon"><img src="data:,a" data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/xml"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/html"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/plain"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="text/css"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/mp4"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/ogg"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="video/webm"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="unknown/unknown"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="application/octet-stream"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="application/x-shockwave-flash"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image\\gif"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="gif"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=".gif"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="*"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="*/*"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/*"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type=","><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif, image/png"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/gif image/png"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b" type="image/foobarbaz"><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><span></span><source srcset="data:,b"><img data-expect="">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b"><span></span><img src="data:,a" data-expect="data:,a">]
|
||||
expected: FAIL
|
||||
|
||||
[<picture></picture><source srcset="data:,b"><img data-expect="data:,b">]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue