mirror of
https://github.com/servo/servo.git
synced 2025-08-26 23:58:20 +01:00
Auto merge of #10934 - emilio:other-gecko-pseudos, r=bholley,mbrubeck
style: Add infrastructure to support lazy pseudo-elements This builds on top of #10815, so it's really just the last commit the one that should be reviewed. I tried to apply the new infrastructure to servo, but failed (for now?). The problem with it is that it'd require `ThreadSafeLayoutElement` to implement `selectors::Element`, which is a lot of work and might be racy (not totally sure about it though). Thus, I prefered to keep selectors eager until knowing that it's safe to do it. r? @mbrubeck for style changes, @bholley for the geckolib changes (minimal for now, glue + a list of lazy PEs must be added) <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10934) <!-- Reviewable:end -->
This commit is contained in:
commit
29823cb378
13 changed files with 635 additions and 171 deletions
|
@ -78,11 +78,11 @@ extern "C" {
|
|||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_PrependStyleSheet(sheet: *mut RawServoStyleSheet,
|
||||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_RemoveStyleSheet(sheet: *mut RawServoStyleSheet,
|
||||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_InsertStyleSheetBefore(sheet: *mut RawServoStyleSheet,
|
||||
reference: *mut RawServoStyleSheet,
|
||||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_RemoveStyleSheet(sheet: *mut RawServoStyleSheet,
|
||||
set: *mut RawServoStyleSet);
|
||||
pub fn Servo_StyleSheetHasRules(sheet: *mut RawServoStyleSheet) -> bool;
|
||||
pub fn Servo_InitStyleSet() -> *mut RawServoStyleSet;
|
||||
pub fn Servo_DropStyleSet(set: *mut RawServoStyleSet);
|
||||
|
@ -93,6 +93,14 @@ extern "C" {
|
|||
pseudoTag: *mut nsIAtom,
|
||||
set: *mut RawServoStyleSet)
|
||||
-> *mut ServoComputedValues;
|
||||
pub fn Servo_GetComputedValuesForPseudoElement(parent_style:
|
||||
*mut ServoComputedValues,
|
||||
match_element:
|
||||
*mut RawGeckoElement,
|
||||
pseudo_tag: *mut nsIAtom,
|
||||
set: *mut RawServoStyleSet,
|
||||
is_probe: bool)
|
||||
-> *mut ServoComputedValues;
|
||||
pub fn Servo_AddRefComputedValues(arg1: *mut ServoComputedValues);
|
||||
pub fn Servo_ReleaseComputedValues(arg1: *mut ServoComputedValues);
|
||||
pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, ns: *const u8,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#![allow(unsafe_code)]
|
||||
|
||||
use app_units::Au;
|
||||
use bindings::{RawGeckoDocument, RawGeckoNode};
|
||||
use bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
|
||||
use bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComputedValues, ServoNodeData};
|
||||
use bindings::{nsIAtom};
|
||||
use data::PerDocumentStyleData;
|
||||
|
@ -20,15 +20,16 @@ use std::slice;
|
|||
use std::str::from_utf8_unchecked;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use style::context::{ReflowGoal};
|
||||
use style::dom::{TDocument, TNode};
|
||||
use style::dom::{TDocument, TElement, TNode};
|
||||
use style::error_reporting::StdoutErrorReporter;
|
||||
use style::parallel;
|
||||
use style::properties::ComputedValues;
|
||||
use style::selector_impl::{SelectorImplExt, PseudoElementCascadeType};
|
||||
use style::stylesheets::Origin;
|
||||
use traversal::RecalcStyleOnly;
|
||||
use url::Url;
|
||||
use util::arc_ptr_eq;
|
||||
use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData};
|
||||
use wrapper::{GeckoDocument, GeckoElement, GeckoNode, NonOpaqueStyleData};
|
||||
|
||||
// TODO: This is ugly and should go away once we get an atom back-end.
|
||||
pub fn pseudo_element_from_atom(pseudo: *mut nsIAtom,
|
||||
|
@ -256,7 +257,7 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: *
|
|||
-> *mut ServoComputedValues {
|
||||
let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data);
|
||||
|
||||
let pseudo = match pseudo_element_from_atom(pseudo_tag, true) {
|
||||
let pseudo = match pseudo_element_from_atom(pseudo_tag, /* ua_stylesheet = */ true) {
|
||||
Ok(pseudo) => pseudo,
|
||||
Err(pseudo) => {
|
||||
warn!("stylo: Unable to parse anonymous-box pseudo-element: {}", pseudo);
|
||||
|
@ -267,11 +268,67 @@ pub extern "C" fn Servo_GetComputedValuesForAnonymousBox(parent_style_or_null: *
|
|||
type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
|
||||
|
||||
Helpers::maybe_with(parent_style_or_null, |maybe_parent| {
|
||||
let new_computed = data.stylist.computed_values_for_pseudo(&pseudo, maybe_parent);
|
||||
let new_computed = data.stylist.precomputed_values_for_pseudo(&pseudo, maybe_parent);
|
||||
new_computed.map_or(ptr::null_mut(), |c| Helpers::from(c))
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_GetComputedValuesForPseudoElement(parent_style: *mut ServoComputedValues,
|
||||
match_element: *mut RawGeckoElement,
|
||||
pseudo_tag: *mut nsIAtom,
|
||||
raw_data: *mut RawServoStyleSet,
|
||||
is_probe: bool)
|
||||
-> *mut ServoComputedValues {
|
||||
debug_assert!(!match_element.is_null());
|
||||
|
||||
let parent_or_null = || {
|
||||
if is_probe {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
Servo_AddRefComputedValues(parent_style);
|
||||
parent_style
|
||||
}
|
||||
};
|
||||
|
||||
let pseudo = match pseudo_element_from_atom(pseudo_tag, /* ua_stylesheet = */ true) {
|
||||
Ok(pseudo) => pseudo,
|
||||
Err(pseudo) => {
|
||||
warn!("stylo: Unable to parse anonymous-box pseudo-element: {}", pseudo);
|
||||
return parent_or_null();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let data = PerDocumentStyleData::borrow_mut_from_raw(raw_data);
|
||||
|
||||
let element = unsafe { GeckoElement::from_raw(match_element) };
|
||||
|
||||
type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
|
||||
|
||||
match GeckoSelectorImpl::pseudo_element_cascade_type(&pseudo) {
|
||||
PseudoElementCascadeType::Eager => {
|
||||
let node = element.as_node();
|
||||
let maybe_computed = node.borrow_data()
|
||||
.and_then(|data| {
|
||||
data.per_pseudo.get(&pseudo).map(|c| c.clone())
|
||||
});
|
||||
maybe_computed.map_or_else(parent_or_null, Helpers::from)
|
||||
}
|
||||
PseudoElementCascadeType::Lazy => {
|
||||
Helpers::with(parent_style, |parent| {
|
||||
data.stylist
|
||||
.lazily_compute_pseudo_element_style(&element, &pseudo, parent)
|
||||
.map_or_else(parent_or_null, Helpers::from)
|
||||
})
|
||||
}
|
||||
PseudoElementCascadeType::Precomputed => {
|
||||
unreachable!("Anonymous pseudo found in \
|
||||
Servo_GetComputedValuesForPseudoElement");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Servo_AddRefComputedValues(ptr: *mut ServoComputedValues) -> () {
|
||||
type Helpers = ArcHelpers<ServoComputedValues, GeckoComputedValues>;
|
||||
|
|
|
@ -6,7 +6,7 @@ use properties::GeckoComputedValues;
|
|||
use selectors::parser::{ParserContext, SelectorImpl};
|
||||
use style;
|
||||
use style::element_state::ElementState;
|
||||
use style::selector_impl::SelectorImplExt;
|
||||
use style::selector_impl::{PseudoElementCascadeType, SelectorImplExt};
|
||||
|
||||
pub type Stylist = style::selector_matching::Stylist<GeckoSelectorImpl>;
|
||||
pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>;
|
||||
|
@ -22,7 +22,12 @@ pub enum PseudoElement {
|
|||
FirstLine,
|
||||
// TODO: Probably a few more are missing here
|
||||
|
||||
// https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
|
||||
AnonBox(AnonBoxPseudoElement),
|
||||
}
|
||||
|
||||
// https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
|
||||
#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
|
||||
pub enum AnonBoxPseudoElement {
|
||||
MozNonElement,
|
||||
MozAnonymousBlock,
|
||||
MozAnonymousPositionedBlock,
|
||||
|
@ -153,6 +158,7 @@ impl SelectorImpl for GeckoSelectorImpl {
|
|||
|
||||
fn parse_pseudo_element(context: &ParserContext,
|
||||
name: &str) -> Result<PseudoElement, ()> {
|
||||
use self::AnonBoxPseudoElement::*;
|
||||
use self::PseudoElement::*;
|
||||
|
||||
// The braces here are unfortunate, but they're needed for
|
||||
|
@ -168,7 +174,7 @@ impl SelectorImpl for GeckoSelectorImpl {
|
|||
return Err(())
|
||||
}
|
||||
|
||||
Ok(match_ignore_ascii_case! { name,
|
||||
Ok(AnonBox(match_ignore_ascii_case! { name,
|
||||
"-moz-non-element" => MozNonElement,
|
||||
|
||||
"-moz-anonymous-block" => MozAnonymousBlock,
|
||||
|
@ -235,7 +241,7 @@ impl SelectorImpl for GeckoSelectorImpl {
|
|||
"-moz-svg-text" => MozSVGText,
|
||||
|
||||
_ => return Err(())
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,86 +249,89 @@ impl SelectorImplExt for GeckoSelectorImpl {
|
|||
type ComputedValues = GeckoComputedValues;
|
||||
|
||||
#[inline]
|
||||
fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
|
||||
fn pseudo_element_cascade_type(pseudo: &PseudoElement) -> PseudoElementCascadeType {
|
||||
match *pseudo {
|
||||
PseudoElement::Before |
|
||||
PseudoElement::After |
|
||||
PseudoElement::FirstLine => true,
|
||||
_ => false,
|
||||
PseudoElement::After => PseudoElementCascadeType::Eager,
|
||||
PseudoElement::AnonBox(_) => PseudoElementCascadeType::Precomputed,
|
||||
_ => PseudoElementCascadeType::Lazy,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn each_pseudo_element<F>(mut fun: F)
|
||||
where F: FnMut(PseudoElement) {
|
||||
fun(PseudoElement::Before);
|
||||
fun(PseudoElement::After);
|
||||
fun(PseudoElement::FirstLine);
|
||||
use self::AnonBoxPseudoElement::*;
|
||||
use self::PseudoElement::*;
|
||||
|
||||
fun(PseudoElement::MozNonElement);
|
||||
fun(PseudoElement::MozAnonymousBlock);
|
||||
fun(PseudoElement::MozAnonymousPositionedBlock);
|
||||
fun(PseudoElement::MozMathMLAnonymousBlock);
|
||||
fun(PseudoElement::MozXULAnonymousBlock);
|
||||
fun(Before);
|
||||
fun(After);
|
||||
fun(FirstLine);
|
||||
|
||||
fun(PseudoElement::MozHorizontalFramesetBorder);
|
||||
fun(PseudoElement::MozVerticalFramesetBorder);
|
||||
fun(PseudoElement::MozLineFrame);
|
||||
fun(PseudoElement::MozButtonContent);
|
||||
fun(PseudoElement::MozButtonLabel);
|
||||
fun(PseudoElement::MozCellContent);
|
||||
fun(PseudoElement::MozDropdownList);
|
||||
fun(PseudoElement::MozFieldsetContent);
|
||||
fun(PseudoElement::MozFramesetBlank);
|
||||
fun(PseudoElement::MozDisplayComboboxControlFrame);
|
||||
fun(AnonBox(MozNonElement));
|
||||
fun(AnonBox(MozAnonymousBlock));
|
||||
fun(AnonBox(MozAnonymousPositionedBlock));
|
||||
fun(AnonBox(MozMathMLAnonymousBlock));
|
||||
fun(AnonBox(MozXULAnonymousBlock));
|
||||
|
||||
fun(PseudoElement::MozHTMLCanvasContent);
|
||||
fun(PseudoElement::MozInlineTable);
|
||||
fun(PseudoElement::MozTable);
|
||||
fun(PseudoElement::MozTableCell);
|
||||
fun(PseudoElement::MozTableColumnGroup);
|
||||
fun(PseudoElement::MozTableColumn);
|
||||
fun(PseudoElement::MozTableOuter);
|
||||
fun(PseudoElement::MozTableRowGroup);
|
||||
fun(PseudoElement::MozTableRow);
|
||||
fun(AnonBox(MozHorizontalFramesetBorder));
|
||||
fun(AnonBox(MozVerticalFramesetBorder));
|
||||
fun(AnonBox(MozLineFrame));
|
||||
fun(AnonBox(MozButtonContent));
|
||||
fun(AnonBox(MozButtonLabel));
|
||||
fun(AnonBox(MozCellContent));
|
||||
fun(AnonBox(MozDropdownList));
|
||||
fun(AnonBox(MozFieldsetContent));
|
||||
fun(AnonBox(MozFramesetBlank));
|
||||
fun(AnonBox(MozDisplayComboboxControlFrame));
|
||||
|
||||
fun(PseudoElement::MozCanvas);
|
||||
fun(PseudoElement::MozPageBreak);
|
||||
fun(PseudoElement::MozPage);
|
||||
fun(PseudoElement::MozPageContent);
|
||||
fun(PseudoElement::MozPageSequence);
|
||||
fun(PseudoElement::MozScrolledContent);
|
||||
fun(PseudoElement::MozScrolledCanvas);
|
||||
fun(PseudoElement::MozScrolledPageSequence);
|
||||
fun(PseudoElement::MozColumnContent);
|
||||
fun(PseudoElement::MozViewport);
|
||||
fun(PseudoElement::MozViewportScroll);
|
||||
fun(PseudoElement::MozAnonymousFlexItem);
|
||||
fun(PseudoElement::MozAnonymousGridItem);
|
||||
fun(AnonBox(MozHTMLCanvasContent));
|
||||
fun(AnonBox(MozInlineTable));
|
||||
fun(AnonBox(MozTable));
|
||||
fun(AnonBox(MozTableCell));
|
||||
fun(AnonBox(MozTableColumnGroup));
|
||||
fun(AnonBox(MozTableColumn));
|
||||
fun(AnonBox(MozTableOuter));
|
||||
fun(AnonBox(MozTableRowGroup));
|
||||
fun(AnonBox(MozTableRow));
|
||||
|
||||
fun(PseudoElement::MozRuby);
|
||||
fun(PseudoElement::MozRubyBase);
|
||||
fun(PseudoElement::MozRubyBaseContainer);
|
||||
fun(PseudoElement::MozRubyText);
|
||||
fun(PseudoElement::MozRubyTextContainer);
|
||||
fun(AnonBox(MozCanvas));
|
||||
fun(AnonBox(MozPageBreak));
|
||||
fun(AnonBox(MozPage));
|
||||
fun(AnonBox(MozPageContent));
|
||||
fun(AnonBox(MozPageSequence));
|
||||
fun(AnonBox(MozScrolledContent));
|
||||
fun(AnonBox(MozScrolledCanvas));
|
||||
fun(AnonBox(MozScrolledPageSequence));
|
||||
fun(AnonBox(MozColumnContent));
|
||||
fun(AnonBox(MozViewport));
|
||||
fun(AnonBox(MozViewportScroll));
|
||||
fun(AnonBox(MozAnonymousFlexItem));
|
||||
fun(AnonBox(MozAnonymousGridItem));
|
||||
|
||||
fun(PseudoElement::MozTreeColumn);
|
||||
fun(PseudoElement::MozTreeRow);
|
||||
fun(PseudoElement::MozTreeSeparator);
|
||||
fun(PseudoElement::MozTreeCell);
|
||||
fun(PseudoElement::MozTreeIndentation);
|
||||
fun(PseudoElement::MozTreeLine);
|
||||
fun(PseudoElement::MozTreeTwisty);
|
||||
fun(PseudoElement::MozTreeImage);
|
||||
fun(PseudoElement::MozTreeCellText);
|
||||
fun(PseudoElement::MozTreeCheckbox);
|
||||
fun(PseudoElement::MozTreeProgressMeter);
|
||||
fun(PseudoElement::MozTreeDropFeedback);
|
||||
fun(AnonBox(MozRuby));
|
||||
fun(AnonBox(MozRubyBase));
|
||||
fun(AnonBox(MozRubyBaseContainer));
|
||||
fun(AnonBox(MozRubyText));
|
||||
fun(AnonBox(MozRubyTextContainer));
|
||||
|
||||
fun(PseudoElement::MozSVGMarkerAnonChild);
|
||||
fun(PseudoElement::MozSVGOuterSVGAnonChild);
|
||||
fun(PseudoElement::MozSVGForeignContent);
|
||||
fun(PseudoElement::MozSVGText);
|
||||
fun(AnonBox(MozTreeColumn));
|
||||
fun(AnonBox(MozTreeRow));
|
||||
fun(AnonBox(MozTreeSeparator));
|
||||
fun(AnonBox(MozTreeCell));
|
||||
fun(AnonBox(MozTreeIndentation));
|
||||
fun(AnonBox(MozTreeLine));
|
||||
fun(AnonBox(MozTreeTwisty));
|
||||
fun(AnonBox(MozTreeImage));
|
||||
fun(AnonBox(MozTreeCellText));
|
||||
fun(AnonBox(MozTreeCheckbox));
|
||||
fun(AnonBox(MozTreeProgressMeter));
|
||||
fun(AnonBox(MozTreeDropFeedback));
|
||||
|
||||
fun(AnonBox(MozSVGMarkerAnonChild));
|
||||
fun(AnonBox(MozSVGOuterSVGAnonChild));
|
||||
fun(AnonBox(MozSVGForeignContent));
|
||||
fun(AnonBox(MozSVGText));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -32,7 +32,8 @@ use std::slice;
|
|||
use std::str::from_utf8_unchecked;
|
||||
use std::sync::Arc;
|
||||
use string_cache::{Atom, Namespace};
|
||||
use style::dom::{OpaqueNode, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
|
||||
use style::dom::{OpaqueNode, PresentationalHintsSynthetizer};
|
||||
use style::dom::{TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
|
||||
use style::element_state::ElementState;
|
||||
#[allow(unused_imports)] // Used in commented-out code.
|
||||
use style::error_reporting::StdoutErrorReporter;
|
||||
|
@ -339,12 +340,6 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
}
|
||||
}
|
||||
|
||||
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
|
||||
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
|
||||
{
|
||||
// FIXME(bholley) - Need to implement this.
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> {
|
||||
unsafe {
|
||||
|
@ -360,6 +355,14 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'le> PresentationalHintsSynthetizer for GeckoElement<'le> {
|
||||
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V)
|
||||
where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>
|
||||
{
|
||||
// FIXME(bholley) - Need to implement this.
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||
type Impl = GeckoSelectorImpl;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue