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:
bors-servo 2016-05-04 03:42:23 -07:00
commit 29823cb378
13 changed files with 635 additions and 171 deletions

View file

@ -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,

View file

@ -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>;

View file

@ -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]

View file

@ -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;