--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -70,16 +70,17 @@
#include "nsFrameLoader.h"
#include "mozilla/dom/FontFaceSet.h"
#include "nsContentUtils.h"
#include "nsPIWindowRoot.h"
#include "mozilla/Preferences.h"
#include "gfxTextRun.h"
#include "nsFontFaceUtils.h"
#include "nsLayoutStylesheetCache.h"
+#include "mozilla/ServoBindings.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/PerformanceTiming.h"
#include "mozilla/layers/APZThreadUtils.h"
// Needed for Start/Stop of Image Animation
@@ -2207,20 +2208,40 @@ nsPresContext::UpdateIsChrome()
mIsChrome = mContainer &&
nsIDocShellTreeItem::typeChrome == mContainer->ItemType();
}
bool
nsPresContext::HasAuthorSpecifiedRules(const nsIFrame *aFrame,
uint32_t ruleTypeMask) const
{
- return
- nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
- ruleTypeMask,
- UseDocumentColors());
+ if (mShell->StyleSet()->IsGecko()) {
+ return
+ nsRuleNode::HasAuthorSpecifiedRules(aFrame->StyleContext(),
+ ruleTypeMask,
+ UseDocumentColors());
+ } else {
+ Element *elem = aFrame->GetContent()->AsElement();
+ if (elem->IsNativeAnonymous()) {
+ elem = nsContentUtils::GetClosestNonNativeAnonymousAncestor(elem);
+ }
+ if (!elem->HasServoData()) {
+ return false;
+ }
+
+ nsIAtom *pseudoTag = aFrame->StyleContext()->GetPseudo();
+ RefPtr<RawServoRuleNode> ruleNode;
+ ruleNode = mShell->StyleSet()->AsServo()->ResolveRuleNode(elem, pseudoTag);
+ if (!ruleNode) {
+ return false;
+ }
+ return Servo_HasAuthorSpecifiedRules(ruleNode,
+ ruleTypeMask,
+ UseDocumentColors());
+ }
}
gfxUserFontSet*
nsPresContext::GetUserFontSet(bool aFlushUserFontSet)
{
return mDocument->GetUserFontSet(aFlushUserFontSet);
}
--- a/layout/style/ServoArcTypeList.h
+++ b/layout/style/ServoArcTypeList.h
@@ -13,8 +13,9 @@ SERVO_ARC_TYPE(DeclarationBlock, RawServ
SERVO_ARC_TYPE(StyleRule, RawServoStyleRule)
SERVO_ARC_TYPE(ImportRule, RawServoImportRule)
SERVO_ARC_TYPE(AnimationValue, RawServoAnimationValue)
SERVO_ARC_TYPE(MediaList, RawServoMediaList)
SERVO_ARC_TYPE(MediaRule, RawServoMediaRule)
SERVO_ARC_TYPE(NamespaceRule, RawServoNamespaceRule)
SERVO_ARC_TYPE(PageRule, RawServoPageRule)
SERVO_ARC_TYPE(SupportsRule, RawServoSupportsRule)
+SERVO_ARC_TYPE(RuleNode, RawServoRuleNode)
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -381,16 +381,23 @@ SERVO_BINDING_FUNC(Servo_NoteExplicitHin
SERVO_BINDING_FUNC(Servo_TakeChangeHint, nsChangeHint, RawGeckoElementBorrowed element)
SERVO_BINDING_FUNC(Servo_ResolveStyle, ServoComputedValuesStrong,
RawGeckoElementBorrowed element,
RawServoStyleSetBorrowed set,
bool allow_stale)
SERVO_BINDING_FUNC(Servo_ResolvePseudoStyle, ServoComputedValuesStrong,
RawGeckoElementBorrowed element, nsIAtom* pseudo_tag,
bool is_probe, RawServoStyleSetBorrowed set)
+SERVO_BINDING_FUNC(Servo_ResolveRuleNode, RawServoRuleNodeStrong,
+ RawGeckoElementBorrowed element, nsIAtom* pseudo_tag,
+ RawServoStyleSetBorrowed set)
+SERVO_BINDING_FUNC(Servo_HasAuthorSpecifiedRules, bool,
+ RawServoRuleNodeBorrowed rules,
+ uint32_t rule_type_mask,
+ bool author_colors_allowed)
// Resolves style for an element or pseudo-element without processing pending
// restyles first. The Element and its ancestors may be unstyled, have pending
// restyles, or be in a display:none subtree. Styles are cached when possible,
// though caching is not possible within display:none subtrees, and the styles
// may be invalidated by already-scheduled restyles.
//
// The tree must be in a consistent state such that a normal traversal could be
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -540,16 +540,23 @@ ServoStyleSet::ResolveNonInheritingAnony
RefPtr<nsStyleContext> retval =
GetContext(computedValues.forget(), nullptr, aPseudoTag,
CSSPseudoElementType::NonInheritingAnonBox, nullptr);
cache = retval;
return retval.forget();
}
+already_AddRefed<RawServoRuleNode>
+ServoStyleSet::ResolveRuleNode(dom::Element *aElement, nsIAtom *aPseudoTag)
+{
+ MOZ_ASSERT(aElement);
+ return Servo_ResolveRuleNode(aElement, aPseudoTag, mRawSet.get()).Consume();
+}
+
// manage the set of style sheets in the style set
nsresult
ServoStyleSet::AppendStyleSheet(SheetType aType,
ServoStyleSheet* aSheet)
{
MOZ_ASSERT(aSheet);
MOZ_ASSERT(aSheet->IsApplicable());
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -33,16 +33,17 @@ class ServoStyleSheet;
struct Keyframe;
struct ServoComputedValuesWithParent;
} // namespace mozilla
class nsIContent;
class nsIDocument;
class nsStyleContext;
class nsPresContext;
struct nsTimingFunction;
+struct RawServoRuleNode;
struct TreeMatchContext;
namespace mozilla {
/**
* The set of style sheets that apply to a document, backed by a Servo
* Stylist. A ServoStyleSet contains ServoStyleSheets.
*/
@@ -187,16 +188,20 @@ public:
nsStyleContext* aParentContext);
// Get a style context for an anonymous box that does not inherit style from
// anything. aPseudoTag is the pseudo-tag to use and must be non-null. It
// must be an anon box, and must be a non-inheriting one.
already_AddRefed<nsStyleContext>
ResolveNonInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag);
+ // Get the rule node for a (pseudo-)element, resolving it lazily if needed.
+ already_AddRefed<RawServoRuleNode>
+ ResolveRuleNode(dom::Element *aElement, nsIAtom *aPseudoTag);
+
// manage the set of style sheets in the style set
nsresult AppendStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
nsresult PrependStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
nsresult RemoveStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
nsresult ReplaceSheets(SheetType aType,
const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets);
nsresult InsertStyleSheetBefore(SheetType aType,
ServoStyleSheet* aNewSheet,
--- a/servo/components/style/gecko/arc_types.rs
+++ b/servo/components/style/gecko/arc_types.rs
@@ -4,27 +4,30 @@
//! This file lists all arc FFI types and defines corresponding addref
//! and release functions. This list corresponds to ServoArcTypeList.h
//! file in Gecko.
#![allow(non_snake_case, missing_docs)]
use gecko_bindings::bindings::{RawServoMediaList, RawServoMediaRule, RawServoNamespaceRule, RawServoPageRule};
+use gecko_bindings::bindings::{RawServoRuleNode, RawServoRuleNodeStrong};
use gecko_bindings::bindings::{RawServoStyleSheet, RawServoImportRule, RawServoSupportsRule};
use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
use gecko_bindings::structs::{RawServoDeclarationBlock, RawServoStyleRule};
use gecko_bindings::structs::RawServoAnimationValue;
use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
use media_queries::MediaList;
use properties::{ComputedValues, PropertyDeclarationBlock};
use properties::animated_properties::AnimationValue;
use shared_lock::Locked;
+use std::{mem, ptr};
use stylesheets::{CssRules, Stylesheet, StyleRule, ImportRule, MediaRule};
use stylesheets::{NamespaceRule, PageRule, SupportsRule};
+use rule_tree::StrongRuleNode;
macro_rules! impl_arc_ffi {
($servo_type:ty => $gecko_type:ty [$addref:ident, $release:ident]) => {
unsafe impl HasFFI for $servo_type {
type FFIType = $gecko_type;
}
unsafe impl HasArcFFI for $servo_type {}
@@ -70,8 +73,33 @@ impl_arc_ffi!(Locked<MediaRule> => RawSe
impl_arc_ffi!(Locked<NamespaceRule> => RawServoNamespaceRule
[Servo_NamespaceRule_AddRef, Servo_NamespaceRule_Release]);
impl_arc_ffi!(Locked<PageRule> => RawServoPageRule
[Servo_PageRule_AddRef, Servo_PageRule_Release]);
impl_arc_ffi!(Locked<SupportsRule> => RawServoSupportsRule
[Servo_SupportsRule_AddRef, Servo_SupportsRule_Release]);
+
+// RuleNode is a Arc-like type but it does not use Arc.
+
+impl StrongRuleNode {
+ pub fn into_strong(self) -> RawServoRuleNodeStrong {
+ let ptr = self.ptr();
+ mem::forget(self);
+ unsafe { mem::transmute(ptr) }
+ }
+
+ pub fn from_ffi<'a>(ffi: &'a &RawServoRuleNode) -> &'a Self {
+ unsafe { &*(ffi as *const &RawServoRuleNode as *const StrongRuleNode) }
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_RuleNode_AddRef(obj: &RawServoRuleNode) {
+ mem::forget(StrongRuleNode::from_ffi(&obj).clone());
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_RuleNode_Release(obj: &RawServoRuleNode) {
+ let ptr = StrongRuleNode::from_ffi(&obj);
+ ptr::read(ptr as *const StrongRuleNode);
+}
--- a/servo/components/style/gecko/generated/bindings.rs
+++ b/servo/components/style/gecko/generated/bindings.rs
@@ -242,16 +242,21 @@ pub type RawServoPageRuleBorrowed<'a> =
pub type RawServoPageRuleBorrowedOrNull<'a> = Option<&'a RawServoPageRule>;
enum RawServoPageRuleVoid { }
pub struct RawServoPageRule(RawServoPageRuleVoid);
pub type RawServoSupportsRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoSupportsRule>;
pub type RawServoSupportsRuleBorrowed<'a> = &'a RawServoSupportsRule;
pub type RawServoSupportsRuleBorrowedOrNull<'a> = Option<&'a RawServoSupportsRule>;
enum RawServoSupportsRuleVoid { }
pub struct RawServoSupportsRule(RawServoSupportsRuleVoid);
+pub type RawServoRuleNodeStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoRuleNode>;
+pub type RawServoRuleNodeBorrowed<'a> = &'a RawServoRuleNode;
+pub type RawServoRuleNodeBorrowedOrNull<'a> = Option<&'a RawServoRuleNode>;
+enum RawServoRuleNodeVoid { }
+pub struct RawServoRuleNode(RawServoRuleNodeVoid);
pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;
pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;
pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;
pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;
enum RawServoStyleSetVoid { }
pub struct RawServoStyleSet(RawServoStyleSetVoid);
@@ -404,16 +409,22 @@ extern "C" {
}
extern "C" {
pub fn Servo_SupportsRule_AddRef(ptr: RawServoSupportsRuleBorrowed);
}
extern "C" {
pub fn Servo_SupportsRule_Release(ptr: RawServoSupportsRuleBorrowed);
}
extern "C" {
+ pub fn Servo_RuleNode_AddRef(ptr: RawServoRuleNodeBorrowed);
+}
+extern "C" {
+ pub fn Servo_RuleNode_Release(ptr: RawServoRuleNodeBorrowed);
+}
+extern "C" {
pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned);
}
extern "C" {
pub fn Gecko_ChildrenCount(node: RawGeckoNodeBorrowed) -> u32;
}
extern "C" {
pub fn Gecko_NodeIsElement(node: RawGeckoNodeBorrowed) -> bool;
}
@@ -2168,16 +2179,26 @@ extern "C" {
}
extern "C" {
pub fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsIAtom, is_probe: bool,
set: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong;
}
extern "C" {
+ pub fn Servo_ResolveRuleNode(element: RawGeckoElementBorrowed,
+ pseudo_tag: *mut nsIAtom,
+ set: RawServoStyleSetBorrowed)
+ -> RawServoRuleNodeStrong;
+}
+extern "C" {
+ pub fn Servo_HasAuthorSpecifiedRules(rules: RawServoRuleNodeStrong,
+ rule_type_mask: u32) -> bool;
+}
+extern "C" {
pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsIAtom,
set: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong;
}
extern "C" {
pub fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
set: RawServoStyleSetBorrowed,
--- a/servo/components/style/rule_tree/mod.rs
+++ b/servo/components/style/rule_tree/mod.rs
@@ -372,17 +372,18 @@ impl CascadeLevel {
CascadeLevel::SMILOverride |
CascadeLevel::Animations |
CascadeLevel::Transitions => true,
_ => false,
}
}
}
-struct RuleNode {
+/// A node in the rule tree.
+pub struct RuleNode {
/// The root node. Only the root has no root pointer, for obvious reasons.
root: Option<WeakRuleNode>,
/// The parent rule node. Only the root has no parent.
parent: Option<StrongRuleNode>,
/// The actual style source, either coming from a selector in a StyleRule,
/// or a raw property declaration block (like the style attribute).
@@ -643,17 +644,18 @@ impl StrongRuleNode {
}
}
// Try again inserting after the new last child.
last = Some(strong);
}
}
- fn ptr(&self) -> *mut RuleNode {
+ /// Raw pointer to the RuleNode
+ pub fn ptr(&self) -> *mut RuleNode {
self.ptr
}
fn get(&self) -> &RuleNode {
if cfg!(debug_assertions) {
let node = unsafe { &*self.ptr };
assert!(node.refcount.load(Ordering::Relaxed) > 0);
}
@@ -785,16 +787,23 @@ impl StrongRuleNode {
unsafe fn maybe_gc(&self) {
debug_assert!(self.get().is_root(), "Can't call GC on a non-root node!");
if self.get().free_count.load(Ordering::Relaxed) > RULE_TREE_GC_INTERVAL {
self.gc();
}
}
+ /// TODO: docs
+ pub fn has_author_specified_rules(&self,
+ _rule_type_mask: u32,
+ _author_colors_allowed: bool) -> bool {
+ true // TODO
+ }
+
/// Returns true if there is either animation or transition level rule.
pub fn has_animation_or_transition_rules(&self) -> bool {
self.self_and_ancestors()
.take_while(|node| node.cascade_level() >= CascadeLevel::SMILOverride)
.any(|node| node.cascade_level().is_animation())
}
}
--- a/servo/components/style/stylist.rs
+++ b/servo/components/style/stylist.rs
@@ -485,23 +485,56 @@ impl Stylist {
pseudo: &PseudoElement,
parent: &Arc<ComputedValues>,
font_metrics: &FontMetricsProvider)
-> Option<ComputedStyle>
where E: TElement +
fmt::Debug +
PresentationalHintsSynthetizer
{
+ let rule_node = match self.lazy_pseudo_rules(guards, element, pseudo) {
+ Some(rule_node) => rule_node,
+ None => return None
+ };
+
+ // Read the comment on `precomputed_values_for_pseudo` to see why it's
+ // difficult to assert that display: contents nodes never arrive here
+ // (tl;dr: It doesn't apply for replaced elements and such, but the
+ // computed value is still "contents").
+ let computed =
+ properties::cascade(&self.device,
+ &rule_node,
+ guards,
+ Some(&**parent),
+ Some(&**parent),
+ None,
+ &RustLogReporter,
+ font_metrics,
+ CascadeFlags::empty(),
+ self.quirks_mode);
+
+ Some(ComputedStyle::new(rule_node, Arc::new(computed)))
+ }
+
+ /// Computes the rule node for a lazily-cascaded pseudo-element.
+ ///
+ /// See the documentation on lazy pseudo-elements in
+ /// docs/components/style.md
+ pub fn lazy_pseudo_rules<E>(&self,
+ guards: &StylesheetGuards,
+ element: &E,
+ pseudo: &PseudoElement)
+ -> Option<StrongRuleNode>
+ where E: TElement + fmt::Debug + PresentationalHintsSynthetizer
+ {
debug_assert!(pseudo.is_lazy());
if self.pseudos_map.get(pseudo).is_none() {
- return None;
+ return None
}
- let mut declarations = vec![];
-
// Apply the selector flags. We should be in sequential mode
// already, so we can directly apply the parent flags.
let mut set_selector_flags = |element: &E, flags: ElementSelectorFlags| {
if cfg!(feature = "servo") {
// Servo calls this function from the worker, but only for internal
// pseudos, so we should never generate selector flags here.
unreachable!("internal pseudo generated slow selector flags?");
}
@@ -517,51 +550,34 @@ impl Stylist {
if !parent_flags.is_empty() {
if let Some(p) = element.parent_element() {
unsafe { p.set_selector_flags(parent_flags); }
}
}
};
+ let mut declarations = vec![];
self.push_applicable_declarations(element,
None,
None,
None,
AnimationRules(None, None),
Some(pseudo),
guards,
&mut declarations,
&mut set_selector_flags);
-
if declarations.is_empty() {
return None
}
- let rule_node =
- self.rule_tree.insert_ordered_rules(
- declarations.into_iter().map(|a| (a.source, a.level)));
-
- // Read the comment on `precomputed_values_for_pseudo` to see why it's
- // difficult to assert that display: contents nodes never arrive here
- // (tl;dr: It doesn't apply for replaced elements and such, but the
- // computed value is still "contents").
- let computed =
- properties::cascade(&self.device,
- &rule_node,
- guards,
- Some(&**parent),
- Some(&**parent),
- None,
- &RustLogReporter,
- font_metrics,
- CascadeFlags::empty(),
- self.quirks_mode);
-
- Some(ComputedStyle::new(rule_node, Arc::new(computed)))
+ let rule_node = self.rule_tree.insert_ordered_rules(declarations.into_iter().map(|a| {
+ (a.source, a.level)
+ }));
+ Some(rule_node)
}
/// Set a given device, which may change the styles that apply to the
/// document.
///
/// This means that we may need to rebuild style data even if the
/// stylesheets haven't changed.
///
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -27,16 +27,17 @@ use style::gecko::traversal::RecalcStyle
use style::gecko::wrapper::GeckoElement;
use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut};
use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
use style::gecko_bindings::bindings::{RawServoMediaList, RawServoMediaListBorrowed, RawServoMediaListStrong};
use style::gecko_bindings::bindings::{RawServoMediaRule, RawServoMediaRuleBorrowed};
use style::gecko_bindings::bindings::{RawServoNamespaceRule, RawServoNamespaceRuleBorrowed};
use style::gecko_bindings::bindings::{RawServoPageRule, RawServoPageRuleBorrowed};
+use style::gecko_bindings::bindings::{RawServoRuleNodeBorrowed, RawServoRuleNodeStrong};
use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed};
use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
use style::gecko_bindings::bindings::{nsACString, nsAString};
use style::gecko_bindings::bindings::Gecko_AnimationAppendKeyframe;
use style::gecko_bindings::bindings::RawGeckoAnimationPropertySegmentBorrowed;
@@ -72,17 +73,17 @@ use style::media_queries::{MediaList, pa
use style::parallel;
use style::parser::{LengthParsingMode, ParserContext};
use style::properties::{CascadeFlags, ComputedValues, Importance, ParsedDeclaration, StyleBuilder};
use style::properties::{PropertyDeclarationBlock, PropertyId};
use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP;
use style::properties::animated_properties::{AnimationValue, ComputeDistance, Interpolate, TransitionProperty};
use style::properties::parse_one_declaration;
use style::restyle_hints::{self, RestyleHint};
-use style::rule_tree::StyleSource;
+use style::rule_tree::{StrongRuleNode, StyleSource};
use style::selector_parser::PseudoElementCascadeType;
use style::sequential;
use style::shared_lock::{SharedRwLock, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked};
use style::string_cache::Atom;
use style::style_adjuster::StyleAdjuster;
use style::stylearc::Arc;
use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers};
use style::stylesheets::{ImportRule, MediaRule, NamespaceRule, Origin};
@@ -934,16 +935,47 @@ pub extern "C" fn Servo_ComputedValues_G
let metrics = get_metrics_provider_for_product();
data.stylist.precomputed_values_for_pseudo(&guards, &pseudo, maybe_parent,
cascade_flags, &metrics)
.values.unwrap()
.into_strong()
}
#[no_mangle]
+pub extern "C" fn Servo_ResolveRuleNode(element: RawGeckoElementBorrowed,
+ pseudo_tag: *mut nsIAtom,
+ raw_data: RawServoStyleSetBorrowed)
+ -> RawServoRuleNodeStrong
+{
+ let element = GeckoElement(element);
+ let doc_data = PerDocumentStyleData::from_ffi(raw_data);
+ let guard = (*GLOBAL_STYLE_DATA).shared_lock.read();
+
+ let data = element.mutate_data().unwrap();
+ let styles = match data.get_styles() {
+ Some(styles) => styles,
+ None => {
+ warn!("Calling Servo_ResolveRuleNode on unstyled element");
+ return Strong::null()
+ }
+ };
+
+ let maybe_rules = if pseudo_tag.is_null() {
+ Some(styles.primary.rules.clone())
+ } else {
+ get_pseudo_rule_node(&guard, element, pseudo_tag, styles, doc_data)
+ };
+
+ match maybe_rules {
+ Some(rule_node) => rule_node.into_strong(),
+ None => Strong::null(),
+ }
+}
+
+#[no_mangle]
pub extern "C" fn Servo_ResolvePseudoStyle(element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsIAtom, is_probe: bool,
raw_data: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong
{
let element = GeckoElement(element);
let data = unsafe { element.ensure_data() }.borrow_mut();
let doc_data = PerDocumentStyleData::from_ffi(raw_data);
@@ -962,16 +994,45 @@ pub extern "C" fn Servo_ResolvePseudoSty
let guard = global_style_data.shared_lock.read();
match get_pseudo_style(&guard, element, pseudo_tag, data.styles(), doc_data) {
Some(values) => values.into_strong(),
None if !is_probe => data.styles().primary.values().clone().into_strong(),
None => Strong::null(),
}
}
+#[no_mangle]
+pub extern "C" fn Servo_HasAuthorSpecifiedRules(rule_node: RawServoRuleNodeBorrowed,
+ rule_type_mask: u32,
+ author_colors_allowed: bool)
+ -> bool
+{
+ StrongRuleNode::from_ffi(&rule_node)
+ .has_author_specified_rules(rule_type_mask, author_colors_allowed)
+}
+
+fn get_pseudo_rule_node(guard: &SharedRwLockReadGuard,
+ element: GeckoElement,
+ pseudo_tag: *mut nsIAtom,
+ styles: &ElementStyles,
+ doc_data: &PerDocumentStyleData)
+ -> Option<StrongRuleNode>
+{
+ let pseudo = PseudoElement::from_atom_unchecked(Atom::from(pseudo_tag), false);
+ match pseudo.cascade_type() {
+ PseudoElementCascadeType::Eager => styles.pseudos.get(&pseudo).map(|s| s.rules.clone()),
+ PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
+ PseudoElementCascadeType::Lazy => {
+ let d = doc_data.borrow_mut();
+ let guards = StylesheetGuards::same(guard);
+ d.stylist.lazy_pseudo_rules(&guards, &element, &pseudo)
+ },
+ }
+}
+
fn get_pseudo_style(guard: &SharedRwLockReadGuard,
element: GeckoElement,
pseudo_tag: *mut nsIAtom,
styles: &ElementStyles,
doc_data: &PerDocumentStyleData)
-> Option<Arc<ComputedValues>>
{
let pseudo = PseudoElement::from_atom_unchecked(Atom::from(pseudo_tag), false);