<commit_before>/* 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/. */

#![allow(unsafe_code)]


use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use data::PersistentStyleData;
use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot::GeckoElementSnapshot;
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference};
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement};
use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::structs;
use gecko_bindings::structs::{NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO, NODE_IS_DIRTY_FOR_SERVO};
use gecko_bindings::structs::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
use gecko_bindings::structs::{nsChangeHint, nsIAtom, nsIContent, nsStyleContext};
use gecko_bindings::structs::OpaqueStyleData;
use gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
use libc::uintptr_t;
use parking_lot::RwLock;
use parser::ParserContextExtraData;
use properties::{ComputedValues, parse_style_attribute};
use properties::PropertyDeclarationBlock;
use selector_impl::ElementExt;
use selector_matching::ApplicableDeclarationBlock;
use selectors::Element;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use sink::Push;
use std::fmt;
use std::ops::BitOr;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr};
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use url::Url;

pub struct NonOpaqueStyleData(AtomicRefCell<PersistentStyleData>);

impl NonOpaqueStyleData {
    pub fn new() -> Self {
        NonOpaqueStyleData(AtomicRefCell::new(PersistentStyleData::new()))
    }
}


pub struct GeckoDeclarationBlock {
    pub declarations: Option<Arc<RwLock<PropertyDeclarationBlock>>>,
    // XXX The following two fields are made atomic to work around the
    // ownership system so that they can be changed inside a shared
    // instance. It wouldn't provide safety as Rust usually promises,
    // but it is fine as far as we only access them in a single thread.
    // If we need to access them in different threads, we would need
    // to redesign how it works with MiscContainer in Gecko side.
    pub cache: AtomicPtr<bindings::nsHTMLCSSStyleSheet>,
    pub immutable: AtomicBool,
}

impl PartialEq for GeckoDeclarationBlock {
    fn eq(&self, other: &GeckoDeclarationBlock) -> bool {
        match (&self.declarations, &other.declarations) {
            (&None, &None) => true,
            (&Some(ref s), &Some(ref other)) => *s.read() == *other.read(),
            _ => false,
        }
    }
}

unsafe impl HasFFI for GeckoDeclarationBlock {
    type FFIType = bindings::ServoDeclarationBlock;
}
unsafe impl HasArcFFI for GeckoDeclarationBlock {}


// We can eliminate OpaqueStyleData when the bindings move into the style crate.
fn to_opaque_style_data(d: *mut NonOpaqueStyleData) -> *mut OpaqueStyleData {
    d as *mut OpaqueStyleData
}
fn from_opaque_style_data(d: *mut OpaqueStyleData) -> *mut NonOpaqueStyleData {
    d as *mut NonOpaqueStyleData
}

// Important: We don't currently refcount the DOM, because the wrapper lifetime
// magic guarantees that our LayoutFoo references won't outlive the root, and
// we don't mutate any of the references on the Gecko side during restyle. We
// could implement refcounting if need be (at a potentially non-trivial
// performance cost) by implementing Drop and making LayoutFoo non-Copy.
#[derive(Clone, Copy)]
pub struct GeckoNode<'ln>(pub &'ln RawGeckoNode);

impl<'ln> GeckoNode<'ln> {
    fn from_content(content: &'ln nsIContent) -> Self {
        GeckoNode(&content._base)
    }

    fn node_info(&self) -> &structs::NodeInfo {
        debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
        unsafe { &*self.0.mNodeInfo.mRawPtr }
    }

    fn flags(&self) -> u32 {
        (self.0)._base._base_1.mFlags
    }

    // FIXME: We can implement this without OOL calls, but we can't easily given
    // GeckoNode is a raw reference.
    //
    // We can use a Cell<T>, but that's a bit of a pain.
    fn set_flags(&self, flags: u32) {
        unsafe { Gecko_SetNodeFlags(self.0, flags) }
    }

    fn unset_flags(&self, flags: u32) {
        unsafe { Gecko_UnsetNodeFlags(self.0, flags) }
    }

    fn get_node_data(&self) -> Option<&NonOpaqueStyleData> {
        unsafe {
            from_opaque_style_data(self.0.mServoData.get()).as_ref()
        }
    }

    pub fn initialize_data(self) {
        if self.get_node_data().is_none() {
            let ptr = Box::new(NonOpaqueStyleData::new());
            debug_assert!(self.0.mServoData.get().is_null());
            self.0.mServoData.set(to_opaque_style_data(Box::into_raw(ptr)));
        }
    }

    pub fn clear_data(self) {
        if !self.get_node_data().is_none() {
            let d = from_opaque_style_data(self.0.mServoData.get());
            let _ = unsafe { Box::from_raw(d) };
            self.0.mServoData.set(ptr::null_mut());
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GeckoRestyleDamage(nsChangeHint);

impl TRestyleDamage for GeckoRestyleDamage {
    type PreExistingComputedValues = nsStyleContext;

    fn empty() -> Self {
        use std::mem;
        GeckoRestyleDamage(unsafe { mem::transmute(0u32) })
    }

    fn compute(source: &nsStyleContext,
               new_style: &Arc<ComputedValues>) -> Self {
        let context = source as *const nsStyleContext as *mut nsStyleContext;
        let hint = unsafe { Gecko_CalcStyleDifference(context, new_style.as_borrowed_opt().unwrap()) };
        GeckoRestyleDamage(hint)
    }

    fn rebuild_and_reflow() -> Self {
        GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame)
    }
}

impl BitOr for GeckoRestyleDamage {
    type Output = Self;

    fn bitor(self, other: Self) -> Self {
        use std::mem;
        GeckoRestyleDamage(unsafe { mem::transmute(self.0 as u32 | other.0 as u32) })
    }
}


impl<'ln> NodeInfo for GeckoNode<'ln> {
    fn is_element(&self) -> bool {
        use gecko_bindings::structs::nsINode_BooleanFlag;
        self.0.mBoolFlags & nsINode_BooleanFlag::NodeIsElement as u32 != 0
    }

    fn is_text_node(&self) -> bool {
        // This is a DOM constant that isn't going to change.
        const TEXT_NODE: u16 = 3;
        self.node_info().mInner.mNodeType == TEXT_NODE
    }
}

impl<'ln> TNode for GeckoNode<'ln> {
    type ConcreteDocument = GeckoDocument<'ln>;
    type ConcreteElement = GeckoElement<'ln>;
    type ConcreteRestyleDamage = GeckoRestyleDamage;
    type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;

    fn to_unsafe(&self) -> UnsafeNode {
        (self.0 as *const _ as usize, 0)
    }

    unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
        GeckoNode(&*(n.0 as *mut RawGeckoNode))
    }

    fn dump(self) {
        unimplemented!()
    }

    fn dump_style(self) {<commit_msg>Auto merge of #13671 - emilio:flag-madness, r=Manishearth<commit_after>/* 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/. */

#![allow(unsafe_code)]


use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use data::PersistentStyleData;
use dom::{LayoutIterator, NodeInfo, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode};
use dom::{OpaqueNode, PresentationalHintsSynthetizer};
use element_state::ElementState;
use error_reporting::StdoutErrorReporter;
use gecko::selector_impl::{GeckoSelectorImpl, NonTSPseudoClass, PseudoElement};
use gecko::snapshot::GeckoElementSnapshot;
use gecko::snapshot_helpers;
use gecko_bindings::bindings;
use gecko_bindings::bindings::{Gecko_CalcStyleDifference, Gecko_StoreStyleDifference};
use gecko_bindings::bindings::{Gecko_DropStyleChildrenIterator, Gecko_MaybeCreateStyleChildrenIterator};
use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentElement};
use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetNextStyleChild};
use gecko_bindings::bindings::{Gecko_GetServoDeclarationBlock, Gecko_IsHTMLElementInHTMLDocument};
use gecko_bindings::bindings::{Gecko_IsLink, Gecko_IsRootElement};
use gecko_bindings::bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink, Gecko_Namespace};
use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
use gecko_bindings::bindings::Gecko_ClassOrClassList;
use gecko_bindings::bindings::Gecko_GetStyleContext;
use gecko_bindings::structs;
use gecko_bindings::structs::{NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO, NODE_IS_DIRTY_FOR_SERVO};
use gecko_bindings::structs::{RawGeckoDocument, RawGeckoElement, RawGeckoNode};
use gecko_bindings::structs::{nsChangeHint, nsIAtom, nsIContent, nsStyleContext};
use gecko_bindings::structs::OpaqueStyleData;
use gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
use libc::uintptr_t;
use parking_lot::RwLock;
use parser::ParserContextExtraData;
use properties::{ComputedValues, parse_style_attribute};
use properties::PropertyDeclarationBlock;
use selector_impl::ElementExt;
use selector_matching::ApplicableDeclarationBlock;
use selectors::Element;
use selectors::parser::{AttrSelector, NamespaceConstraint};
use sink::Push;
use std::fmt;
use std::ops::BitOr;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr};
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
use url::Url;

pub struct NonOpaqueStyleData(AtomicRefCell<PersistentStyleData>);

impl NonOpaqueStyleData {
    pub fn new() -> Self {
        NonOpaqueStyleData(AtomicRefCell::new(PersistentStyleData::new()))
    }
}


pub struct GeckoDeclarationBlock {
    pub declarations: Option<Arc<RwLock<PropertyDeclarationBlock>>>,
    // XXX The following two fields are made atomic to work around the
    // ownership system so that they can be changed inside a shared
    // instance. It wouldn't provide safety as Rust usually promises,
    // but it is fine as far as we only access them in a single thread.
    // If we need to access them in different threads, we would need
    // to redesign how it works with MiscContainer in Gecko side.
    pub cache: AtomicPtr<bindings::nsHTMLCSSStyleSheet>,
    pub immutable: AtomicBool,
}

impl PartialEq for GeckoDeclarationBlock {
    fn eq(&self, other: &GeckoDeclarationBlock) -> bool {
        match (&self.declarations, &other.declarations) {
            (&None, &None) => true,
            (&Some(ref s), &Some(ref other)) => *s.read() == *other.read(),
            _ => false,
        }
    }
}

unsafe impl HasFFI for GeckoDeclarationBlock {
    type FFIType = bindings::ServoDeclarationBlock;
}
unsafe impl HasArcFFI for GeckoDeclarationBlock {}


// We can eliminate OpaqueStyleData when the bindings move into the style crate.
fn to_opaque_style_data(d: *mut NonOpaqueStyleData) -> *mut OpaqueStyleData {
    d as *mut OpaqueStyleData
}
fn from_opaque_style_data(d: *mut OpaqueStyleData) -> *mut NonOpaqueStyleData {
    d as *mut NonOpaqueStyleData
}

// Important: We don't currently refcount the DOM, because the wrapper lifetime
// magic guarantees that our LayoutFoo references won't outlive the root, and
// we don't mutate any of the references on the Gecko side during restyle. We
// could implement refcounting if need be (at a potentially non-trivial
// performance cost) by implementing Drop and making LayoutFoo non-Copy.
#[derive(Clone, Copy)]
pub struct GeckoNode<'ln>(pub &'ln RawGeckoNode);

impl<'ln> GeckoNode<'ln> {
    fn from_content(content: &'ln nsIContent) -> Self {
        GeckoNode(&content._base)
    }

    fn node_info(&self) -> &structs::NodeInfo {
        debug_assert!(!self.0.mNodeInfo.mRawPtr.is_null());
        unsafe { &*self.0.mNodeInfo.mRawPtr }
    }

    fn flags(&self) -> u32 {
        (self.0)._base._base_1.mFlags
    }

    // FIXME: We can implement this without OOL calls, but we can't easily given
    // GeckoNode is a raw reference.
    //
    // We can use a Cell<T>, but that's a bit of a pain.
    fn set_flags(&self, flags: u32) {
        unsafe { Gecko_SetNodeFlags(self.0, flags) }
    }

    fn unset_flags(&self, flags: u32) {
        unsafe { Gecko_UnsetNodeFlags(self.0, flags) }
    }

    fn get_node_data(&self) -> Option<&NonOpaqueStyleData> {
        unsafe {
            from_opaque_style_data(self.0.mServoData.get()).as_ref()
        }
    }

    pub fn initialize_data(self) {
        if self.get_node_data().is_none() {
            let ptr = Box::new(NonOpaqueStyleData::new());
            debug_assert!(self.0.mServoData.get().is_null());
            self.0.mServoData.set(to_opaque_style_data(Box::into_raw(ptr)));
        }
    }

    pub fn clear_data(self) {
        if !self.get_node_data().is_none() {
            let d = from_opaque_style_data(self.0.mServoData.get());
            let _ = unsafe { Box::from_raw(d) };
            self.0.mServoData.set(ptr::null_mut());
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GeckoRestyleDamage(nsChangeHint);

impl TRestyleDamage for GeckoRestyleDamage {
    type PreExistingComputedValues = nsStyleContext;

    fn empty() -> Self {
        use std::mem;
        GeckoRestyleDamage(unsafe { mem::transmute(0u32) })
    }

    fn compute(source: &nsStyleContext,
               new_style: &Arc<ComputedValues>) -> Self {
        let context = source as *const nsStyleContext as *mut nsStyleContext;
        let hint = unsafe { Gecko_CalcStyleDifference(context, new_style.as_borrowed_opt().unwrap()) };
        GeckoRestyleDamage(hint)
    }

    fn rebuild_and_reflow() -> Self {
        GeckoRestyleDamage(nsChangeHint::nsChangeHint_ReconstructFrame)
    }
}

impl BitOr for GeckoRestyleDamage {
    type Output = Self;

    fn bitor(self, other: Self) -> Self {
        use std::mem;
        GeckoRestyleDamage(unsafe { mem::transmute(self.0 as u32 | other.0 as u32) })
    }
}


impl<'ln> NodeInfo for GeckoNode<'ln> {
    fn is_element(&self) -> bool {
        use gecko_bindings::structs::nsINode_BooleanFlag;
        self.0.mBoolFlags & (1u32 << nsINode_BooleanFlag::NodeIsElement as u32) != 0
    }

    fn is_text_node(&self) -> bool {
        // This is a DOM constant that isn't going to change.
        const TEXT_NODE: u16 = 3;
        self.node_info().mInner.mNodeType == TEXT_NODE
    }
}

impl<'ln> TNode for GeckoNode<'ln> {
    type ConcreteDocument = GeckoDocument<'ln>;
    type ConcreteElement = GeckoElement<'ln>;
    type ConcreteRestyleDamage = GeckoRestyleDamage;
    type ConcreteChildrenIterator = GeckoChildrenIterator<'ln>;

    fn to_unsafe(&self) -> UnsafeNode {
        (self.0 as *const _ as usize, 0)
    }

    unsafe fn from_unsafe(n: &UnsafeNode) -> Self {
        GeckoNode(&*(n.0 as *mut RawGeckoNode))
    }

    fn dump(self) {
        unimplemented!()
    }

    fn dump_style(self) {
{'fraction_non_alphanumeric': 0.11165721487082546, 'fraction_numerical': 0.005545053560176433, 'mean_word_length': 4.154595647937642, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4648201', 'n_tokens_mistral': 5381, 'n_tokens_neox': 5178, 'n_words': 1214}