Auto merge of #12469 - emilio:stylo, r=bholley

style: Rewrite the restyle hints code to allow different kinds of element snapshots.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [x] These changes do not require tests because refactoring.

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

This is a rewrite for how style interfaces with its consumers in order to allow
different representations for an element snapshot.

This also changes the requirements of an element snapshot, requiring them to
only implement MatchAttr, instead of MatchAttrGeneric. This is important for
stylo since implementing MatchAttrGeneric is way more difficult for us given the
atom limitations. This also allows for more performant implementations in the
Gecko side of things.

I don't want to get this merged just yet, mainly because the stylo part is not
implemented, but I'd like early feedback from @bholley and/or @heycam: How do
you see this approach? I don't think we'll have much problem to implement
MatchAttr for our element snapshots, but... worth checking.

r? @heycam

<!-- 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/12469)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-07-21 16:54:34 -05:00 committed by GitHub
commit 1e0321f7dd
18 changed files with 1183 additions and 256 deletions

View file

@ -133,6 +133,8 @@ unsafe impl Sync for nsStyleUnion {}
impl HeapSizeOf for nsStyleUnion { fn heap_size_of_children(&self) -> usize { 0 } }
use structs::nsStyleCoord_CalcValue as CalcValue;
use structs::nsStyleCoord_Calc as Calc;
use structs::nsRestyleHint;
use structs::ServoElementSnapshot;
use structs::SheetParsingMode;
use structs::nsMainThreadPtrHandle;
use structs::nsMainThreadPtrHolder;
@ -185,6 +187,8 @@ extern "C" {
pub fn Gecko_LocalName(element: *mut RawGeckoElement) -> *mut nsIAtom;
pub fn Gecko_Namespace(element: *mut RawGeckoElement) -> *mut nsIAtom;
pub fn Gecko_GetElementId(element: *mut RawGeckoElement) -> *mut nsIAtom;
pub fn Gecko_AtomAttrValue(element: *mut RawGeckoElement,
attribute: *mut nsIAtom) -> *mut nsIAtom;
pub fn Gecko_HasAttr(element: *mut RawGeckoElement, ns: *mut nsIAtom,
name: *mut nsIAtom) -> bool;
pub fn Gecko_AttrEquals(element: *mut RawGeckoElement, ns: *mut nsIAtom,
@ -207,6 +211,36 @@ extern "C" {
pub fn Gecko_ClassOrClassList(element: *mut RawGeckoElement,
class_: *mut *mut nsIAtom,
classList: *mut *mut *mut nsIAtom) -> u32;
pub fn Gecko_SnapshotAtomAttrValue(element: *mut ServoElementSnapshot,
attribute: *mut nsIAtom)
-> *mut nsIAtom;
pub fn Gecko_SnapshotHasAttr(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom)
-> bool;
pub fn Gecko_SnapshotAttrEquals(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom,
str: *mut nsIAtom, ignoreCase: bool)
-> bool;
pub fn Gecko_SnapshotAttrDashEquals(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom,
str: *mut nsIAtom) -> bool;
pub fn Gecko_SnapshotAttrIncludes(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom,
str: *mut nsIAtom) -> bool;
pub fn Gecko_SnapshotAttrHasSubstring(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom,
name: *mut nsIAtom,
str: *mut nsIAtom) -> bool;
pub fn Gecko_SnapshotAttrHasPrefix(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom,
str: *mut nsIAtom) -> bool;
pub fn Gecko_SnapshotAttrHasSuffix(element: *mut ServoElementSnapshot,
ns: *mut nsIAtom, name: *mut nsIAtom,
str: *mut nsIAtom) -> bool;
pub fn Gecko_SnapshotClassOrClassList(element: *mut ServoElementSnapshot,
class_: *mut *mut nsIAtom,
classList: *mut *mut *mut nsIAtom)
-> u32;
pub fn Gecko_GetServoDeclarationBlock(element: *mut RawGeckoElement)
-> *mut ServoDeclarationBlock;
pub fn Gecko_GetNodeData(node: *mut RawGeckoNode) -> *mut ServoNodeData;
@ -331,6 +365,10 @@ extern "C" {
set: *mut RawServoStyleSet);
pub fn Servo_RestyleSubtree(node: *mut RawGeckoNode,
set: *mut RawServoStyleSet);
pub fn Servo_ComputeRestyleHint(element: *mut RawGeckoElement,
snapshot: *mut ServoElementSnapshot,
set: *mut RawServoStyleSet)
-> nsRestyleHint;
pub fn Servo_StyleWorkerThreadCount() -> u32;
pub fn Gecko_Construct_nsStyleFont(ptr: *mut nsStyleFont);
pub fn Gecko_CopyConstruct_nsStyleFont(ptr: *mut nsStyleFont,

View file

@ -188,10 +188,20 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
pub const NS_FONT_VARIANT_NORMAL: ::std::os::raw::c_uint = 0;
pub const NS_FONT_VARIANT_SMALL_CAPS: ::std::os::raw::c_uint = 1;
pub const NS_CORNER_TOP_LEFT_X: ::std::os::raw::c_uint = 0;
@ -2725,6 +2735,12 @@ impl ::std::clone::Clone for nsIExpandedPrincipal {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _Make_integer_sequence<_Tp, _ISeq> {
pub _phantom0: ::std::marker::PhantomData<_Tp>,
pub _phantom1: ::std::marker::PhantomData<_ISeq>,
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsIURI {
pub _base: nsISupports,
@ -2766,6 +2782,26 @@ pub enum nsIRequest_nsIRequest_h_unnamed_7 {
impl ::std::clone::Clone for nsIRequest {
fn clone(&self) -> Self { *self }
}
/**
* EventStates is the class used to represent the event states of nsIContent
* instances. These states are calculated by IntrinsicState() and
* ContentStatesChanged() has to be called when one of them changes thus
* informing the layout/style engine of the change.
* Event states are associated with pseudo-classes.
*/
#[repr(C)]
#[derive(Debug, Copy)]
pub struct EventStates {
pub mStates: ::std::os::raw::c_ulong,
}
impl ::std::clone::Clone for EventStates {
fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_EventStates() {
assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
}
/**
* Enum defining the mode in which a sheet is to be parsed. This is
* usually, but not always, the same as the cascade level at which the
@ -2886,7 +2922,7 @@ fn bindgen_test_layout_nsMutationGuard() {
extern "C" {
#[link_name = "_ZN15nsMutationGuard11sGenerationE"]
pub static mut nsMutationGuard_consts_sGeneration:
::std::os::raw::c_ulonglong;
::std::os::raw::c_ulong;
}
pub type Float = f32;
#[repr(i8)]
@ -3262,6 +3298,259 @@ pub enum PlaybackDirection {
EndGuard_ = 4,
}
pub type NativeType = AnimationEffectReadOnly;
#[repr(C)]
#[derive(Debug)]
pub struct nsAttrName {
pub mBits: usize,
}
#[test]
fn bindgen_test_layout_nsAttrName() {
assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
}
pub type nscolor = u32;
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
pub enum nsStyledElementNotElementCSSInlineStyle { }
pub enum MiscContainer { }
pub enum ServoDeclarationBlock { }
pub enum Declaration { }
/**
* A class used to construct a nsString from a nsStringBuffer (we might
* want to move this to nsString at some point).
*
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
* assumes the string is maximally large, given the nsStringBuffer's storage
* size. This means the given string buffer *must* be sized exactly correctly
* for the string it contains (including one byte for a null terminator). If
* it has any unused storage space, then that will result in bogus characters
* at the end of our nsCheapString.
*/
#[repr(C)]
#[derive(Debug)]
pub struct nsCheapString {
pub _base: nsString,
}
#[test]
fn bindgen_test_layout_nsCheapString() {
assert_eq!(::std::mem::size_of::<nsCheapString>() , 16usize);
assert_eq!(::std::mem::align_of::<nsCheapString>() , 8usize);
}
#[repr(C)]
#[derive(Debug)]
pub struct nsAttrValue {
pub mBits: usize,
}
pub const eSVGTypesBegin: nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGAngle;
pub const eSVGTypesEnd: nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGViewBox;
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsAttrValue_ValueType {
eString = 0,
eAtom = 2,
eInteger = 3,
eColor = 7,
eEnum = 11,
ePercent = 15,
eGeckoCSSDeclaration = 16,
eServoCSSDeclaration = 17,
eURL = 18,
eImage = 19,
eAtomArray = 20,
eDoubleValue = 21,
eIntMarginValue = 22,
eSVGAngle = 23,
eSVGIntegerPair = 24,
eSVGLength = 25,
eSVGLengthList = 26,
eSVGNumberList = 27,
eSVGNumberPair = 28,
eSVGPathData = 29,
eSVGPointList = 30,
eSVGPreserveAspectRatio = 31,
eSVGStringList = 32,
eSVGTransformList = 33,
eSVGViewBox = 34,
}
/**
* Structure for a mapping from int (enum) values to strings. When you use
* it you generally create an array of them.
* Instantiate like this:
* EnumTable myTable[] = {
* { "string1", 1 },
* { "string2", 2 },
* { 0 }
* }
*/
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsAttrValue_EnumTable {
/** The string the value maps to */
pub tag: *const ::std::os::raw::c_char,
/** The enum value that maps to this string */
pub value: i16,
}
impl ::std::clone::Clone for nsAttrValue_EnumTable {
fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_nsAttrValue_EnumTable() {
assert_eq!(::std::mem::size_of::<nsAttrValue_EnumTable>() , 16usize);
assert_eq!(::std::mem::align_of::<nsAttrValue_EnumTable>() , 8usize);
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsAttrValue_ValueBaseType {
eStringBase = 0,
eOtherBase = 1,
eAtomBase = 2,
eIntegerBase = 3,
}
#[test]
fn bindgen_test_layout_nsAttrValue() {
assert_eq!(::std::mem::size_of::<nsAttrValue>() , 8usize);
assert_eq!(::std::mem::align_of::<nsAttrValue>() , 8usize);
}
extern "C" {
#[link_name = "_ZN11nsAttrValue15sEnumTableArrayE"]
pub static mut nsAttrValue_consts_sEnumTableArray:
nsTArray<*const nsAttrValue_EnumTable>;
}
pub enum nsCSSSelector { }
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsChangeHint {
nsChangeHint_RepaintFrame = 1,
nsChangeHint_NeedReflow = 2,
nsChangeHint_ClearAncestorIntrinsics = 4,
nsChangeHint_ClearDescendantIntrinsics = 8,
nsChangeHint_NeedDirtyReflow = 16,
nsChangeHint_SyncFrameView = 32,
nsChangeHint_UpdateCursor = 64,
nsChangeHint_UpdateEffects = 128,
nsChangeHint_UpdateOpacityLayer = 256,
nsChangeHint_UpdateTransformLayer = 512,
nsChangeHint_ReconstructFrame = 1024,
nsChangeHint_UpdateOverflow = 2048,
nsChangeHint_UpdateSubtreeOverflow = 4096,
nsChangeHint_UpdatePostTransformOverflow = 8192,
nsChangeHint_UpdateParentOverflow = 16384,
nsChangeHint_ChildrenOnlyTransform = 32768,
nsChangeHint_RecomputePosition = 65536,
nsChangeHint_UpdateContainingBlock = 131072,
nsChangeHint_BorderStyleNoneChange = 262144,
nsChangeHint_UpdateTextPath = 524288,
nsChangeHint_SchedulePaint = 1048576,
nsChangeHint_NeutralChange = 2097152,
nsChangeHint_InvalidateRenderingObservers = 4194304,
nsChangeHint_ReflowChangesSizeOrPosition = 8388608,
nsChangeHint_UpdateComputedBSize = 16777216,
nsChangeHint_UpdateUsesOpacity = 33554432,
nsChangeHint_UpdateBackgroundPosition = 67108864,
}
pub type nsChangeHint_size_t = ::std::os::raw::c_int;
/**
* |nsRestyleHint| is a bitfield for the result of
* |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
* restyling is necessary, use |nsRestyleHint(0)|.
*
* Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
* can stop processing at a frame when it detects no style changes and it is
* known that the styles of the subtree beneath it will not change, leaving
* the old style context on the frame. eRestyle_Force can be used to skip this
* optimization on a frame, and to force its new style context to be used.
*
* Similarly, eRestyle_ForceDescendants will cause the frame and all of its
* descendants to be traversed and for the new style contexts that are created
* to be set on the frames.
*
* NOTE: When adding new restyle hints, please also add them to
* RestyleManager::RestyleHintToString.
*/
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsRestyleHint {
eRestyle_Self = 1,
eRestyle_SomeDescendants = 2,
eRestyle_Subtree = 4,
eRestyle_LaterSiblings = 8,
eRestyle_CSSTransitions = 16,
eRestyle_CSSAnimations = 32,
eRestyle_SVGAttrAnimations = 64,
eRestyle_StyleAttribute = 128,
eRestyle_StyleAttribute_Animations = 256,
eRestyle_Force = 512,
eRestyle_ForceDescendants = 1024,
eRestyle_AllHintsWithAnimations = 368,
}
pub type nsRestyleHint_size_t = ::std::os::raw::c_int;
/**
* Additional data used in conjunction with an nsRestyleHint to control the
* restyle process.
*/
#[repr(C)]
#[derive(Debug)]
pub struct RestyleHintData {
pub mSelectorsForDescendants: nsTArray<*mut nsCSSSelector>,
}
#[test]
fn bindgen_test_layout_RestyleHintData() {
assert_eq!(::std::mem::size_of::<RestyleHintData>() , 8usize);
assert_eq!(::std::mem::align_of::<RestyleHintData>() , 8usize);
}
/**
* A structure representing a single attribute name and value.
*
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
*/
#[repr(C)]
#[derive(Debug)]
pub struct ServoAttrSnapshot {
pub mName: nsAttrName,
pub mValue: nsAttrValue,
}
#[test]
fn bindgen_test_layout_ServoAttrSnapshot() {
assert_eq!(::std::mem::size_of::<ServoAttrSnapshot>() , 16usize);
assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
}
/**
* A bitflags enum class used to determine what data does a ServoElementSnapshot
* contains.
*/
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum ServoElementSnapshotFlags {
State = 1,
Attributes = 2,
HTMLElementInHTMLDocument = 4,
All = 7,
}
/**
* This class holds all non-tree-structural state of an element that might be
* used for selector matching eventually.
*
* This means the attributes, and the element state, such as :hover, :active,
* etc...
*/
#[repr(C)]
#[derive(Debug)]
pub struct ServoElementSnapshot {
pub mContains: ServoElementSnapshotFlags,
pub mAttrs: nsTArray<ServoAttrSnapshot>,
pub mState: ::std::os::raw::c_uchar,
pub mExplicitRestyleHint: nsRestyleHint,
pub mExplicitChangeHint: nsChangeHint,
pub mIsHTMLElementInHTMLDocument: bool,
}
#[test]
fn bindgen_test_layout_ServoElementSnapshot() {
assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
}
pub enum ErrorReporter { }
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@ -4136,10 +4425,6 @@ pub enum nsCSSPropertyLogicalGroup {
eCSSPropertyLogicalGroup_Size = 8,
eCSSPropertyLogicalGroup_COUNT = 9,
}
pub type nscolor = u32;
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
/**
* Class to safely handle main-thread-only pointers off the main thread.
*

View file

@ -188,10 +188,20 @@ pub const NS_ERROR_MODULE_BASE_OFFSET: ::std::os::raw::c_uint = 69;
pub const MOZ_STRING_WITH_OBSOLETE_API: ::std::os::raw::c_uint = 1;
pub const NSID_LENGTH: ::std::os::raw::c_uint = 39;
pub const NS_NUMBER_OF_FLAGS_IN_REFCNT: ::std::os::raw::c_uint = 2;
pub const _STL_PAIR_H: ::std::os::raw::c_uint = 1;
pub const _GLIBCXX_UTILITY: ::std::os::raw::c_uint = 1;
pub const __cpp_lib_tuple_element_t: ::std::os::raw::c_uint = 201402;
pub const __cpp_lib_tuples_by_type: ::std::os::raw::c_uint = 201304;
pub const __cpp_lib_exchange_function: ::std::os::raw::c_uint = 201304;
pub const __cpp_lib_integer_sequence: ::std::os::raw::c_uint = 201304;
pub const NS_EVENT_STATE_HIGHEST_SERVO_BIT: ::std::os::raw::c_uint = 6;
pub const DOM_USER_DATA: ::std::os::raw::c_uint = 1;
pub const SMIL_MAPPED_ATTR_ANIMVAL: ::std::os::raw::c_uint = 2;
pub const TWIPS_PER_POINT_INT: ::std::os::raw::c_uint = 20;
pub const POINTS_PER_INCH_INT: ::std::os::raw::c_uint = 72;
pub const NS_ATTRNAME_NODEINFO_BIT: ::std::os::raw::c_uint = 1;
pub const NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM: ::std::os::raw::c_uint = 12;
pub const NS_ATTRVALUE_INTEGERTYPE_BITS: ::std::os::raw::c_uint = 4;
pub const NS_FONT_VARIANT_NORMAL: ::std::os::raw::c_uint = 0;
pub const NS_FONT_VARIANT_SMALL_CAPS: ::std::os::raw::c_uint = 1;
pub const NS_CORNER_TOP_LEFT_X: ::std::os::raw::c_uint = 0;
@ -2704,6 +2714,12 @@ impl ::std::clone::Clone for nsIExpandedPrincipal {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _Make_integer_sequence<_Tp, _ISeq> {
pub _phantom0: ::std::marker::PhantomData<_Tp>,
pub _phantom1: ::std::marker::PhantomData<_ISeq>,
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsIURI {
pub _base: nsISupports,
@ -2745,6 +2761,26 @@ pub enum nsIRequest_nsIRequest_h_unnamed_7 {
impl ::std::clone::Clone for nsIRequest {
fn clone(&self) -> Self { *self }
}
/**
* EventStates is the class used to represent the event states of nsIContent
* instances. These states are calculated by IntrinsicState() and
* ContentStatesChanged() has to be called when one of them changes thus
* informing the layout/style engine of the change.
* Event states are associated with pseudo-classes.
*/
#[repr(C)]
#[derive(Debug, Copy)]
pub struct EventStates {
pub mStates: ::std::os::raw::c_ulong,
}
impl ::std::clone::Clone for EventStates {
fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_EventStates() {
assert_eq!(::std::mem::size_of::<EventStates>() , 8usize);
assert_eq!(::std::mem::align_of::<EventStates>() , 8usize);
}
/**
* Enum defining the mode in which a sheet is to be parsed. This is
* usually, but not always, the same as the cascade level at which the
@ -2865,7 +2901,7 @@ fn bindgen_test_layout_nsMutationGuard() {
extern "C" {
#[link_name = "_ZN15nsMutationGuard11sGenerationE"]
pub static mut nsMutationGuard_consts_sGeneration:
::std::os::raw::c_ulonglong;
::std::os::raw::c_ulong;
}
pub type Float = f32;
#[repr(i8)]
@ -3241,6 +3277,259 @@ pub enum PlaybackDirection {
EndGuard_ = 4,
}
pub type NativeType = AnimationEffectReadOnly;
#[repr(C)]
#[derive(Debug)]
pub struct nsAttrName {
pub mBits: usize,
}
#[test]
fn bindgen_test_layout_nsAttrName() {
assert_eq!(::std::mem::size_of::<nsAttrName>() , 8usize);
assert_eq!(::std::mem::align_of::<nsAttrName>() , 8usize);
}
pub type nscolor = u32;
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
pub enum nsStyledElementNotElementCSSInlineStyle { }
pub enum MiscContainer { }
pub enum ServoDeclarationBlock { }
pub enum Declaration { }
/**
* A class used to construct a nsString from a nsStringBuffer (we might
* want to move this to nsString at some point).
*
* WARNING: Note that nsCheapString doesn't take an explicit length -- it
* assumes the string is maximally large, given the nsStringBuffer's storage
* size. This means the given string buffer *must* be sized exactly correctly
* for the string it contains (including one byte for a null terminator). If
* it has any unused storage space, then that will result in bogus characters
* at the end of our nsCheapString.
*/
#[repr(C)]
#[derive(Debug)]
pub struct nsCheapString {
pub _base: nsString,
}
#[test]
fn bindgen_test_layout_nsCheapString() {
assert_eq!(::std::mem::size_of::<nsCheapString>() , 16usize);
assert_eq!(::std::mem::align_of::<nsCheapString>() , 8usize);
}
#[repr(C)]
#[derive(Debug)]
pub struct nsAttrValue {
pub mBits: usize,
}
pub const eSVGTypesBegin: nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGAngle;
pub const eSVGTypesEnd: nsAttrValue_ValueType =
nsAttrValue_ValueType::eSVGViewBox;
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsAttrValue_ValueType {
eString = 0,
eAtom = 2,
eInteger = 3,
eColor = 7,
eEnum = 11,
ePercent = 15,
eGeckoCSSDeclaration = 16,
eServoCSSDeclaration = 17,
eURL = 18,
eImage = 19,
eAtomArray = 20,
eDoubleValue = 21,
eIntMarginValue = 22,
eSVGAngle = 23,
eSVGIntegerPair = 24,
eSVGLength = 25,
eSVGLengthList = 26,
eSVGNumberList = 27,
eSVGNumberPair = 28,
eSVGPathData = 29,
eSVGPointList = 30,
eSVGPreserveAspectRatio = 31,
eSVGStringList = 32,
eSVGTransformList = 33,
eSVGViewBox = 34,
}
/**
* Structure for a mapping from int (enum) values to strings. When you use
* it you generally create an array of them.
* Instantiate like this:
* EnumTable myTable[] = {
* { "string1", 1 },
* { "string2", 2 },
* { 0 }
* }
*/
#[repr(C)]
#[derive(Debug, Copy)]
pub struct nsAttrValue_EnumTable {
/** The string the value maps to */
pub tag: *const ::std::os::raw::c_char,
/** The enum value that maps to this string */
pub value: i16,
}
impl ::std::clone::Clone for nsAttrValue_EnumTable {
fn clone(&self) -> Self { *self }
}
#[test]
fn bindgen_test_layout_nsAttrValue_EnumTable() {
assert_eq!(::std::mem::size_of::<nsAttrValue_EnumTable>() , 16usize);
assert_eq!(::std::mem::align_of::<nsAttrValue_EnumTable>() , 8usize);
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsAttrValue_ValueBaseType {
eStringBase = 0,
eOtherBase = 1,
eAtomBase = 2,
eIntegerBase = 3,
}
#[test]
fn bindgen_test_layout_nsAttrValue() {
assert_eq!(::std::mem::size_of::<nsAttrValue>() , 8usize);
assert_eq!(::std::mem::align_of::<nsAttrValue>() , 8usize);
}
extern "C" {
#[link_name = "_ZN11nsAttrValue15sEnumTableArrayE"]
pub static mut nsAttrValue_consts_sEnumTableArray:
nsTArray<*const nsAttrValue_EnumTable>;
}
pub enum nsCSSSelector { }
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsChangeHint {
nsChangeHint_RepaintFrame = 1,
nsChangeHint_NeedReflow = 2,
nsChangeHint_ClearAncestorIntrinsics = 4,
nsChangeHint_ClearDescendantIntrinsics = 8,
nsChangeHint_NeedDirtyReflow = 16,
nsChangeHint_SyncFrameView = 32,
nsChangeHint_UpdateCursor = 64,
nsChangeHint_UpdateEffects = 128,
nsChangeHint_UpdateOpacityLayer = 256,
nsChangeHint_UpdateTransformLayer = 512,
nsChangeHint_ReconstructFrame = 1024,
nsChangeHint_UpdateOverflow = 2048,
nsChangeHint_UpdateSubtreeOverflow = 4096,
nsChangeHint_UpdatePostTransformOverflow = 8192,
nsChangeHint_UpdateParentOverflow = 16384,
nsChangeHint_ChildrenOnlyTransform = 32768,
nsChangeHint_RecomputePosition = 65536,
nsChangeHint_UpdateContainingBlock = 131072,
nsChangeHint_BorderStyleNoneChange = 262144,
nsChangeHint_UpdateTextPath = 524288,
nsChangeHint_SchedulePaint = 1048576,
nsChangeHint_NeutralChange = 2097152,
nsChangeHint_InvalidateRenderingObservers = 4194304,
nsChangeHint_ReflowChangesSizeOrPosition = 8388608,
nsChangeHint_UpdateComputedBSize = 16777216,
nsChangeHint_UpdateUsesOpacity = 33554432,
nsChangeHint_UpdateBackgroundPosition = 67108864,
}
pub type nsChangeHint_size_t = ::std::os::raw::c_int;
/**
* |nsRestyleHint| is a bitfield for the result of
* |HasStateDependentStyle| and |HasAttributeDependentStyle|. When no
* restyling is necessary, use |nsRestyleHint(0)|.
*
* Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
* can stop processing at a frame when it detects no style changes and it is
* known that the styles of the subtree beneath it will not change, leaving
* the old style context on the frame. eRestyle_Force can be used to skip this
* optimization on a frame, and to force its new style context to be used.
*
* Similarly, eRestyle_ForceDescendants will cause the frame and all of its
* descendants to be traversed and for the new style contexts that are created
* to be set on the frames.
*
* NOTE: When adding new restyle hints, please also add them to
* RestyleManager::RestyleHintToString.
*/
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsRestyleHint {
eRestyle_Self = 1,
eRestyle_SomeDescendants = 2,
eRestyle_Subtree = 4,
eRestyle_LaterSiblings = 8,
eRestyle_CSSTransitions = 16,
eRestyle_CSSAnimations = 32,
eRestyle_SVGAttrAnimations = 64,
eRestyle_StyleAttribute = 128,
eRestyle_StyleAttribute_Animations = 256,
eRestyle_Force = 512,
eRestyle_ForceDescendants = 1024,
eRestyle_AllHintsWithAnimations = 368,
}
pub type nsRestyleHint_size_t = ::std::os::raw::c_int;
/**
* Additional data used in conjunction with an nsRestyleHint to control the
* restyle process.
*/
#[repr(C)]
#[derive(Debug)]
pub struct RestyleHintData {
pub mSelectorsForDescendants: nsTArray<*mut nsCSSSelector>,
}
#[test]
fn bindgen_test_layout_RestyleHintData() {
assert_eq!(::std::mem::size_of::<RestyleHintData>() , 8usize);
assert_eq!(::std::mem::align_of::<RestyleHintData>() , 8usize);
}
/**
* A structure representing a single attribute name and value.
*
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
*/
#[repr(C)]
#[derive(Debug)]
pub struct ServoAttrSnapshot {
pub mName: nsAttrName,
pub mValue: nsAttrValue,
}
#[test]
fn bindgen_test_layout_ServoAttrSnapshot() {
assert_eq!(::std::mem::size_of::<ServoAttrSnapshot>() , 16usize);
assert_eq!(::std::mem::align_of::<ServoAttrSnapshot>() , 8usize);
}
/**
* A bitflags enum class used to determine what data does a ServoElementSnapshot
* contains.
*/
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum ServoElementSnapshotFlags {
State = 1,
Attributes = 2,
HTMLElementInHTMLDocument = 4,
All = 7,
}
/**
* This class holds all non-tree-structural state of an element that might be
* used for selector matching eventually.
*
* This means the attributes, and the element state, such as :hover, :active,
* etc...
*/
#[repr(C)]
#[derive(Debug)]
pub struct ServoElementSnapshot {
pub mContains: ServoElementSnapshotFlags,
pub mAttrs: nsTArray<ServoAttrSnapshot>,
pub mState: ::std::os::raw::c_uchar,
pub mExplicitRestyleHint: nsRestyleHint,
pub mExplicitChangeHint: nsChangeHint,
pub mIsHTMLElementInHTMLDocument: bool,
}
#[test]
fn bindgen_test_layout_ServoElementSnapshot() {
assert_eq!(::std::mem::size_of::<ServoElementSnapshot>() , 32usize);
assert_eq!(::std::mem::align_of::<ServoElementSnapshot>() , 8usize);
}
pub enum ErrorReporter { }
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
@ -4115,10 +4404,6 @@ pub enum nsCSSPropertyLogicalGroup {
eCSSPropertyLogicalGroup_Size = 8,
eCSSPropertyLogicalGroup_COUNT = 9,
}
pub type nscolor = u32;
#[repr(i8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum nsHexColorType { NoAlpha = 0, AllowAlpha = 1, }
/**
* Class to safely handle main-thread-only pointers off the main thread.
*

View file

@ -45,6 +45,7 @@ COMPILATION_TARGETS = {
"includes": [
"{}/dist/include/nsThemeConstants.h",
"{}/dist/include/mozilla/dom/AnimationEffectReadOnlyBinding.h",
"{}/dist/include/mozilla/ServoElementSnapshot.h",
],
"files": [
"{}/dist/include/nsStyleStruct.h",
@ -74,6 +75,8 @@ COMPILATION_TARGETS = {
"nsDataHashtable.h", "nsCSSScanner.h", "nsTArray",
"pair", "SheetParsingMode.h", "StaticPtr.h", "nsProxyRelease.h",
"mozilla/dom/AnimationEffectReadOnlyBinding.h",
"nsChangeHint.h", "ServoElementSnapshot.h",
"EventStates.h", "nsAttrValue.h", "nsAttrName.h",
"/Types.h", # <- Disallow UnionTypes.h
"/utility", # <- Disallow xutility
"nsINode.h", # <- For `NodeFlags`.
@ -123,7 +126,7 @@ COMPILATION_TARGETS = {
"nsStyleCoord", "nsStyleGradientStop", "nsStyleImageLayers",
"nsStyleImageLayers::Layer", "nsStyleImageLayers::LayerType",
"nsStyleUnit", "nsStyleUnion", "nsStyleCoord::CalcValue",
"nsStyleCoord::Calc",
"nsStyleCoord::Calc", "nsRestyleHint", "ServoElementSnapshot",
"SheetParsingMode", "nsMainThreadPtrHandle",
"nsMainThreadPtrHolder", "nscolor", "nsFont", "FontFamilyList",

View file

@ -13,7 +13,10 @@ use gecko_bindings::bindings::{RawServoStyleSet, RawServoStyleSheet, ServoComput
use gecko_bindings::bindings::{ServoDeclarationBlock, ServoNodeData, ThreadSafePrincipalHolder};
use gecko_bindings::bindings::{ThreadSafeURIHolder, nsHTMLCSSStyleSheet};
use gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI};
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::nsRestyleHint;
use gecko_bindings::structs::{SheetParsingMode, nsIAtom};
use snapshot::GeckoElementSnapshot;
use std::mem::transmute;
use std::ptr;
use std::slice;
@ -439,3 +442,22 @@ pub extern "C" fn Servo_CSSSupports(property: *const u8, property_length: u32,
Err(()) => false,
}
}
#[no_mangle]
pub extern "C" fn Servo_ComputeRestyleHint(element: *mut RawGeckoElement,
snapshot: *mut ServoElementSnapshot,
raw_data: *mut RawServoStyleSet) -> nsRestyleHint {
let per_doc_data = unsafe { &mut *(raw_data as *mut PerDocumentStyleData) };
let snapshot = unsafe { GeckoElementSnapshot::from_raw(snapshot) };
let element = unsafe { GeckoElement::from_raw(element) };
// NB: This involves an FFI call, we can get rid of it easily if needed.
let current_state = element.get_state();
let hint = per_doc_data.stylist
.compute_restyle_hint(&element, &snapshot,
current_state);
// NB: Binary representations match.
unsafe { transmute(hint.bits() as u32) }
}

View file

@ -22,6 +22,8 @@ extern crate util;
mod context;
mod data;
mod snapshot;
mod snapshot_helpers;
#[allow(non_snake_case)]
pub mod glue;
mod traversal;

149
ports/geckolib/snapshot.rs Normal file
View file

@ -0,0 +1,149 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use gecko_bindings::bindings;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
use selectors::parser::AttrSelector;
use snapshot_helpers;
use string_cache::Atom;
use style::element_state::ElementState;
use style::restyle_hints::ElementSnapshot;
use wrapper::AttrSelectorHelpers;
// NB: This is sound, in some sense, because during computation of restyle hints
// the snapshot is kept alive by the modified elements table.
#[derive(Debug)]
pub struct GeckoElementSnapshot(*mut ServoElementSnapshot);
impl GeckoElementSnapshot {
#[inline]
pub unsafe fn from_raw(raw: *mut ServoElementSnapshot) -> Self {
GeckoElementSnapshot(raw)
}
#[inline]
fn is_html_element_in_html_document(&self) -> bool {
unsafe { (*self.0).mIsHTMLElementInHTMLDocument }
}
#[inline]
fn has_any(&self, flags: Flags) -> bool {
unsafe { ((*self.0).mContains as u8 & flags as u8) != 0 }
}
}
impl ::selectors::MatchAttr for GeckoElementSnapshot {
type AttrString = Atom;
fn match_attr_has(&self, attr: &AttrSelector) -> bool {
unsafe {
bindings::Gecko_SnapshotHasAttr(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()))
}
}
fn match_attr_equals(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrEquals(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ false)
}
}
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrEquals(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ true)
}
}
fn match_attr_includes(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrIncludes(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
fn match_attr_dash(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrDashEquals(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
fn match_attr_prefix(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasPrefix(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
fn match_attr_substring(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasSubstring(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
fn match_attr_suffix(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasSuffix(self.0,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
}
impl ElementSnapshot for GeckoElementSnapshot {
fn state(&self) -> Option<ElementState> {
if self.has_any(Flags::State) {
Some(ElementState::from_bits_truncate(unsafe { (*self.0).mState as u16 }))
} else {
None
}
}
#[inline]
fn has_attrs(&self) -> bool {
self.has_any(Flags::Attributes)
}
fn id_attr(&self) -> Option<Atom> {
let ptr = unsafe {
bindings::Gecko_SnapshotAtomAttrValue(self.0,
atom!("id").as_ptr())
};
if ptr.is_null() {
None
} else {
Some(Atom::from(ptr))
}
}
// TODO: share logic with Element::{has_class, each_class}?
fn has_class(&self, name: &Atom) -> bool {
snapshot_helpers::has_class(self.0,
name,
bindings::Gecko_SnapshotClassOrClassList)
}
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
snapshot_helpers::each_class(self.0,
callback,
bindings::Gecko_SnapshotClassOrClassList)
}
}

View file

@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Element an snapshot common logic.
use gecko_bindings::structs::nsIAtom;
use std::{ptr, slice};
use string_cache::Atom;
pub type ClassOrClassList<T> = unsafe extern fn (T, *mut *mut nsIAtom, *mut *mut *mut nsIAtom) -> u32;
pub fn has_class<T>(item: T,
name: &Atom,
getter: ClassOrClassList<T>) -> bool
{
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = getter(item, &mut class, &mut list);
match length {
0 => false,
1 => name.as_ptr() == class,
n => {
let classes = slice::from_raw_parts(list, n as usize);
classes.iter().any(|ptr| name.as_ptr() == *ptr)
}
}
}
}
pub fn each_class<F, T>(item: T,
mut callback: F,
getter: ClassOrClassList<T>)
where F: FnMut(&Atom)
{
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = getter(item, &mut class, &mut list);
match length {
0 => {}
1 => Atom::with(class, &mut callback),
n => {
let classes = slice::from_raw_parts(list, n as usize);
for c in classes {
Atom::with(*c, &mut callback)
}
}
}
}
}

View file

@ -7,7 +7,6 @@
use gecko_bindings::bindings;
use gecko_bindings::bindings::Gecko_ChildrenCount;
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetElementId;
use gecko_bindings::bindings::Gecko_GetNodeData;
use gecko_bindings::bindings::ServoNodeData;
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
@ -20,7 +19,6 @@ use gecko_bindings::bindings::{Gecko_GetPrevSibling, Gecko_GetPrevSiblingElement
use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement, Gecko_IsTextNode};
use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink};
#[allow(unused_imports)] // Used in commented-out code.
use gecko_bindings::bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData};
use gecko_bindings::bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
use gecko_bindings::structs::nsIAtom;
@ -30,29 +28,25 @@ use libc::uintptr_t;
use selectors::Element;
use selectors::matching::DeclarationBlock;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use snapshot::GeckoElementSnapshot;
use snapshot_helpers;
use std::marker::PhantomData;
use std::ops::BitOr;
use std::ptr;
use std::slice;
use std::sync::Arc;
use string_cache::{Atom, BorrowedAtom, BorrowedNamespace, Namespace};
use style::data::PrivateStyleData;
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;
use style::gecko_selector_impl::{GeckoSelectorImpl, NonTSPseudoClass};
#[allow(unused_imports)] // Used in commented-out code.
use style::parser::ParserContextExtraData;
#[allow(unused_imports)] // Used in commented-out code.
use style::properties::{ComputedValues, parse_style_attribute};
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock};
use style::refcell::{Ref, RefCell, RefMut};
use style::restyle_hints::ElementSnapshot;
use style::selector_impl::ElementExt;
use style::sink::Push;
#[allow(unused_imports)] // Used in commented-out code.
use url::Url;
pub type NonOpaqueStyleData = *mut RefCell<PrivateStyleData>;
@ -324,7 +318,7 @@ impl<'ld> TDocument for GeckoDocument<'ld> {
}
}
fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, ElementSnapshot)> {
fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, GeckoElementSnapshot)> {
unimplemented!()
/*
let elements = unsafe { self.document.drain_modified_elements() };
@ -497,48 +491,30 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
fn get_id(&self) -> Option<Atom> {
unsafe {
let ptr = Gecko_GetElementId(self.element);
if ptr.is_null() {
None
} else {
Some(Atom::from(ptr))
}
let ptr = unsafe {
bindings::Gecko_AtomAttrValue(self.element,
atom!("id").as_ptr())
};
if ptr.is_null() {
None
} else {
Some(Atom::from(ptr))
}
}
fn has_class(&self, name: &Atom) -> bool {
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list);
match length {
0 => false,
1 => name.as_ptr() == class,
n => {
let classes = slice::from_raw_parts(list, n as usize);
classes.iter().any(|ptr| name.as_ptr() == *ptr)
}
}
}
snapshot_helpers::has_class(self.element,
name,
Gecko_ClassOrClassList)
}
fn each_class<F>(&self, mut callback: F) where F: FnMut(&Atom) {
unsafe {
let mut class: *mut nsIAtom = ptr::null_mut();
let mut list: *mut *mut nsIAtom = ptr::null_mut();
let length = Gecko_ClassOrClassList(self.element, &mut class, &mut list);
match length {
0 => {}
1 => Atom::with(class, &mut callback),
n => {
let classes = slice::from_raw_parts(list, n as usize);
for c in classes {
Atom::with(*c, &mut callback)
}
}
}
}
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
snapshot_helpers::each_class(self.element,
callback,
Gecko_ClassOrClassList)
}
fn is_html_element_in_html_document(&self) -> bool {
@ -548,9 +524,9 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
}
}
trait AttrSelectorHelpers {
pub trait AttrSelectorHelpers {
fn ns_or_null(&self) -> *mut nsIAtom;
fn select_name<'le>(&self, el: &GeckoElement<'le>) -> *mut nsIAtom;
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom;
}
impl AttrSelectorHelpers for AttrSelector {
@ -561,13 +537,12 @@ impl AttrSelectorHelpers for AttrSelector {
}
}
fn select_name<'le>(&self, el: &GeckoElement<'le>) -> *mut nsIAtom {
if el.is_html_element_in_html_document() {
fn select_name(&self, is_html_element_in_html_document: bool) -> *mut nsIAtom {
if is_html_element_in_html_document {
self.lower_name.as_ptr()
} else {
self.name.as_ptr()
}
}
}
@ -577,14 +552,14 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_HasAttr(self.element,
attr.ns_or_null(),
attr.select_name(self))
attr.select_name(self.is_html_element_in_html_document()))
}
}
fn match_attr_equals(&self, attr: &AttrSelector, value: &Self::AttrString) -> bool {
unsafe {
bindings::Gecko_AttrEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ false)
}
@ -593,7 +568,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
/* ignoreCase = */ false)
}
@ -602,7 +577,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrIncludes(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -610,7 +585,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrDashEquals(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -618,7 +593,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasPrefix(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -626,7 +601,7 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasSubstring(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
@ -634,13 +609,16 @@ impl<'le> ::selectors::MatchAttr for GeckoElement<'le> {
unsafe {
bindings::Gecko_AttrHasSuffix(self.element,
attr.ns_or_null(),
attr.select_name(self),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
}
}
}
impl<'le> ElementExt for GeckoElement<'le> {
type Snapshot = GeckoElementSnapshot;
#[inline]
fn is_link(&self) -> bool {
self.match_non_ts_pseudo_class(NonTSPseudoClass::AnyLink)
}