mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Auto merge of #19024 - emilio:document, r=KiChjang
Introduce style::dom::TDocument. The secret plan is introducing a `get_elements_with_id` for use by `querySelector` / `querySelectorAll`. But this allows also to make some code look a bit nicer. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/19024) <!-- Reviewable:end -->
This commit is contained in:
commit
ee4e371c73
6 changed files with 117 additions and 47 deletions
|
@ -51,7 +51,7 @@ use script_layout_interface::{OpaqueStyleAndLayoutData, StyleData};
|
|||
use script_layout_interface::wrapper_traits::{DangerousThreadSafeLayoutNode, GetLayoutData, LayoutNode};
|
||||
use script_layout_interface::wrapper_traits::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
|
||||
use selectors::attr::{AttrSelectorOperation, NamespaceConstraint, CaseSensitivity};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, RelevantLinkStatus};
|
||||
use selectors::matching::{ElementSelectorFlags, MatchingContext, QuirksMode, RelevantLinkStatus};
|
||||
use selectors::matching::VisitedHandlingMode;
|
||||
use selectors::sink::Push;
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
|
@ -69,7 +69,7 @@ use style::computed_values::display;
|
|||
use style::context::SharedStyleContext;
|
||||
use style::data::ElementData;
|
||||
use style::dom::{DomChildren, LayoutIterator, NodeInfo, OpaqueNode};
|
||||
use style::dom::{TElement, TNode};
|
||||
use style::dom::{TDocument, TElement, TNode};
|
||||
use style::element_state::*;
|
||||
use style::font_metrics::ServoMetricsProvider;
|
||||
use style::properties::{ComputedValues, PropertyDeclarationBlock};
|
||||
|
@ -139,10 +139,6 @@ impl<'ln> ServoLayoutNode<'ln> {
|
|||
self.node.type_id_for_layout()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
|
||||
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
|
||||
|
@ -158,6 +154,7 @@ impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
|
|||
}
|
||||
|
||||
impl<'ln> TNode for ServoLayoutNode<'ln> {
|
||||
type ConcreteDocument = ServoLayoutDocument<'ln>;
|
||||
type ConcreteElement = ServoLayoutElement<'ln>;
|
||||
|
||||
fn parent_node(&self) -> Option<Self> {
|
||||
|
@ -190,6 +187,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
|||
}
|
||||
}
|
||||
|
||||
fn owner_doc(&self) -> Self::ConcreteDocument {
|
||||
ServoLayoutDocument::from_layout_js(unsafe { self.node.owner_doc_for_layout() })
|
||||
}
|
||||
|
||||
fn traversal_parent(&self) -> Option<ServoLayoutElement<'ln>> {
|
||||
self.parent_element()
|
||||
}
|
||||
|
@ -206,6 +207,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> {
|
|||
as_element(self.node)
|
||||
}
|
||||
|
||||
fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
|
||||
self.node.downcast().map(ServoLayoutDocument::from_layout_js)
|
||||
}
|
||||
|
||||
fn can_be_fragmented(&self) -> bool {
|
||||
unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) }
|
||||
}
|
||||
|
@ -287,11 +292,23 @@ pub struct ServoLayoutDocument<'ld> {
|
|||
chain: PhantomData<&'ld ()>,
|
||||
}
|
||||
|
||||
impl<'ld> ServoLayoutDocument<'ld> {
|
||||
fn as_node(&self) -> ServoLayoutNode<'ld> {
|
||||
impl<'ld> TDocument for ServoLayoutDocument<'ld> {
|
||||
type ConcreteNode = ServoLayoutNode<'ld>;
|
||||
|
||||
fn as_node(&self) -> Self::ConcreteNode {
|
||||
ServoLayoutNode::from_layout_js(self.document.upcast())
|
||||
}
|
||||
|
||||
fn quirks_mode(&self) -> QuirksMode {
|
||||
unsafe { self.document.quirks_mode() }
|
||||
}
|
||||
|
||||
fn is_html_document(&self) -> bool {
|
||||
unsafe { self.document.is_html_document_for_layout() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ld> ServoLayoutDocument<'ld> {
|
||||
pub fn root_element(&self) -> Option<ServoLayoutElement<'ld>> {
|
||||
self.as_node().dom_children().flat_map(|n| n.as_element()).next()
|
||||
}
|
||||
|
@ -773,8 +790,12 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
|||
|
||||
fn is_html_element_in_html_document(&self) -> bool {
|
||||
unsafe {
|
||||
self.element.html_element_in_html_document_for_layout()
|
||||
if !self.element.is_html_element() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self.as_node().owner_doc().is_html_document()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -446,7 +446,7 @@ pub trait LayoutElementHelpers {
|
|||
#[allow(unsafe_code)]
|
||||
unsafe fn get_rowspan(self) -> u32;
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn html_element_in_html_document_for_layout(&self) -> bool;
|
||||
unsafe fn is_html_element(&self) -> bool;
|
||||
fn id_attribute(&self) -> *const Option<Atom>;
|
||||
fn style_attribute(&self) -> *const Option<Arc<Locked<PropertyDeclarationBlock>>>;
|
||||
fn local_name(&self) -> &LocalName;
|
||||
|
@ -781,11 +781,8 @@ impl LayoutElementHelpers for LayoutDom<Element> {
|
|||
|
||||
#[inline]
|
||||
#[allow(unsafe_code)]
|
||||
unsafe fn html_element_in_html_document_for_layout(&self) -> bool {
|
||||
if (*self.unsafe_get()).namespace != ns!(html) {
|
||||
return false;
|
||||
}
|
||||
self.upcast::<Node>().owner_doc_for_layout().is_html_document_for_layout()
|
||||
unsafe fn is_html_element(&self) -> bool {
|
||||
(*self.unsafe_get()).namespace == ns!(html)
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -22,7 +22,7 @@ use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock};
|
|||
use rule_tree::CascadeLevel;
|
||||
use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl};
|
||||
use selectors::Element as SelectorsElement;
|
||||
use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode};
|
||||
use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode};
|
||||
use selectors::sink::Push;
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
use shared_lock::Locked;
|
||||
|
@ -133,12 +133,30 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// The `TDocument` trait, to represent a document node.
|
||||
pub trait TDocument : Sized + Copy + Clone {
|
||||
/// The concrete `TNode` type.
|
||||
type ConcreteNode: TNode<ConcreteDocument = Self>;
|
||||
|
||||
/// Get this document as a `TNode`.
|
||||
fn as_node(&self) -> Self::ConcreteNode;
|
||||
|
||||
/// Returns whether this document is an HTML document.
|
||||
fn is_html_document(&self) -> bool;
|
||||
|
||||
/// Returns the quirks mode of this document.
|
||||
fn quirks_mode(&self) -> QuirksMode;
|
||||
}
|
||||
|
||||
/// The `TNode` trait. This is the main generic trait over which the style
|
||||
/// system can be implemented.
|
||||
pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
|
||||
/// The concrete `TElement` type.
|
||||
type ConcreteElement: TElement<ConcreteNode = Self>;
|
||||
|
||||
/// The concrete `TDocument` type.
|
||||
type ConcreteDocument: TDocument<ConcreteNode = Self>;
|
||||
|
||||
/// Get this node's parent node.
|
||||
fn parent_node(&self) -> Option<Self>;
|
||||
|
||||
|
@ -154,6 +172,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
|
|||
/// Get this node's next sibling.
|
||||
fn next_sibling(&self) -> Option<Self>;
|
||||
|
||||
/// Get the owner document of this node.
|
||||
fn owner_doc(&self) -> Self::ConcreteDocument;
|
||||
|
||||
/// Iterate over the DOM children of a node.
|
||||
fn dom_children(&self) -> DomChildren<Self> {
|
||||
DomChildren(self.first_child())
|
||||
|
@ -211,6 +232,9 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo + PartialEq {
|
|||
/// Get this node as an element, if it's one.
|
||||
fn as_element(&self) -> Option<Self::ConcreteElement>;
|
||||
|
||||
/// Get this node as a document, if it's one.
|
||||
fn as_document(&self) -> Option<Self::ConcreteDocument>;
|
||||
|
||||
/// Whether this node can be fragmented. This is used for multicol, and only
|
||||
/// for Servo.
|
||||
fn can_be_fragmented(&self) -> bool;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! and Gecko.
|
||||
|
||||
use context::QuirksMode;
|
||||
use dom::{TElement, TNode};
|
||||
use dom::{TDocument, TElement, TNode};
|
||||
use invalidation::element::invalidator::{Invalidation, InvalidationProcessor, InvalidationVector};
|
||||
use selectors::{Element, NthIndexCache, SelectorList};
|
||||
use selectors::matching::{self, MatchingContext, MatchingMode};
|
||||
|
@ -308,7 +308,6 @@ pub fn query_selector<E, Q>(
|
|||
root: E::ConcreteNode,
|
||||
selector_list: &SelectorList<E::Impl>,
|
||||
results: &mut Q::Output,
|
||||
quirks_mode: QuirksMode,
|
||||
)
|
||||
where
|
||||
E: TElement,
|
||||
|
@ -316,6 +315,7 @@ where
|
|||
{
|
||||
use invalidation::element::invalidator::TreeStyleInvalidator;
|
||||
|
||||
let quirks_mode = root.owner_doc().quirks_mode();
|
||||
let fast_result = query_selector_fast::<E, Q>(
|
||||
root,
|
||||
selector_list,
|
||||
|
|
|
@ -20,7 +20,7 @@ use applicable_declarations::ApplicableDeclarationBlock;
|
|||
use atomic_refcell::{AtomicRefCell, AtomicRef, AtomicRefMut};
|
||||
use context::{QuirksMode, SharedStyleContext, PostAnimationTasks, UpdateAnimationsTasks};
|
||||
use data::ElementData;
|
||||
use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TNode};
|
||||
use dom::{LayoutIterator, NodeInfo, OpaqueNode, TElement, TDocument, TNode};
|
||||
use element_state::{ElementState, DocumentState, NS_DOCUMENT_STATE_WINDOW_INACTIVE};
|
||||
use error_reporting::ParseErrorReporter;
|
||||
use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult};
|
||||
|
@ -92,6 +92,26 @@ use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
|
|||
use stylesheets::UrlExtraData;
|
||||
use stylist::Stylist;
|
||||
|
||||
/// A simple wrapper over `nsIDocument`.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GeckoDocument<'ld>(pub &'ld structs::nsIDocument);
|
||||
|
||||
impl<'ld> TDocument for GeckoDocument<'ld> {
|
||||
type ConcreteNode = GeckoNode<'ld>;
|
||||
|
||||
fn as_node(&self) -> Self::ConcreteNode {
|
||||
GeckoNode(&self.0._base)
|
||||
}
|
||||
|
||||
fn is_html_document(&self) -> bool {
|
||||
self.0.mType == structs::root::nsIDocument_Type::eHTML
|
||||
}
|
||||
|
||||
fn quirks_mode(&self) -> QuirksMode {
|
||||
self.0.mCompatMode.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple wrapper over a non-null Gecko node (`nsINode`) pointer.
|
||||
///
|
||||
/// Important: We don't currently refcount the DOM, because the wrapper lifetime
|
||||
|
@ -124,6 +144,13 @@ impl<'ln> fmt::Debug for GeckoNode<'ln> {
|
|||
}
|
||||
|
||||
impl<'ln> GeckoNode<'ln> {
|
||||
#[inline]
|
||||
fn is_document(&self) -> bool {
|
||||
// This is a DOM constant that isn't going to change.
|
||||
const DOCUMENT_NODE: u16 = 9;
|
||||
self.node_info().mInner.mNodeType == DOCUMENT_NODE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_content(content: &'ln nsIContent) -> Self {
|
||||
GeckoNode(&content._base)
|
||||
|
@ -153,22 +180,11 @@ impl<'ln> GeckoNode<'ln> {
|
|||
(self.0).mBoolFlags
|
||||
}
|
||||
|
||||
/// Owner document quirks mode getter.
|
||||
#[inline]
|
||||
pub fn owner_document_quirks_mode(&self) -> QuirksMode {
|
||||
self.owner_doc().mCompatMode.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_bool_flag(&self, flag: nsINode_BooleanFlag) -> bool {
|
||||
self.bool_flags() & (1u32 << flag as u32) != 0
|
||||
}
|
||||
|
||||
fn owner_doc(&self) -> &structs::nsIDocument {
|
||||
debug_assert!(!self.node_info().mDocument.is_null());
|
||||
unsafe { &*self.node_info().mDocument }
|
||||
}
|
||||
|
||||
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
|
||||
/// Make sure to mirror any modifications in both places.
|
||||
fn flattened_tree_parent_is_parent(&self) -> bool {
|
||||
|
@ -223,6 +239,7 @@ impl<'ln> NodeInfo for GeckoNode<'ln> {
|
|||
}
|
||||
|
||||
impl<'ln> TNode for GeckoNode<'ln> {
|
||||
type ConcreteDocument = GeckoDocument<'ln>;
|
||||
type ConcreteElement = GeckoElement<'ln>;
|
||||
|
||||
fn parent_node(&self) -> Option<Self> {
|
||||
|
@ -249,6 +266,12 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
unsafe { self.0.mNextSibling.as_ref().map(GeckoNode::from_content) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn owner_doc(&self) -> Self::ConcreteDocument {
|
||||
debug_assert!(!self.node_info().mDocument.is_null());
|
||||
GeckoDocument(unsafe { &*self.node_info().mDocument })
|
||||
}
|
||||
|
||||
fn traversal_parent(&self) -> Option<GeckoElement<'ln>> {
|
||||
self.flattened_tree_parent().and_then(|n| n.as_element())
|
||||
}
|
||||
|
@ -271,6 +294,15 @@ impl<'ln> TNode for GeckoNode<'ln> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_document(&self) -> Option<Self::ConcreteDocument> {
|
||||
if self.is_document() {
|
||||
Some(self.owner_doc())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn can_be_fragmented(&self) -> bool {
|
||||
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
|
||||
// Maybe this isn’t useful for Gecko?
|
||||
|
@ -596,7 +628,7 @@ impl<'le> GeckoElement<'le> {
|
|||
fn document_state(&self) -> DocumentState {
|
||||
let node = self.as_node();
|
||||
unsafe {
|
||||
let states = Gecko_DocumentState(node.owner_doc());
|
||||
let states = Gecko_DocumentState(node.owner_doc().0);
|
||||
DocumentState::from_bits_truncate(states)
|
||||
}
|
||||
}
|
||||
|
@ -632,13 +664,7 @@ impl<'le> GeckoElement<'le> {
|
|||
#[inline]
|
||||
fn get_document_theme(&self) -> DocumentTheme {
|
||||
let node = self.as_node();
|
||||
unsafe { Gecko_GetDocumentLWTheme(node.owner_doc()) }
|
||||
}
|
||||
|
||||
/// Owner document quirks mode getter.
|
||||
#[inline]
|
||||
pub fn owner_document_quirks_mode(&self) -> QuirksMode {
|
||||
self.as_node().owner_document_quirks_mode()
|
||||
unsafe { Gecko_GetDocumentLWTheme(node.owner_doc().0) }
|
||||
}
|
||||
|
||||
/// Only safe to call on the main thread, with exclusive access to the element and
|
||||
|
@ -949,7 +975,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
}
|
||||
|
||||
fn owner_doc_matches_for_testing(&self, device: &Device) -> bool {
|
||||
self.as_node().owner_doc() as *const structs::nsIDocument ==
|
||||
self.as_node().owner_doc().0 as *const structs::nsIDocument ==
|
||||
device.pres_context().mDocument.raw::<structs::nsIDocument>()
|
||||
}
|
||||
|
||||
|
@ -1584,7 +1610,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
if self.get_local_name().as_ptr() == atom!("th").as_ptr() {
|
||||
hints.push(TH_RULE.clone());
|
||||
} else if self.get_local_name().as_ptr() == atom!("table").as_ptr() &&
|
||||
self.as_node().owner_doc().mCompatMode == structs::nsCompatibility::eCompatibility_NavQuirks {
|
||||
self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks {
|
||||
hints.push(TABLE_COLOR_RULE.clone());
|
||||
}
|
||||
}
|
||||
|
@ -2031,7 +2057,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
|||
|
||||
fn is_html_element_in_html_document(&self) -> bool {
|
||||
self.is_html_element() &&
|
||||
self.as_node().owner_doc().mType == structs::root::nsIDocument_Type::eHTML
|
||||
self.as_node().owner_doc().is_html_document()
|
||||
}
|
||||
|
||||
fn ignores_nth_child_selectors(&self) -> bool {
|
||||
|
|
|
@ -19,7 +19,7 @@ use style::applicable_declarations::ApplicableDeclarationBlock;
|
|||
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
|
||||
use style::context::ThreadLocalStyleContext;
|
||||
use style::data::{ElementStyles, self};
|
||||
use style::dom::{ShowSubtreeData, TElement, TNode};
|
||||
use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
|
||||
use style::driver;
|
||||
use style::element_state::{DocumentState, ElementState};
|
||||
use style::error_reporting::{NullReporter, ParseErrorReporter};
|
||||
|
@ -1577,7 +1577,9 @@ pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(rule: RawServoStyleRule
|
|||
};
|
||||
|
||||
let element = GeckoElement(element);
|
||||
let mut ctx = MatchingContext::new(matching_mode, None, None, element.owner_document_quirks_mode());
|
||||
let quirks_mode = element.as_node().owner_doc().quirks_mode();
|
||||
let mut ctx =
|
||||
MatchingContext::new(matching_mode, None, None, quirks_mode);
|
||||
matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
|
||||
})
|
||||
}
|
||||
|
@ -1591,9 +1593,10 @@ pub unsafe extern "C" fn Servo_SelectorList_Closest(
|
|||
use style::dom_apis;
|
||||
|
||||
let element = GeckoElement(element);
|
||||
let quirks_mode = element.as_node().owner_doc().quirks_mode();
|
||||
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
|
||||
|
||||
dom_apis::element_closest(element, &selectors, element.owner_document_quirks_mode())
|
||||
dom_apis::element_closest(element, &selectors, quirks_mode)
|
||||
.map_or(ptr::null(), |e| e.0)
|
||||
}
|
||||
|
||||
|
@ -1606,11 +1609,12 @@ pub unsafe extern "C" fn Servo_SelectorList_Matches(
|
|||
use style::dom_apis;
|
||||
|
||||
let element = GeckoElement(element);
|
||||
let quirks_mode = element.as_node().owner_doc().quirks_mode();
|
||||
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
|
||||
dom_apis::element_matches(
|
||||
&element,
|
||||
&selectors,
|
||||
element.owner_document_quirks_mode(),
|
||||
quirks_mode,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1629,7 +1633,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
|
|||
node,
|
||||
&selectors,
|
||||
&mut result,
|
||||
node.owner_document_quirks_mode(),
|
||||
);
|
||||
|
||||
result.map_or(ptr::null(), |e| e.0)
|
||||
|
@ -1653,7 +1656,6 @@ pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
|
|||
node,
|
||||
&selectors,
|
||||
&mut result,
|
||||
node.owner_document_quirks_mode(),
|
||||
);
|
||||
|
||||
if !result.is_empty() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue