mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Merge pull request #3352 from mbrubeck/link-style
Move link rel=stylesheet fetching to layout task. r=jdm
This commit is contained in:
commit
0e2cdc5cca
17 changed files with 154 additions and 196 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -256,6 +256,7 @@ dependencies = [
|
||||||
name = "layout"
|
name = "layout"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"encoding 0.1.0 (git+https://github.com/lifthrasiir/rust-encoding#12b6610adff6eddc060691888c36017cd3ad57f7)",
|
||||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)",
|
"geom 0.1.0 (git+https://github.com/servo/rust-geom#2982b770db6e5e3270305e0fd6b8068f6f80a489)",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
"layout_traits 0.0.1",
|
"layout_traits 0.0.1",
|
||||||
|
|
|
@ -80,7 +80,7 @@ impl Pipeline {
|
||||||
script_port,
|
script_port,
|
||||||
constellation_chan.clone(),
|
constellation_chan.clone(),
|
||||||
failure.clone(),
|
failure.clone(),
|
||||||
resource_task,
|
resource_task.clone(),
|
||||||
image_cache_task.clone(),
|
image_cache_task.clone(),
|
||||||
window_size);
|
window_size);
|
||||||
ScriptControlChan(script_chan)
|
ScriptControlChan(script_chan)
|
||||||
|
@ -117,6 +117,7 @@ impl Pipeline {
|
||||||
failure,
|
failure,
|
||||||
script_chan.clone(),
|
script_chan.clone(),
|
||||||
render_chan.clone(),
|
render_chan.clone(),
|
||||||
|
resource_task,
|
||||||
image_cache_task,
|
image_cache_task,
|
||||||
font_cache_task,
|
font_cache_task,
|
||||||
opts.clone(),
|
opts.clone(),
|
||||||
|
|
|
@ -31,6 +31,9 @@ path = "../net"
|
||||||
[dependencies.util]
|
[dependencies.util]
|
||||||
path = "../util"
|
path = "../util"
|
||||||
|
|
||||||
|
[dependencies.encoding]
|
||||||
|
git = "https://github.com/lifthrasiir/rust-encoding"
|
||||||
|
|
||||||
[dependencies.geom]
|
[dependencies.geom]
|
||||||
git = "https://github.com/servo/rust-geom"
|
git = "https://github.com/servo/rust-geom"
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@ use util::{LayoutDataAccess, LayoutDataWrapper, OpaqueNodeMethods, ToGfxColor};
|
||||||
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
|
use wrapper::{LayoutNode, TLayoutNode, ThreadSafeLayoutNode};
|
||||||
|
|
||||||
use collections::dlist::DList;
|
use collections::dlist::DList;
|
||||||
|
use encoding::EncodingRef;
|
||||||
|
use encoding::all::UTF_8;
|
||||||
use geom::point::Point2D;
|
use geom::point::Point2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
|
@ -33,7 +35,7 @@ use layout_traits::{LayoutControlMsg, LayoutTaskFactory};
|
||||||
use script::dom::bindings::js::JS;
|
use script::dom::bindings::js::JS;
|
||||||
use script::dom::node::{ElementNodeTypeId, LayoutDataRef, Node};
|
use script::dom::node::{ElementNodeTypeId, LayoutDataRef, Node};
|
||||||
use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
|
use script::dom::element::{HTMLBodyElementTypeId, HTMLHtmlElementTypeId};
|
||||||
use script::layout_interface::{AddStylesheetMsg, ScriptLayoutChan};
|
use script::layout_interface::{AddStylesheetMsg, LoadStylesheetMsg, ScriptLayoutChan};
|
||||||
use script::layout_interface::{TrustedNodeAddress, ContentBoxesResponse, ExitNowMsg};
|
use script::layout_interface::{TrustedNodeAddress, ContentBoxesResponse, ExitNowMsg};
|
||||||
use script::layout_interface::{ContentBoxResponse, HitTestResponse, MouseOverResponse};
|
use script::layout_interface::{ContentBoxResponse, HitTestResponse, MouseOverResponse};
|
||||||
use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
|
use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, PrepareToExitMsg};
|
||||||
|
@ -46,6 +48,7 @@ use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
|
||||||
use gfx::font_cache_task::{FontCacheTask};
|
use gfx::font_cache_task::{FontCacheTask};
|
||||||
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
|
||||||
use servo_util::bloom::BloomFilter;
|
use servo_util::bloom::BloomFilter;
|
||||||
|
use servo_net::resource_task::{ResourceTask, load_bytes_iter};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::logical_geometry::LogicalPoint;
|
use servo_util::logical_geometry::LogicalPoint;
|
||||||
|
@ -112,6 +115,9 @@ pub struct LayoutTask {
|
||||||
/// The channel on which messages can be sent to the time profiler.
|
/// The channel on which messages can be sent to the time profiler.
|
||||||
pub time_profiler_chan: TimeProfilerChan,
|
pub time_profiler_chan: TimeProfilerChan,
|
||||||
|
|
||||||
|
/// The channel on which messages can be sent to the resource task.
|
||||||
|
pub resource_task: ResourceTask,
|
||||||
|
|
||||||
/// The channel on which messages can be sent to the image cache.
|
/// The channel on which messages can be sent to the image cache.
|
||||||
pub image_cache_task: ImageCacheTask,
|
pub image_cache_task: ImageCacheTask,
|
||||||
|
|
||||||
|
@ -298,6 +304,7 @@ impl LayoutTaskFactory for LayoutTask {
|
||||||
failure_msg: Failure,
|
failure_msg: Failure,
|
||||||
script_chan: ScriptControlChan,
|
script_chan: ScriptControlChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
|
resource_task: ResourceTask,
|
||||||
img_cache_task: ImageCacheTask,
|
img_cache_task: ImageCacheTask,
|
||||||
font_cache_task: FontCacheTask,
|
font_cache_task: FontCacheTask,
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
|
@ -316,6 +323,7 @@ impl LayoutTaskFactory for LayoutTask {
|
||||||
constellation_chan,
|
constellation_chan,
|
||||||
script_chan,
|
script_chan,
|
||||||
render_chan,
|
render_chan,
|
||||||
|
resource_task,
|
||||||
img_cache_task,
|
img_cache_task,
|
||||||
font_cache_task,
|
font_cache_task,
|
||||||
&opts,
|
&opts,
|
||||||
|
@ -365,6 +373,7 @@ impl LayoutTask {
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
script_chan: ScriptControlChan,
|
script_chan: ScriptControlChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
|
resource_task: ResourceTask,
|
||||||
image_cache_task: ImageCacheTask,
|
image_cache_task: ImageCacheTask,
|
||||||
font_cache_task: FontCacheTask,
|
font_cache_task: FontCacheTask,
|
||||||
opts: &Opts,
|
opts: &Opts,
|
||||||
|
@ -387,6 +396,7 @@ impl LayoutTask {
|
||||||
script_chan: script_chan,
|
script_chan: script_chan,
|
||||||
render_chan: render_chan,
|
render_chan: render_chan,
|
||||||
time_profiler_chan: time_profiler_chan,
|
time_profiler_chan: time_profiler_chan,
|
||||||
|
resource_task: resource_task,
|
||||||
image_cache_task: image_cache_task.clone(),
|
image_cache_task: image_cache_task.clone(),
|
||||||
font_cache_task: font_cache_task,
|
font_cache_task: font_cache_task,
|
||||||
opts: opts.clone(),
|
opts: opts.clone(),
|
||||||
|
@ -494,6 +504,7 @@ impl LayoutTask {
|
||||||
fn handle_script_request<'a>(&'a self, request: Msg, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) -> bool {
|
fn handle_script_request<'a>(&'a self, request: Msg, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) -> bool {
|
||||||
match request {
|
match request {
|
||||||
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet, possibly_locked_rw_data),
|
AddStylesheetMsg(sheet) => self.handle_add_stylesheet(sheet, possibly_locked_rw_data),
|
||||||
|
LoadStylesheetMsg(url) => self.handle_load_stylesheet(url, possibly_locked_rw_data),
|
||||||
GetRPCMsg(response_chan) => {
|
GetRPCMsg(response_chan) => {
|
||||||
response_chan.send(
|
response_chan.send(
|
||||||
box LayoutRPCImpl(
|
box LayoutRPCImpl(
|
||||||
|
@ -567,6 +578,18 @@ impl LayoutTask {
|
||||||
response_port.recv()
|
response_port.recv()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_load_stylesheet<'a>(&'a self, url: Url, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
||||||
|
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
||||||
|
let environment_encoding = UTF_8 as EncodingRef;
|
||||||
|
|
||||||
|
let (metadata, iter) = load_bytes_iter(&self.resource_task, url);
|
||||||
|
let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice());
|
||||||
|
let final_url = metadata.final_url;
|
||||||
|
|
||||||
|
let sheet = Stylesheet::from_bytes_iter(iter, final_url, protocol_encoding_label, Some(environment_encoding));
|
||||||
|
self.handle_add_stylesheet(sheet, possibly_locked_rw_data);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_add_stylesheet<'a>(&'a self, sheet: Stylesheet, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
fn handle_add_stylesheet<'a>(&'a self, sheet: Stylesheet, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) {
|
||||||
// Find all font-face rules and notify the font cache of them.
|
// Find all font-face rules and notify the font cache of them.
|
||||||
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
// GWTODO: Need to handle unloading web fonts (when we handle unloading stylesheets!)
|
||||||
|
|
|
@ -29,6 +29,7 @@ extern crate servo_msg = "msg";
|
||||||
extern crate servo_util = "util";
|
extern crate servo_util = "util";
|
||||||
|
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
|
extern crate encoding;
|
||||||
extern crate green;
|
extern crate green;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
extern crate sync;
|
extern crate sync;
|
||||||
|
|
|
@ -23,6 +23,7 @@ use gfx::render_task::RenderChan;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
||||||
use servo_msg::constellation_msg::Failure;
|
use servo_msg::constellation_msg::Failure;
|
||||||
use servo_net::image_cache_task::ImageCacheTask;
|
use servo_net::image_cache_task::ImageCacheTask;
|
||||||
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::opts::Opts;
|
use servo_util::opts::Opts;
|
||||||
use servo_util::time::TimeProfilerChan;
|
use servo_util::time::TimeProfilerChan;
|
||||||
use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel};
|
use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel};
|
||||||
|
@ -48,6 +49,7 @@ pub trait LayoutTaskFactory {
|
||||||
failure_msg: Failure,
|
failure_msg: Failure,
|
||||||
script_chan: ScriptControlChan,
|
script_chan: ScriptControlChan,
|
||||||
render_chan: RenderChan,
|
render_chan: RenderChan,
|
||||||
|
resource_task: ResourceTask,
|
||||||
img_cache_task: ImageCacheTask,
|
img_cache_task: ImageCacheTask,
|
||||||
font_cache_task: FontCacheTask,
|
font_cache_task: FontCacheTask,
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
|
|
|
@ -219,6 +219,34 @@ impl ResourceManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load a URL asynchronously and iterate over chunks of bytes from the response.
|
||||||
|
pub fn load_bytes_iter(resource_task: &ResourceTask, url: Url) -> (Metadata, ProgressMsgPortIterator) {
|
||||||
|
let (input_chan, input_port) = channel();
|
||||||
|
resource_task.send(Load(LoadData::new(url), input_chan));
|
||||||
|
|
||||||
|
let response = input_port.recv();
|
||||||
|
let iter = ProgressMsgPortIterator { progress_port: response.progress_port };
|
||||||
|
(response.metadata, iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterator that reads chunks of bytes from a ProgressMsg port
|
||||||
|
pub struct ProgressMsgPortIterator {
|
||||||
|
progress_port: Receiver<ProgressMsg>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator<Vec<u8>> for ProgressMsgPortIterator {
|
||||||
|
fn next(&mut self) -> Option<Vec<u8>> {
|
||||||
|
match self.progress_port.recv() {
|
||||||
|
Payload(data) => Some(data),
|
||||||
|
Done(Ok(())) => None,
|
||||||
|
Done(Err(e)) => {
|
||||||
|
error!("error receiving bytes: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exit() {
|
fn test_exit() {
|
||||||
let resource_task = new_resource_task();
|
let resource_task = new_resource_task();
|
||||||
|
|
|
@ -2,20 +2,25 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::attr::AttrHelpers;
|
||||||
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
|
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
|
||||||
use dom::bindings::codegen::InheritTypes::HTMLLinkElementDerived;
|
use dom::bindings::codegen::InheritTypes::HTMLLinkElementDerived;
|
||||||
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast};
|
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
|
||||||
use dom::bindings::js::{JSRef, Temporary};
|
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
|
||||||
use dom::bindings::utils::{Reflectable, Reflector};
|
use dom::bindings::utils::{Reflectable, Reflector};
|
||||||
use dom::document::Document;
|
use dom::document::Document;
|
||||||
use dom::element::HTMLLinkElementTypeId;
|
use dom::element::{AttributeHandlers, Element, HTMLLinkElementTypeId};
|
||||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
|
use layout_interface::{LayoutChan, LoadStylesheetMsg};
|
||||||
use servo_util::atom::Atom;
|
use servo_util::atom::Atom;
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||||
|
use servo_util::namespace::Null;
|
||||||
|
|
||||||
|
use std::ascii::StrAsciiExt;
|
||||||
|
use url::UrlParser;
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
pub struct HTMLLinkElement {
|
pub struct HTMLLinkElement {
|
||||||
|
@ -72,6 +77,55 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> {
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bind_to_tree(&self, tree_in_doc: bool) {
|
||||||
|
match self.super_type() {
|
||||||
|
Some(ref s) => s.bind_to_tree(tree_in_doc),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
if tree_in_doc {
|
||||||
|
let element: &JSRef<Element> = ElementCast::from_ref(self);
|
||||||
|
|
||||||
|
// FIXME: workaround for https://github.com/mozilla/rust/issues/13246;
|
||||||
|
// we get unrooting order failures if these are inside the match.
|
||||||
|
let rel = {
|
||||||
|
let rel = element.get_attribute(Null, "rel").root();
|
||||||
|
rel.map(|rel| rel.deref().value().as_slice().to_string())
|
||||||
|
};
|
||||||
|
let href = {
|
||||||
|
let href = element.get_attribute(Null, "href").root();
|
||||||
|
href.map(|href| href.deref().value().as_slice().to_string())
|
||||||
|
};
|
||||||
|
|
||||||
|
match (rel, href) {
|
||||||
|
(Some(ref rel), Some(ref href)) => {
|
||||||
|
if rel.as_slice().split(HTML_SPACE_CHARACTERS.as_slice())
|
||||||
|
.any(|s| s.as_slice().eq_ignore_ascii_case("stylesheet")) {
|
||||||
|
self.handle_stylesheet_url(href.as_slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PrivateHTMLLinkElementHelpers {
|
||||||
|
fn handle_stylesheet_url(&self, href: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PrivateHTMLLinkElementHelpers for JSRef<'a, HTMLLinkElement> {
|
||||||
|
fn handle_stylesheet_url(&self, href: &str) {
|
||||||
|
let window = window_from_node(self).root();
|
||||||
|
match UrlParser::new().base_url(&window.deref().page().get_url()).parse(href) {
|
||||||
|
Ok(url) => {
|
||||||
|
let LayoutChan(ref layout_chan) = *window.deref().page().layout_chan;
|
||||||
|
layout_chan.send(LoadStylesheetMsg(url));
|
||||||
|
}
|
||||||
|
Err(e) => debug!("Parsing url {:s} failed: {:?}", href, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reflectable for HTMLLinkElement {
|
impl Reflectable for HTMLLinkElement {
|
||||||
|
|
|
@ -13,9 +13,9 @@ use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
|
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
|
||||||
use dom::virtualmethods::VirtualMethods;
|
use dom::virtualmethods::VirtualMethods;
|
||||||
use html::cssparse::parse_inline_css;
|
|
||||||
use layout_interface::{AddStylesheetMsg, LayoutChan};
|
use layout_interface::{AddStylesheetMsg, LayoutChan};
|
||||||
use servo_util::str::DOMString;
|
use servo_util::str::DOMString;
|
||||||
|
use style::Stylesheet;
|
||||||
|
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable)]
|
||||||
pub struct HTMLStyleElement {
|
pub struct HTMLStyleElement {
|
||||||
|
@ -54,7 +54,7 @@ impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> {
|
||||||
let url = win.deref().page().get_url();
|
let url = win.deref().page().get_url();
|
||||||
|
|
||||||
let data = node.GetTextContent().expect("Element.textContent must be a string");
|
let data = node.GetTextContent().expect("Element.textContent must be a string");
|
||||||
let sheet = parse_inline_css(url, data);
|
let sheet = Stylesheet::from_str(data.as_slice(), url);
|
||||||
let LayoutChan(ref layout_chan) = *win.deref().page().layout_chan;
|
let LayoutChan(ref layout_chan) = *win.deref().page().layout_chan;
|
||||||
layout_chan.send(AddStylesheetMsg(sheet));
|
layout_chan.send(AddStylesheetMsg(sheet));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
/// Some little helpers for hooking up the HTML parser with the CSS parser.
|
|
||||||
|
|
||||||
use std::comm::{channel, Receiver};
|
|
||||||
use encoding::EncodingRef;
|
|
||||||
use encoding::all::UTF_8;
|
|
||||||
use style::Stylesheet;
|
|
||||||
use servo_net::resource_task::{Load, LoadData, LoadResponse, ProgressMsg, Payload, Done, ResourceTask};
|
|
||||||
use servo_util::task::spawn_named;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
/// Where a style sheet comes from.
|
|
||||||
pub enum StylesheetProvenance {
|
|
||||||
UrlProvenance(Url, ResourceTask),
|
|
||||||
InlineProvenance(Url, String),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the style data and returns the stylesheet
|
|
||||||
pub fn parse_inline_css(url: Url, data: String) -> Stylesheet {
|
|
||||||
parse_css(InlineProvenance(url, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_css(provenance: StylesheetProvenance) -> Stylesheet {
|
|
||||||
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
|
|
||||||
let environment_encoding = UTF_8 as EncodingRef;
|
|
||||||
|
|
||||||
match provenance {
|
|
||||||
UrlProvenance(url, resource_task) => {
|
|
||||||
debug!("cssparse: loading style sheet at {:s}", url.serialize());
|
|
||||||
let (input_chan, input_port) = channel();
|
|
||||||
resource_task.send(Load(LoadData::new(url), input_chan));
|
|
||||||
let LoadResponse { metadata: metadata, progress_port: progress_port , ..}
|
|
||||||
= input_port.recv();
|
|
||||||
let final_url = &metadata.final_url;
|
|
||||||
let protocol_encoding_label = metadata.charset.as_ref().map(|s| s.as_slice());
|
|
||||||
let iter = ProgressMsgPortIterator { progress_port: progress_port };
|
|
||||||
Stylesheet::from_bytes_iter(
|
|
||||||
iter, final_url.clone(),
|
|
||||||
protocol_encoding_label, Some(environment_encoding))
|
|
||||||
}
|
|
||||||
InlineProvenance(base_url, data) => {
|
|
||||||
debug!("cssparse: loading inline stylesheet {:s}", data);
|
|
||||||
Stylesheet::from_str(data.as_slice(), base_url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawn_css_parser(provenance: StylesheetProvenance) -> Receiver<Stylesheet> {
|
|
||||||
let (result_chan, result_port) = channel();
|
|
||||||
|
|
||||||
spawn_named("cssparser", proc() {
|
|
||||||
result_chan.send(parse_css(provenance));
|
|
||||||
});
|
|
||||||
|
|
||||||
return result_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ProgressMsgPortIterator {
|
|
||||||
progress_port: Receiver<ProgressMsg>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator<Vec<u8>> for ProgressMsgPortIterator {
|
|
||||||
fn next(&mut self) -> Option<Vec<u8>> {
|
|
||||||
match self.progress_port.recv() {
|
|
||||||
Payload(data) => Some(data),
|
|
||||||
Done(..) => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,14 +10,13 @@ use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast};
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
|
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
|
||||||
use dom::bindings::utils::Reflectable;
|
use dom::bindings::utils::Reflectable;
|
||||||
use dom::document::{Document, DocumentHelpers};
|
use dom::document::{Document, DocumentHelpers};
|
||||||
use dom::element::{AttributeHandlers, HTMLLinkElementTypeId};
|
use dom::element::AttributeHandlers;
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
|
use dom::htmlheadingelement::{Heading1, Heading2, Heading3, Heading4, Heading5, Heading6};
|
||||||
use dom::htmlformelement::HTMLFormElement;
|
use dom::htmlformelement::HTMLFormElement;
|
||||||
use dom::htmlscriptelement::HTMLScriptElementHelpers;
|
use dom::htmlscriptelement::HTMLScriptElementHelpers;
|
||||||
use dom::node::{ElementNodeTypeId, NodeHelpers};
|
use dom::node::NodeHelpers;
|
||||||
use dom::types::*;
|
use dom::types::*;
|
||||||
use html::cssparse::{StylesheetProvenance, UrlProvenance, spawn_css_parser};
|
|
||||||
use page::Page;
|
use page::Page;
|
||||||
|
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
|
@ -29,13 +28,12 @@ use servo_net::resource_task::{Load, LoadData, Payload, Done, ResourceTask, load
|
||||||
use servo_util::atom::Atom;
|
use servo_util::atom::Atom;
|
||||||
use servo_util::namespace;
|
use servo_util::namespace;
|
||||||
use servo_util::namespace::{Namespace, Null};
|
use servo_util::namespace::{Namespace, Null};
|
||||||
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
use servo_util::str::DOMString;
|
||||||
use servo_util::task::spawn_named;
|
use servo_util::task::spawn_named;
|
||||||
use std::ascii::StrAsciiExt;
|
use std::ascii::StrAsciiExt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::comm::{channel, Sender, Receiver};
|
use std::comm::{channel, Sender, Receiver};
|
||||||
use style::Stylesheet;
|
|
||||||
use url::{Url, UrlParser};
|
use url::{Url, UrlParser};
|
||||||
use http::headers::HeaderEnum;
|
use http::headers::HeaderEnum;
|
||||||
use time;
|
use time;
|
||||||
|
@ -65,11 +63,6 @@ pub enum HTMLInput {
|
||||||
InputUrl(Url),
|
InputUrl(Url),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CSSMessage {
|
|
||||||
CSSTaskNewFile(StylesheetProvenance),
|
|
||||||
CSSTaskExit
|
|
||||||
}
|
|
||||||
|
|
||||||
enum JSMessage {
|
enum JSMessage {
|
||||||
JSTaskNewFile(Url),
|
JSTaskNewFile(Url),
|
||||||
JSTaskNewInlineScript(String, Option<Url>),
|
JSTaskNewInlineScript(String, Option<Url>),
|
||||||
|
@ -78,7 +71,6 @@ enum JSMessage {
|
||||||
|
|
||||||
/// Messages generated by the HTML parser upon discovery of additional resources
|
/// Messages generated by the HTML parser upon discovery of additional resources
|
||||||
pub enum HtmlDiscoveryMessage {
|
pub enum HtmlDiscoveryMessage {
|
||||||
HtmlDiscoveredStyle(Stylesheet),
|
|
||||||
HtmlDiscoveredScript(JSResult)
|
HtmlDiscoveredScript(JSResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,43 +92,6 @@ unsafe fn from_hubbub_node<T: Reflectable>(n: hubbub::NodeDataPtr) -> Temporary<
|
||||||
Temporary::new(JS::from_raw(mem::transmute(n)))
|
Temporary::new(JS::from_raw(mem::transmute(n)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Runs a task that coordinates parsing links to css stylesheets.
|
|
||||||
|
|
||||||
This function should be spawned in a separate task and spins waiting
|
|
||||||
for the html builder to find links to css stylesheets and sends off
|
|
||||||
tasks to parse each link. When the html process finishes, it notifies
|
|
||||||
the listener, who then collects the css rules from each task it
|
|
||||||
spawned, collates them, and sends them to the given result channel.
|
|
||||||
|
|
||||||
# Arguments
|
|
||||||
|
|
||||||
* `to_parent` - A channel on which to send back the full set of rules.
|
|
||||||
* `from_parent` - A port on which to receive new links.
|
|
||||||
|
|
||||||
*/
|
|
||||||
fn css_link_listener(to_parent: Sender<HtmlDiscoveryMessage>,
|
|
||||||
from_parent: Receiver<CSSMessage>) {
|
|
||||||
let mut result_vec = vec!();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match from_parent.recv_opt() {
|
|
||||||
Ok(CSSTaskNewFile(provenance)) => {
|
|
||||||
result_vec.push(spawn_css_parser(provenance));
|
|
||||||
}
|
|
||||||
Ok(CSSTaskExit) | Err(()) => {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the sheets back in order
|
|
||||||
// FIXME: Shouldn't wait until after we've recieved CSSTaskExit to start sending these
|
|
||||||
for port in result_vec.iter() {
|
|
||||||
assert!(to_parent.send_opt(HtmlDiscoveredStyle(port.recv())).is_ok());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>,
|
fn js_script_listener(to_parent: Sender<HtmlDiscoveryMessage>,
|
||||||
from_parent: Receiver<JSMessage>,
|
from_parent: Receiver<JSMessage>,
|
||||||
resource_task: ResourceTask) {
|
resource_task: ResourceTask) {
|
||||||
|
@ -335,16 +290,9 @@ pub fn parse_html(page: &Page,
|
||||||
resource_task: ResourceTask)
|
resource_task: ResourceTask)
|
||||||
-> HtmlParserResult {
|
-> HtmlParserResult {
|
||||||
debug!("Hubbub: parsing {:?}", input);
|
debug!("Hubbub: parsing {:?}", input);
|
||||||
// Spawn a CSS parser to receive links to CSS style sheets.
|
|
||||||
|
|
||||||
let (discovery_chan, discovery_port) = channel();
|
|
||||||
let stylesheet_chan = discovery_chan.clone();
|
|
||||||
let (css_chan, css_msg_port) = channel();
|
|
||||||
spawn_named("parse_html:css", proc() {
|
|
||||||
css_link_listener(stylesheet_chan, css_msg_port);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Spawn a JS parser to receive JavaScript.
|
// Spawn a JS parser to receive JavaScript.
|
||||||
|
let (discovery_chan, discovery_port) = channel();
|
||||||
let resource_task2 = resource_task.clone();
|
let resource_task2 = resource_task.clone();
|
||||||
let js_result_chan = discovery_chan.clone();
|
let js_result_chan = discovery_chan.clone();
|
||||||
let (js_chan, js_msg_port) = channel();
|
let (js_chan, js_msg_port) = channel();
|
||||||
|
@ -395,7 +343,7 @@ pub fn parse_html(page: &Page,
|
||||||
let mut parser = build_parser(unsafe { document.to_hubbub_node() });
|
let mut parser = build_parser(unsafe { document.to_hubbub_node() });
|
||||||
debug!("created parser");
|
debug!("created parser");
|
||||||
|
|
||||||
let (css_chan2, js_chan2) = (css_chan.clone(), js_chan.clone());
|
let js_chan2 = js_chan.clone();
|
||||||
|
|
||||||
let doc_cell = RefCell::new(document);
|
let doc_cell = RefCell::new(document);
|
||||||
|
|
||||||
|
@ -447,54 +395,6 @@ pub fn parse_html(page: &Page,
|
||||||
prefix.map(|p| p.to_string()));
|
prefix.map(|p| p.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: workaround for https://github.com/mozilla/rust/issues/13246;
|
|
||||||
// we get unrooting order failures if these are inside the match.
|
|
||||||
let rel = {
|
|
||||||
let rel = element.deref().get_attribute(Null, "rel").root();
|
|
||||||
rel.map(|a| a.deref().Value())
|
|
||||||
};
|
|
||||||
let href = {
|
|
||||||
let href= element.deref().get_attribute(Null, "href").root();
|
|
||||||
href.map(|a| a.deref().Value())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Spawn additional parsing, network loads, etc. from tag and attrs
|
|
||||||
let type_id = {
|
|
||||||
let node: &JSRef<Node> = NodeCast::from_ref(&*element);
|
|
||||||
node.type_id()
|
|
||||||
};
|
|
||||||
match type_id {
|
|
||||||
// Handle CSS style sheets from <link> elements
|
|
||||||
ElementNodeTypeId(HTMLLinkElementTypeId) => {
|
|
||||||
match (rel, href) {
|
|
||||||
(Some(ref rel), Some(ref href)) => {
|
|
||||||
if rel.as_slice()
|
|
||||||
.split(HTML_SPACE_CHARACTERS.as_slice())
|
|
||||||
.any(|s| {
|
|
||||||
s.as_slice().eq_ignore_ascii_case("stylesheet")
|
|
||||||
}) {
|
|
||||||
debug!("found CSS stylesheet: {:s}", *href);
|
|
||||||
let mut url_parser = UrlParser::new();
|
|
||||||
match base_url {
|
|
||||||
None => (),
|
|
||||||
Some(ref base_url) => {
|
|
||||||
url_parser.base_url(base_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match url_parser.parse(href.as_slice()) {
|
|
||||||
Ok(url) => css_chan2.send(CSSTaskNewFile(
|
|
||||||
UrlProvenance(url, resource_task.clone()))),
|
|
||||||
Err(e) => debug!("Parsing url {:s} failed: {:?}", *href, e)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { element.deref().to_hubbub_node() }
|
unsafe { element.deref().to_hubbub_node() }
|
||||||
},
|
},
|
||||||
create_text: |data: String| {
|
create_text: |data: String| {
|
||||||
|
@ -641,7 +541,6 @@ pub fn parse_html(page: &Page,
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("finished parsing");
|
debug!("finished parsing");
|
||||||
css_chan.send(CSSTaskExit);
|
|
||||||
js_chan.send(JSTaskExit);
|
js_chan.send(JSTaskExit);
|
||||||
|
|
||||||
HtmlParserResult {
|
HtmlParserResult {
|
||||||
|
|
|
@ -29,6 +29,9 @@ pub enum Msg {
|
||||||
/// Adds the given stylesheet to the document.
|
/// Adds the given stylesheet to the document.
|
||||||
AddStylesheetMsg(Stylesheet),
|
AddStylesheetMsg(Stylesheet),
|
||||||
|
|
||||||
|
/// Adds the given stylesheet to the document.
|
||||||
|
LoadStylesheetMsg(Url),
|
||||||
|
|
||||||
/// Requests a reflow.
|
/// Requests a reflow.
|
||||||
ReflowMsg(Box<Reflow>),
|
ReflowMsg(Box<Reflow>),
|
||||||
|
|
||||||
|
|
|
@ -199,7 +199,6 @@ pub mod dom {
|
||||||
|
|
||||||
/// Parsers for HTML and CSS.
|
/// Parsers for HTML and CSS.
|
||||||
pub mod html {
|
pub mod html {
|
||||||
pub mod cssparse;
|
|
||||||
pub mod hubbub_html_parser;
|
pub mod hubbub_html_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,8 @@ use dom::node::{ElementNodeTypeId, Node, NodeHelpers};
|
||||||
use dom::window::{TimerId, Window, WindowHelpers};
|
use dom::window::{TimerId, Window, WindowHelpers};
|
||||||
use dom::worker::{Worker, TrustedWorkerAddress};
|
use dom::worker::{Worker, TrustedWorkerAddress};
|
||||||
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
|
use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress};
|
||||||
use html::hubbub_html_parser::{InputString, InputUrl, HtmlParserResult};
|
use html::hubbub_html_parser::{InputString, InputUrl, HtmlParserResult, HtmlDiscoveredScript};
|
||||||
use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript};
|
|
||||||
use html::hubbub_html_parser;
|
use html::hubbub_html_parser;
|
||||||
use layout_interface::AddStylesheetMsg;
|
|
||||||
use layout_interface::{ScriptLayoutChan, LayoutChan, MatchSelectorsDocumentDamage};
|
use layout_interface::{ScriptLayoutChan, LayoutChan, MatchSelectorsDocumentDamage};
|
||||||
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay};
|
use layout_interface::{ReflowDocumentDamage, ReflowForDisplay};
|
||||||
use layout_interface::ContentChangedDocumentDamage;
|
use layout_interface::ContentChangedDocumentDamage;
|
||||||
|
@ -682,10 +680,6 @@ impl ScriptTask {
|
||||||
assert!(js_scripts.is_none());
|
assert!(js_scripts.is_none());
|
||||||
js_scripts = Some(scripts);
|
js_scripts = Some(scripts);
|
||||||
}
|
}
|
||||||
Ok(HtmlDiscoveredStyle(sheet)) => {
|
|
||||||
let LayoutChan(ref chan) = *page.layout_chan;
|
|
||||||
chan.send(AddStylesheetMsg(sheet));
|
|
||||||
}
|
|
||||||
Err(()) => break
|
Err(()) => break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,3 +124,4 @@ flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html
|
||||||
== inline_block_baseline_a.html inline_block_baseline_ref.html
|
== inline_block_baseline_a.html inline_block_baseline_ref.html
|
||||||
== float_table_a.html float_table_ref.html
|
== float_table_a.html float_table_ref.html
|
||||||
== table_containing_block_a.html table_containing_block_ref.html
|
== table_containing_block_a.html table_containing_block_ref.html
|
||||||
|
== link_style_order.html link_style_order_ref.html
|
||||||
|
|
11
tests/ref/link_style_order.html
Normal file
11
tests/ref/link_style_order.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>link/style order test</title>
|
||||||
|
<link rel="stylesheet" href="data:text/css,body{background:red;}">
|
||||||
|
<style>body { background: green; }</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
10
tests/ref/link_style_order_ref.html
Normal file
10
tests/ref/link_style_order_ref.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>link/style order test</title>
|
||||||
|
<style>body { background: green; }</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue