mirror of
https://github.com/servo/servo.git
synced 2025-07-31 19:20:22 +01:00
script: Abstract HTMLLinkElement and StyleElement into StylesheetOwner.
This commit is contained in:
parent
072db0279a
commit
b9901fbd89
4 changed files with 117 additions and 91 deletions
|
@ -51,9 +51,11 @@ use dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
|
|||
use dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
|
||||
use dom::htmllabelelement::HTMLLabelElement;
|
||||
use dom::htmllegendelement::HTMLLegendElement;
|
||||
use dom::htmllinkelement::HTMLLinkElement;
|
||||
use dom::htmlobjectelement::HTMLObjectElement;
|
||||
use dom::htmloptgroupelement::HTMLOptGroupElement;
|
||||
use dom::htmlselectelement::HTMLSelectElement;
|
||||
use dom::htmlstyleelement::HTMLStyleElement;
|
||||
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementLayoutHelpers};
|
||||
use dom::htmltableelement::{HTMLTableElement, HTMLTableElementLayoutHelpers};
|
||||
use dom::htmltablerowelement::{HTMLTableRowElement, HTMLTableRowElementLayoutHelpers};
|
||||
|
@ -109,6 +111,7 @@ use style::sink::Push;
|
|||
use style::stylist::ApplicableDeclarationBlock;
|
||||
use style::values::CSSFloat;
|
||||
use style::values::specified::{self, CSSColor, CSSRGBA, LengthOrPercentage};
|
||||
use stylesheet_loader::StylesheetOwner;
|
||||
|
||||
// TODO: Update focus state when the top-level browsing context gains or loses system focus,
|
||||
// and when the element enters or leaves a browsing context container.
|
||||
|
@ -2407,6 +2410,18 @@ impl Element {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn as_stylesheet_owner(&self) -> Option<&StylesheetOwner> {
|
||||
if let Some(s) = self.downcast::<HTMLStyleElement>() {
|
||||
return Some(s as &StylesheetOwner)
|
||||
}
|
||||
|
||||
if let Some(l) = self.downcast::<HTMLLinkElement>() {
|
||||
return Some(l as &StylesheetOwner)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#category-submit
|
||||
pub fn as_maybe_validatable(&self) -> Option<&Validatable> {
|
||||
let element = match self.upcast::<Node>().type_id() {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
use cssparser::Parser as CssParser;
|
||||
use dom::attr::Attr;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListBinding::DOMTokenListMethods;
|
||||
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementMethods;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
|
@ -20,6 +21,7 @@ use dom::node::{Node, document_from_node, window_from_node};
|
|||
use dom::stylesheet::StyleSheet as DOMStyleSheet;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use html5ever_atoms::LocalName;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use script_traits::{MozBrowserEvent, ScriptMsg as ConstellationMsg};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::ToOwned;
|
||||
|
@ -30,7 +32,7 @@ use style::attr::AttrValue;
|
|||
use style::media_queries::parse_media_query_list;
|
||||
use style::str::HTML_SPACE_CHARACTERS;
|
||||
use style::stylesheets::Stylesheet;
|
||||
use stylesheet_loader::{StylesheetLoader, StylesheetContextSource};
|
||||
use stylesheet_loader::{StylesheetLoader, StylesheetContextSource, StylesheetOwner};
|
||||
|
||||
unsafe_no_jsmanaged_fields!(Stylesheet);
|
||||
|
||||
|
@ -216,28 +218,6 @@ impl VirtualMethods for HTMLLinkElement {
|
|||
|
||||
|
||||
impl HTMLLinkElement {
|
||||
pub fn increment_pending_loads_count(&self) {
|
||||
self.pending_loads.set(self.pending_loads.get() + 1)
|
||||
}
|
||||
|
||||
/// Returns None if there are still pending loads, or whether any load has
|
||||
/// failed since the loads started.
|
||||
pub fn load_finished(&self, succeeded: bool) -> Option<bool> {
|
||||
assert!(self.pending_loads.get() > 0, "What finished?");
|
||||
if !succeeded {
|
||||
self.any_failed_load.set(true);
|
||||
}
|
||||
|
||||
self.pending_loads.set(self.pending_loads.get() - 1);
|
||||
if self.pending_loads.get() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let any_failed = self.any_failed_load.get();
|
||||
self.any_failed_load.set(false);
|
||||
Some(any_failed)
|
||||
}
|
||||
|
||||
/// https://html.spec.whatwg.org/multipage/#concept-link-obtain
|
||||
fn handle_stylesheet_url(&self, href: &str) {
|
||||
let document = document_from_node(self);
|
||||
|
@ -297,6 +277,40 @@ impl HTMLLinkElement {
|
|||
}
|
||||
}
|
||||
|
||||
impl StylesheetOwner for HTMLLinkElement {
|
||||
fn increment_pending_loads_count(&self) {
|
||||
self.pending_loads.set(self.pending_loads.get() + 1)
|
||||
}
|
||||
|
||||
fn load_finished(&self, succeeded: bool) -> Option<bool> {
|
||||
assert!(self.pending_loads.get() > 0, "What finished?");
|
||||
if !succeeded {
|
||||
self.any_failed_load.set(true);
|
||||
}
|
||||
|
||||
self.pending_loads.set(self.pending_loads.get() - 1);
|
||||
if self.pending_loads.get() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let any_failed = self.any_failed_load.get();
|
||||
self.any_failed_load.set(false);
|
||||
Some(any_failed)
|
||||
}
|
||||
|
||||
fn parser_inserted(&self) -> bool {
|
||||
self.parser_inserted.get()
|
||||
}
|
||||
|
||||
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
|
||||
if self.RelList().Contains("noreferrer".into()) {
|
||||
return Some(ReferrerPolicy::NoReferrer)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLLinkElementMethods for HTMLLinkElement {
|
||||
// https://html.spec.whatwg.org/multipage/#dom-link-href
|
||||
make_url_getter!(Href, "href");
|
||||
|
|
|
@ -19,13 +19,14 @@ use dom::node::{ChildrenMutation, Node, document_from_node, window_from_node};
|
|||
use dom::stylesheet::StyleSheet as DOMStyleSheet;
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
use html5ever_atoms::LocalName;
|
||||
use net_traits::ReferrerPolicy;
|
||||
use script_layout_interface::message::Msg;
|
||||
use std::cell::Cell;
|
||||
use std::sync::Arc;
|
||||
use style::media_queries::parse_media_query_list;
|
||||
use style::parser::ParserContextExtraData;
|
||||
use style::stylesheets::{Stylesheet, Origin};
|
||||
use stylesheet_loader::StylesheetLoader;
|
||||
use stylesheet_loader::{StylesheetLoader, StylesheetOwner};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct HTMLStyleElement {
|
||||
|
@ -64,28 +65,6 @@ impl HTMLStyleElement {
|
|||
HTMLStyleElementBinding::Wrap)
|
||||
}
|
||||
|
||||
pub fn increment_pending_loads_count(&self) {
|
||||
self.pending_loads.set(self.pending_loads.get() + 1)
|
||||
}
|
||||
|
||||
/// Returns None if there are still pending loads, or whether any load has
|
||||
/// failed since the loads started.
|
||||
pub fn load_finished(&self, succeeded: bool) -> Option<bool> {
|
||||
assert!(self.pending_loads.get() > 0, "What finished?");
|
||||
if !succeeded {
|
||||
self.any_failed_load.set(true);
|
||||
}
|
||||
|
||||
self.pending_loads.set(self.pending_loads.get() - 1);
|
||||
if self.pending_loads.get() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let any_failed = self.any_failed_load.get();
|
||||
self.any_failed_load.set(false);
|
||||
Some(any_failed)
|
||||
}
|
||||
|
||||
pub fn parse_own_css(&self) {
|
||||
let node = self.upcast::<Node>();
|
||||
let element = self.upcast::<Element>();
|
||||
|
@ -137,10 +116,6 @@ impl HTMLStyleElement {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parser_inserted(&self) -> bool {
|
||||
self.parser_inserted.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualMethods for HTMLStyleElement {
|
||||
|
@ -168,6 +143,37 @@ impl VirtualMethods for HTMLStyleElement {
|
|||
}
|
||||
}
|
||||
|
||||
impl StylesheetOwner for HTMLStyleElement {
|
||||
fn increment_pending_loads_count(&self) {
|
||||
self.pending_loads.set(self.pending_loads.get() + 1)
|
||||
}
|
||||
|
||||
fn load_finished(&self, succeeded: bool) -> Option<bool> {
|
||||
assert!(self.pending_loads.get() > 0, "What finished?");
|
||||
if !succeeded {
|
||||
self.any_failed_load.set(true);
|
||||
}
|
||||
|
||||
self.pending_loads.set(self.pending_loads.get() - 1);
|
||||
if self.pending_loads.get() != 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let any_failed = self.any_failed_load.get();
|
||||
self.any_failed_load.set(false);
|
||||
Some(any_failed)
|
||||
}
|
||||
|
||||
fn parser_inserted(&self) -> bool {
|
||||
self.parser_inserted.get()
|
||||
}
|
||||
|
||||
fn referrer_policy(&self) -> Option<ReferrerPolicy> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl HTMLStyleElementMethods for HTMLStyleElement {
|
||||
// https://drafts.csswg.org/cssom/#dom-linkstyle-sheet
|
||||
fn GetSheet(&self) -> Option<Root<DOMStyleSheet>> {
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use document_loader::LoadType;
|
||||
use dom::bindings::codegen::Bindings::DOMTokenListBinding::DOMTokenListBinding::DOMTokenListMethods;
|
||||
use dom::bindings::codegen::Bindings::HTMLLinkElementBinding::HTMLLinkElementBinding::HTMLLinkElementMethods;
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::refcounted::Trusted;
|
||||
use dom::bindings::reflector::DomObject;
|
||||
use dom::element::Element;
|
||||
use dom::eventtarget::EventTarget;
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::htmllinkelement::HTMLLinkElement;
|
||||
use dom::htmlstyleelement::HTMLStyleElement;
|
||||
use dom::node::{document_from_node, window_from_node};
|
||||
use encoding::EncodingRef;
|
||||
use encoding::all::UTF_8;
|
||||
|
@ -33,6 +31,23 @@ use style::parser::ParserContextExtraData;
|
|||
use style::stylesheets::{ImportRule, Stylesheet, Origin};
|
||||
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
|
||||
|
||||
pub trait StylesheetOwner {
|
||||
/// Returns whether this element was inserted by the parser (i.e., it should
|
||||
/// trigger a document-load-blocking load).
|
||||
fn parser_inserted(&self) -> bool;
|
||||
|
||||
/// Which referrer policy should loads triggered by this owner follow, or
|
||||
/// `None` for the default.
|
||||
fn referrer_policy(&self) -> Option<ReferrerPolicy>;
|
||||
|
||||
/// Notes that a new load is pending to finish.
|
||||
fn increment_pending_loads_count(&self);
|
||||
|
||||
/// Returns None if there are still pending loads, or whether any load has
|
||||
/// failed since the loads started.
|
||||
fn load_finished(&self, successful: bool) -> Option<bool>;
|
||||
}
|
||||
|
||||
pub enum StylesheetContextSource {
|
||||
// NB: `media` is just an option so we avoid cloning it.
|
||||
LinkElement { media: Option<MediaList>, url: ServoUrl },
|
||||
|
@ -146,35 +161,18 @@ impl FetchResponseListener for StylesheetContext {
|
|||
successful = metadata.status.map_or(false, |(code, _)| code == 200);
|
||||
}
|
||||
|
||||
if let Some(ref link) = elem.downcast::<HTMLLinkElement>() {
|
||||
if link.parser_inserted() {
|
||||
let owner = elem.upcast::<Element>().as_stylesheet_owner()
|
||||
.expect("Stylesheet not loaded by <style> or <link> element!");
|
||||
if owner.parser_inserted() {
|
||||
document.decrement_script_blocking_stylesheet_count();
|
||||
}
|
||||
} else if let Some(ref style) = elem.downcast::<HTMLStyleElement>() {
|
||||
if style.parser_inserted() {
|
||||
document.decrement_script_blocking_stylesheet_count();
|
||||
}
|
||||
} else {
|
||||
unreachable!(
|
||||
"Stylesheet loads can only be triggered by <link> or <style> elements!");
|
||||
}
|
||||
|
||||
let url = self.source.url();
|
||||
document.finish_load(LoadType::Stylesheet(url));
|
||||
|
||||
if let Some(ref link) = elem.downcast::<HTMLLinkElement>() {
|
||||
if let Some(any_failed) = link.load_finished(successful) {
|
||||
if let Some(any_failed) = owner.load_finished(successful) {
|
||||
let event = if any_failed { atom!("error") } else { atom!("load") };
|
||||
link.upcast::<EventTarget>().fire_event(event);
|
||||
}
|
||||
} else if let Some(ref style) = elem.downcast::<HTMLStyleElement>() {
|
||||
if let Some(any_failed) = style.load_finished(successful) {
|
||||
let event = if any_failed { atom!("error") } else { atom!("load") };
|
||||
style.upcast::<EventTarget>().fire_event(event);
|
||||
}
|
||||
} else {
|
||||
unreachable!(
|
||||
"Stylesheet loads can only be triggered by <link> or <style> elements!");
|
||||
elem.upcast::<EventTarget>().fire_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,21 +212,14 @@ impl<'a> StylesheetLoader<'a> {
|
|||
});
|
||||
|
||||
|
||||
let mut referrer_policy = document.get_referrer_policy();
|
||||
if let Some(ref link) = self.elem.downcast::<HTMLLinkElement>() {
|
||||
link.increment_pending_loads_count();
|
||||
if link.parser_inserted() {
|
||||
let owner = self.elem.upcast::<Element>().as_stylesheet_owner()
|
||||
.expect("Stylesheet not loaded by <style> or <link> element!");
|
||||
let referrer_policy = owner.referrer_policy()
|
||||
.or_else(|| document.get_referrer_policy());
|
||||
owner.increment_pending_loads_count();
|
||||
if owner.parser_inserted() {
|
||||
document.increment_script_blocking_stylesheet_count();
|
||||
}
|
||||
if link.RelList().Contains("noreferrer".into()) {
|
||||
referrer_policy = Some(ReferrerPolicy::NoReferrer);
|
||||
}
|
||||
} else if let Some(ref style) = self.elem.downcast::<HTMLStyleElement>() {
|
||||
style.increment_pending_loads_count();
|
||||
if style.parser_inserted() {
|
||||
document.increment_script_blocking_stylesheet_count();
|
||||
}
|
||||
}
|
||||
|
||||
let request = RequestInit {
|
||||
url: url.clone(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue