diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml deleted file mode 100644 index 8703128ab03..00000000000 --- a/ports/geckolib/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "geckoservo" -version = "0.0.1" -authors = ["The Servo Project Developers"] -license = "MPL-2.0" - -[lib] -name = "geckoservo" -path = "lib.rs" -crate-type = ["staticlib", "rlib"] - -[features] -bindgen = ["style/use_bindgen"] -gecko_debug = ["style/gecko_debug"] - -[dependencies] -atomic_refcell = "0.1" -cssparser = "0.23.0" -cstr = "0.1.2" -libc = "0.2" -log = {version = "0.4", features = ["release_max_level_info"]} -malloc_size_of = {path = "../../components/malloc_size_of"} -nsstring = {path = "../../support/gecko/nsstring"} -parking_lot = "0.5" -selectors = {path = "../../components/selectors"} -servo_arc = {path = "../../components/servo_arc"} -smallvec = "0.6" -style = {path = "../../components/style", features = ["gecko"]} -style_traits = {path = "../../components/style_traits"} diff --git a/ports/geckolib/error_reporter.rs b/ports/geckolib/error_reporter.rs deleted file mode 100644 index 3faddf7dcd2..00000000000 --- a/ports/geckolib/error_reporter.rs +++ /dev/null @@ -1,436 +0,0 @@ -/* 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/. */ - -//! Wrapper around Gecko's CSS error reporting mechanism. - -#![allow(unsafe_code)] - -use cssparser::{CowRcStr, serialize_identifier, ToCss}; -use cssparser::{SourceLocation, ParseError, ParseErrorKind, Token, BasicParseErrorKind}; -use selectors::parser::SelectorParseErrorKind; -use std::ffi::CStr; -use std::ptr; -use style::error_reporting::{ParseErrorReporter, ContextualParseError}; -use style::gecko_bindings::bindings::{Gecko_CreateCSSErrorReporter, Gecko_DestroyCSSErrorReporter}; -use style::gecko_bindings::bindings::Gecko_ReportUnexpectedCSSError; -use style::gecko_bindings::structs::{Loader, StyleSheet as DomStyleSheet, nsIURI}; -use style::gecko_bindings::structs::ErrorReporter as GeckoErrorReporter; -use style::gecko_bindings::structs::URLExtraData as RawUrlExtraData; -use style::stylesheets::UrlExtraData; -use style_traits::{StyleParseErrorKind, ValueParseErrorKind}; - -pub type ErrorKind<'i> = ParseErrorKind<'i, StyleParseErrorKind<'i>>; - -/// Wrapper around an instance of Gecko's CSS error reporter. -pub struct ErrorReporter(*mut GeckoErrorReporter); - -impl ErrorReporter { - /// Create a new instance of the Gecko error reporter. - pub fn new( - sheet: *mut DomStyleSheet, - loader: *mut Loader, - extra_data: *mut RawUrlExtraData, - ) -> Self { - unsafe { - let url = extra_data.as_ref() - .map(|d| d.mBaseURI.raw::()) - .unwrap_or(ptr::null_mut()); - ErrorReporter(Gecko_CreateCSSErrorReporter(sheet, loader, url)) - } - } -} - -impl Drop for ErrorReporter { - fn drop(&mut self) { - unsafe { - Gecko_DestroyCSSErrorReporter(self.0); - } - } -} - -enum ErrorString<'a> { - Snippet(CowRcStr<'a>), - Ident(CowRcStr<'a>), - UnexpectedToken(Token<'a>), -} - -impl<'a> ErrorString<'a> { - fn into_str(self) -> CowRcStr<'a> { - match self { - ErrorString::Snippet(s) => s, - ErrorString::UnexpectedToken(t) => t.to_css_string().into(), - ErrorString::Ident(i) => { - let mut s = String::new(); - serialize_identifier(&i, &mut s).unwrap(); - s.into() - } - } - } -} - -#[derive(Debug)] -enum Action { - Nothing, - Skip, - Drop, -} - -trait ErrorHelpers<'a> { - fn error_data(self) -> (CowRcStr<'a>, ErrorKind<'a>); - fn error_params(self) -> ErrorParams<'a>; - fn to_gecko_message(&self) -> (Option<&'static CStr>, &'static CStr, Action); -} - -fn extract_error_param<'a>(err: ErrorKind<'a>) -> Option> { - Some(match err { - ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(t)) => { - ErrorString::UnexpectedToken(t) - } - - ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(i)) | - ParseErrorKind::Custom(StyleParseErrorKind::UnsupportedAtRule(i)) => { - let mut s = String::from("@"); - serialize_identifier(&i, &mut s).unwrap(); - ErrorString::Snippet(s.into()) - } - - ParseErrorKind::Custom(StyleParseErrorKind::OtherInvalidValue(property)) => { - ErrorString::Snippet(property) - } - - ParseErrorKind::Custom( - StyleParseErrorKind::SelectorError( - SelectorParseErrorKind::UnexpectedIdent(ident) - ) - ) => { - ErrorString::Ident(ident) - } - - ParseErrorKind::Custom(StyleParseErrorKind::UnknownProperty(property)) => { - ErrorString::Ident(property) - } - - ParseErrorKind::Custom( - StyleParseErrorKind::UnexpectedTokenWithinNamespace(token) - ) => { - ErrorString::UnexpectedToken(token) - } - - _ => return None, - }) -} - -struct ErrorParams<'a> { - prefix_param: Option>, - main_param: Option>, -} - -/// If an error parameter is present in the given error, return it. Additionally return -/// a second parameter if it exists, for use in the prefix for the eventual error message. -fn extract_error_params<'a>(err: ErrorKind<'a>) -> Option> { - let (main, prefix) = match err { - ParseErrorKind::Custom(StyleParseErrorKind::InvalidColor(property, token)) | - ParseErrorKind::Custom(StyleParseErrorKind::InvalidFilter(property, token)) => { - (Some(ErrorString::Snippet(property.into())), Some(ErrorString::UnexpectedToken(token))) - } - - ParseErrorKind::Custom( - StyleParseErrorKind::MediaQueryExpectedFeatureName(ident) - ) => { - (Some(ErrorString::Ident(ident)), None) - } - - ParseErrorKind::Custom( - StyleParseErrorKind::ExpectedIdentifier(token) - ) | - ParseErrorKind::Custom( - StyleParseErrorKind::ValueError(ValueParseErrorKind::InvalidColor(token)) - ) => { - (Some(ErrorString::UnexpectedToken(token)), None) - } - - ParseErrorKind::Custom(StyleParseErrorKind::SelectorError(err)) => match err { - SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t) | - SelectorParseErrorKind::BadValueInAttr(t) | - SelectorParseErrorKind::ExpectedBarInAttr(t) | - SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t) | - SelectorParseErrorKind::InvalidQualNameInAttr(t) | - SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t) | - SelectorParseErrorKind::PseudoElementExpectedIdent(t) | - SelectorParseErrorKind::NoIdentForPseudo(t) | - SelectorParseErrorKind::ClassNeedsIdent(t) | - SelectorParseErrorKind::PseudoElementExpectedColon(t) => { - (None, Some(ErrorString::UnexpectedToken(t))) - } - SelectorParseErrorKind::ExpectedNamespace(namespace) => { - (None, Some(ErrorString::Ident(namespace))) - } - SelectorParseErrorKind::UnsupportedPseudoClassOrElement(p) => { - (None, Some(ErrorString::Ident(p))) - } - SelectorParseErrorKind::EmptySelector | - SelectorParseErrorKind::DanglingCombinator => { - (None, None) - } - SelectorParseErrorKind::EmptyNegation => { - (None, Some(ErrorString::Snippet(")".into()))) - } - err => match extract_error_param(ParseErrorKind::Custom(StyleParseErrorKind::SelectorError(err))) { - Some(e) => (Some(e), None), - None => return None, - } - }, - err => match extract_error_param(err) { - Some(e) => (Some(e), None), - None => return None, - } - }; - Some(ErrorParams { - main_param: main, - prefix_param: prefix, - }) -} - -impl<'a> ErrorHelpers<'a> for ContextualParseError<'a> { - fn error_data(self) -> (CowRcStr<'a>, ErrorKind<'a>) { - match self { - ContextualParseError::UnsupportedPropertyDeclaration(s, err) | - ContextualParseError::UnsupportedFontFaceDescriptor(s, err) | - ContextualParseError::UnsupportedFontFeatureValuesDescriptor(s, err) | - ContextualParseError::InvalidKeyframeRule(s, err) | - ContextualParseError::InvalidFontFeatureValuesRule(s, err) | - ContextualParseError::UnsupportedKeyframePropertyDeclaration(s, err) | - ContextualParseError::InvalidRule(s, err) | - ContextualParseError::UnsupportedRule(s, err) | - ContextualParseError::UnsupportedViewportDescriptorDeclaration(s, err) | - ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(s, err) | - ContextualParseError::InvalidMediaRule(s, err) | - ContextualParseError::UnsupportedValue(s, err) => { - (s.into(), err.kind) - } - ContextualParseError::InvalidCounterStyleWithoutSymbols(s) | - ContextualParseError::InvalidCounterStyleNotEnoughSymbols(s) => { - (s.into(), ParseErrorKind::Custom(StyleParseErrorKind::UnspecifiedError.into())) - } - ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols | - ContextualParseError::InvalidCounterStyleExtendsWithSymbols | - ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols => { - ("".into(), ParseErrorKind::Custom(StyleParseErrorKind::UnspecifiedError.into())) - } - } - } - - fn error_params(self) -> ErrorParams<'a> { - let (s, error) = self.error_data(); - extract_error_params(error).unwrap_or_else(|| ErrorParams { - main_param: Some(ErrorString::Snippet(s)), - prefix_param: None - }) - } - - fn to_gecko_message(&self) -> (Option<&'static CStr>, &'static CStr, Action) { - let (msg, action): (&CStr, Action) = match *self { - ContextualParseError::UnsupportedPropertyDeclaration( - _, ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(_)), .. } - ) | - ContextualParseError::UnsupportedPropertyDeclaration( - _, ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(_)), .. } - ) => { - (cstr!("PEParseDeclarationDeclExpected"), Action::Skip) - } - ContextualParseError::UnsupportedPropertyDeclaration( - _, ParseError { kind: ParseErrorKind::Custom(ref err), .. } - ) => { - match *err { - StyleParseErrorKind::InvalidColor(_, _) => { - return (Some(cstr!("PEColorNotColor")), - cstr!("PEValueParsingError"), Action::Drop) - } - StyleParseErrorKind::InvalidFilter(_, _) => { - return (Some(cstr!("PEExpectedNoneOrURLOrFilterFunction")), - cstr!("PEValueParsingError"), Action::Drop) - } - StyleParseErrorKind::OtherInvalidValue(_) => { - (cstr!("PEValueParsingError"), Action::Drop) - } - _ => (cstr!("PEUnknownProperty"), Action::Drop) - } - } - ContextualParseError::UnsupportedPropertyDeclaration(..) => - (cstr!("PEUnknownProperty"), Action::Drop), - ContextualParseError::UnsupportedFontFaceDescriptor(..) => - (cstr!("PEUnknownFontDesc"), Action::Skip), - ContextualParseError::InvalidKeyframeRule(..) => - (cstr!("PEKeyframeBadName"), Action::Nothing), - ContextualParseError::UnsupportedKeyframePropertyDeclaration(..) => - (cstr!("PEBadSelectorKeyframeRuleIgnored"), Action::Nothing), - ContextualParseError::InvalidRule( - _, ParseError { kind: ParseErrorKind::Custom( - StyleParseErrorKind::UnexpectedTokenWithinNamespace(_) - ), .. } - ) => { - (cstr!("PEAtNSUnexpected"), Action::Nothing) - } - ContextualParseError::InvalidRule( - _, ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(_)), .. } - ) | - ContextualParseError::InvalidRule( - _, ParseError { kind: ParseErrorKind::Custom( - StyleParseErrorKind::UnsupportedAtRule(_) - ), .. } - ) => { - (cstr!("PEUnknownAtRule"), Action::Nothing) - } - ContextualParseError::InvalidRule(_, ref err) => { - let prefix = match err.kind { - ParseErrorKind::Custom(StyleParseErrorKind::SelectorError(ref err)) => match *err { - SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(_) => { - Some(cstr!("PEAttSelUnexpected")) - } - SelectorParseErrorKind::ExpectedBarInAttr(_) => { - Some(cstr!("PEAttSelNoBar")) - } - SelectorParseErrorKind::BadValueInAttr(_) => { - Some(cstr!("PEAttSelBadValue")) - } - SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(_) => { - Some(cstr!("PEAttributeNameOrNamespaceExpected")) - } - SelectorParseErrorKind::InvalidQualNameInAttr(_) => { - Some(cstr!("PEAttributeNameExpected")) - } - SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(_) => { - Some(cstr!("PETypeSelNotType")) - } - SelectorParseErrorKind::ExpectedNamespace(_) => { - Some(cstr!("PEUnknownNamespacePrefix")) - } - SelectorParseErrorKind::EmptySelector => { - Some(cstr!("PESelectorGroupNoSelector")) - } - SelectorParseErrorKind::DanglingCombinator => { - Some(cstr!("PESelectorGroupExtraCombinator")) - } - SelectorParseErrorKind::UnsupportedPseudoClassOrElement(_) => { - Some(cstr!("PEPseudoSelUnknown")) - } - SelectorParseErrorKind::PseudoElementExpectedColon(_) => { - Some(cstr!("PEPseudoSelEndOrUserActionPC")) - } - SelectorParseErrorKind::NoIdentForPseudo(_) => { - Some(cstr!("PEPseudoClassArgNotIdent")) - } - SelectorParseErrorKind::PseudoElementExpectedIdent(_) => { - Some(cstr!("PEPseudoSelBadName")) - } - SelectorParseErrorKind::ClassNeedsIdent(_) => { - Some(cstr!("PEClassSelNotIdent")) - } - SelectorParseErrorKind::EmptyNegation => { - Some(cstr!("PENegationBadArg")) - } - _ => None, - }, - _ => None, - }; - return (prefix, cstr!("PEBadSelectorRSIgnored"), Action::Nothing); - } - ContextualParseError::InvalidMediaRule(_, ref err) => { - let err: &CStr = match err.kind { - ParseErrorKind::Custom(StyleParseErrorKind::ExpectedIdentifier(..)) => { - cstr!("PEGatherMediaNotIdent") - }, - ParseErrorKind::Custom(StyleParseErrorKind::MediaQueryExpectedFeatureName(..)) => { - cstr!("PEMQExpectedFeatureName") - }, - ParseErrorKind::Custom(StyleParseErrorKind::MediaQueryExpectedFeatureValue) => { - cstr!("PEMQExpectedFeatureValue") - }, - ParseErrorKind::Custom(StyleParseErrorKind::RangedExpressionWithNoValue) => { - cstr!("PEMQNoMinMaxWithoutValue") - }, - _ => { - cstr!("PEDeclDropped") - }, - }; - (err, Action::Nothing) - } - ContextualParseError::UnsupportedRule(..) => - (cstr!("PEDeclDropped"), Action::Nothing), - ContextualParseError::UnsupportedViewportDescriptorDeclaration(..) | - ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(..) | - ContextualParseError::InvalidCounterStyleWithoutSymbols(..) | - ContextualParseError::InvalidCounterStyleNotEnoughSymbols(..) | - ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols | - ContextualParseError::InvalidCounterStyleExtendsWithSymbols | - ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols | - ContextualParseError::UnsupportedFontFeatureValuesDescriptor(..) | - ContextualParseError::InvalidFontFeatureValuesRule(..) => - (cstr!("PEUnknownAtRule"), Action::Skip), - ContextualParseError::UnsupportedValue(_, ParseError { ref kind, .. }) => { - match *kind { - ParseErrorKind::Custom( - StyleParseErrorKind::ValueError( - ValueParseErrorKind::InvalidColor(..) - ) - ) => (cstr!("PEColorNotColor"), Action::Nothing), - _ => { - // Not the best error message, since we weren't parsing - // a declaration, just a value. But we don't produce - // UnsupportedValue errors other than InvalidColors - // currently. - debug_assert!(false, "should use a more specific error message"); - (cstr!("PEDeclDropped"), Action::Nothing) - } - } - } - }; - (None, msg, action) - } -} - -impl ErrorReporter { - pub fn report(&self, location: SourceLocation, error: ContextualParseError) { - let (pre, name, action) = error.to_gecko_message(); - let suffix = match action { - Action::Nothing => ptr::null(), - Action::Skip => cstr!("PEDeclSkipped").as_ptr(), - Action::Drop => cstr!("PEDeclDropped").as_ptr(), - }; - let params = error.error_params(); - let param = params.main_param; - let pre_param = params.prefix_param; - let param = param.map(|p| p.into_str()); - let pre_param = pre_param.map(|p| p.into_str()); - let param_ptr = param.as_ref().map_or(ptr::null(), |p| p.as_ptr()); - let pre_param_ptr = pre_param.as_ref().map_or(ptr::null(), |p| p.as_ptr()); - // The CSS source text is unused and will be removed in bug 1381188. - let source = ""; - unsafe { - Gecko_ReportUnexpectedCSSError(self.0, - name.as_ptr() as *const _, - param_ptr as *const _, - param.as_ref().map_or(0, |p| p.len()) as u32, - pre.map_or(ptr::null(), |p| p.as_ptr()) as *const _, - pre_param_ptr as *const _, - pre_param.as_ref().map_or(0, |p| p.len()) as u32, - suffix as *const _, - source.as_ptr() as *const _, - source.len() as u32, - location.line, - location.column); - } - } -} - -impl ParseErrorReporter for ErrorReporter { - fn report_error( - &self, - _url: &UrlExtraData, - location: SourceLocation, - error: ContextualParseError - ) { - self.report(location, error) - } -} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs deleted file mode 100644 index 3b341cadbb5..00000000000 --- a/ports/geckolib/glue.rs +++ /dev/null @@ -1,5611 +0,0 @@ -/* 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 cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation}; -use cssparser::ToCss as ParserToCss; -use malloc_size_of::MallocSizeOfOps; -use nsstring::{nsCString, nsStringRepr}; -use selectors::{NthIndexCache, SelectorList}; -use selectors::matching::{MatchingContext, MatchingMode, matches_selector}; -use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; -use smallvec::SmallVec; -use std::cell::RefCell; -use std::collections::BTreeSet; -use std::fmt::Write; -use std::iter; -use std::mem; -use std::os::raw::c_void; -use std::ptr; -use style::applicable_declarations::ApplicableDeclarationBlock; -use style::author_styles::AuthorStyles; -use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext}; -use style::context::ThreadLocalStyleContext; -use style::counter_style; -use style::data::{ElementStyles, self}; -use style::dom::{ShowSubtreeData, TDocument, TElement, TNode}; -use style::driver; -use style::element_state::{DocumentState, ElementState}; -use style::error_reporting::{ContextualParseError, NullReporter, ParseErrorReporter}; -use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product}; -use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl}; -use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL}; -use style::gecko::restyle_damage::GeckoRestyleDamage; -use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement}; -use style::gecko::traversal::RecalcStyleOnly; -use style::gecko::wrapper::{GeckoElement, GeckoNode}; -use style::gecko_bindings::bindings; -use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoElementBorrowedOrNull, RawGeckoNodeBorrowed}; -use style::gecko_bindings::bindings::{RawGeckoKeyframeListBorrowed, RawGeckoKeyframeListBorrowedMut}; -use style::gecko_bindings::bindings::{RawServoAuthorStyles, RawServoAuthorStylesBorrowed}; -use style::gecko_bindings::bindings::{RawServoAuthorStylesBorrowedMut, RawServoAuthorStylesOwned}; -use style::gecko_bindings::bindings::{RawServoCounterStyleRule, RawServoCounterStyleRuleBorrowed}; -use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong}; -use style::gecko_bindings::bindings::{RawServoDocumentRule, RawServoDocumentRuleBorrowed}; -use style::gecko_bindings::bindings::{RawServoFontFaceRuleBorrowed, RawServoFontFaceRuleStrong}; -use style::gecko_bindings::bindings::{RawServoFontFeatureValuesRule, RawServoFontFeatureValuesRuleBorrowed}; -use style::gecko_bindings::bindings::{RawServoImportRule, RawServoImportRuleBorrowed}; -use style::gecko_bindings::bindings::{RawServoKeyframe, RawServoKeyframeBorrowed, RawServoKeyframeStrong}; -use style::gecko_bindings::bindings::{RawServoKeyframesRule, RawServoKeyframesRuleBorrowed}; -use style::gecko_bindings::bindings::{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::{RawServoSelectorListBorrowed, RawServoSelectorListOwned}; -use style::gecko_bindings::bindings::{RawServoSourceSizeListBorrowedOrNull, RawServoSourceSizeListOwned}; -use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetBorrowedOrNull, RawServoStyleSetOwned}; -use style::gecko_bindings::bindings::{RawServoStyleSheetContentsBorrowed, ServoComputedDataBorrowed}; -use style::gecko_bindings::bindings::{RawServoStyleSheetContentsStrong, ComputedStyleBorrowed}; -use style::gecko_bindings::bindings::{RawServoSupportsRule, RawServoSupportsRuleBorrowed}; -use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong}; -use style::gecko_bindings::bindings::{nsACString, nsAString, nsCSSPropertyIDSetBorrowedMut}; -use style::gecko_bindings::bindings::ComputedStyleBorrowedOrNull; -use style::gecko_bindings::bindings::Gecko_AddPropertyToSet; -use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair; -use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet; -use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe; -use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe; -use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart; -use style::gecko_bindings::bindings::Gecko_HaveSeenPtr; -use style::gecko_bindings::bindings::Gecko_NewNoneTransform; -use style::gecko_bindings::bindings::RawGeckoAnimationPropertySegmentBorrowed; -use style::gecko_bindings::bindings::RawGeckoCSSPropertyIDListBorrowed; -use style::gecko_bindings::bindings::RawGeckoComputedKeyframeValuesListBorrowedMut; -use style::gecko_bindings::bindings::RawGeckoComputedTimingBorrowed; -use style::gecko_bindings::bindings::RawGeckoFontFaceRuleListBorrowedMut; -use style::gecko_bindings::bindings::RawGeckoServoAnimationValueListBorrowedMut; -use style::gecko_bindings::bindings::RawGeckoServoStyleRuleListBorrowedMut; -use style::gecko_bindings::bindings::RawServoAnimationValueBorrowed; -use style::gecko_bindings::bindings::RawServoAnimationValueBorrowedOrNull; -use style::gecko_bindings::bindings::RawServoAnimationValueMapBorrowedMut; -use style::gecko_bindings::bindings::RawServoAnimationValueStrong; -use style::gecko_bindings::bindings::RawServoAnimationValueTableBorrowed; -use style::gecko_bindings::bindings::RawServoDeclarationBlockBorrowedOrNull; -use style::gecko_bindings::bindings::RawServoStyleRuleBorrowed; -use style::gecko_bindings::bindings::RawServoStyleSet; -use style::gecko_bindings::bindings::nsCSSValueBorrowedMut; -use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t; -use style::gecko_bindings::bindings::nsTimingFunctionBorrowed; -use style::gecko_bindings::bindings::nsTimingFunctionBorrowedMut; -use style::gecko_bindings::structs; -use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation}; -use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets}; -use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString}; -use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID}; -use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder}; -use style::gecko_bindings::structs::{nsCSSFontDesc, nsCSSCounterDesc}; -use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair}; -use style::gecko_bindings::structs::AtomArray; -use style::gecko_bindings::structs::IterationCompositeOperation; -use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf; -use style::gecko_bindings::structs::OriginFlags; -use style::gecko_bindings::structs::OriginFlags_Author; -use style::gecko_bindings::structs::OriginFlags_User; -use style::gecko_bindings::structs::OriginFlags_UserAgent; -use style::gecko_bindings::structs::RawGeckoGfxMatrix4x4; -use style::gecko_bindings::structs::RawGeckoPresContextOwned; -use style::gecko_bindings::structs::RawServoFontFaceRule; -use style::gecko_bindings::structs::RawServoSelectorList; -use style::gecko_bindings::structs::RawServoSourceSizeList; -use style::gecko_bindings::structs::SeenPtrs; -use style::gecko_bindings::structs::ServoElementSnapshotTable; -use style::gecko_bindings::structs::ServoStyleSetSizes; -use style::gecko_bindings::structs::ServoTraversalFlags; -use style::gecko_bindings::structs::StyleRuleInclusion; -use style::gecko_bindings::structs::URLExtraData; -use style::gecko_bindings::structs::gfxFontFeatureValueSet; -use style::gecko_bindings::structs::nsCSSValueSharedList; -use style::gecko_bindings::structs::nsCompatibility; -use style::gecko_bindings::structs::nsIDocument; -use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator; -use style::gecko_bindings::structs::nsTArray; -use style::gecko_bindings::structs::nsresult; -use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasFFI, HasArcFFI}; -use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; -use style::gecko_bindings::sugar::refptr::RefPtr; -use style::gecko_properties; -use style::invalidation::element::restyle_hints; -use style::media_queries::{MediaList, parse_media_query_list}; -use style::parser::{Parse, ParserContext, self}; -use style::properties::{ComputedValues, DeclarationSource, Importance}; -use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId}; -use style::properties::{PropertyDeclarationId, ShorthandId}; -use style::properties::{SourcePropertyDeclaration, StyleBuilder}; -use style::properties::{parse_one_declaration_into, parse_style_attribute}; -use style::properties::animated_properties::AnimationValue; -use style::properties::animated_properties::compare_property_priority; -use style::rule_cache::RuleCacheConditions; -use style::rule_tree::{CascadeLevel, StrongRuleNode}; -use style::selector_parser::{PseudoElementCascadeType, SelectorImpl}; -use style::shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard, Locked}; -use style::string_cache::{Atom, WeakAtom}; -use style::style_adjuster::StyleAdjuster; -use style::stylesheets::{CssRule, CssRules, CssRuleType, CssRulesHelpers, CounterStyleRule}; -use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule}; -use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule}; -use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule}; -use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; -use style::stylesheets::import_rule::ImportSheet; -use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue}; -use style::stylesheets::supports_rule::parse_condition_or_declaration; -use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist}; -use style::thread_state; -use style::timer::Timer; -use style::traversal::DomTraversal; -use style::traversal::resolve_style; -use style::traversal_flags::{self, TraversalFlags}; -use style::values::{CustomIdent, KeyframesName}; -use style::values::animated::{Animate, Procedure, ToAnimatedZero}; -use style::values::computed::{Context, ToComputedValue}; -use style::values::distance::ComputeSquaredDistance; -use style::values::generics::rect::Rect; -use style::values::specified; -use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPercentage}; -use style::values::specified::source_size_list::SourceSizeList; -use style_traits::{CssType, CssWriter, ParsingMode, StyleParseErrorKind, ToCss}; -use super::error_reporter::ErrorReporter; -use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader}; - -/* - * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in - * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against - * those signatures as well, giving us a second declaration of all the Servo_* functions in this - * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to - * depend on but good enough for our purposes. - */ - -// A dummy url data for where we don't pass url data in. -// We need to get rid of this sooner than later. -static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut URLExtraData; - -#[no_mangle] -pub extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) { - use style::gecko_bindings::sugar::origin_flags; - - // Pretend that we're a Servo Layout thread, to make some assertions happy. - thread_state::initialize(thread_state::ThreadState::LAYOUT); - - // Perform some debug-only runtime assertions. - restyle_hints::assert_restyle_hints_match(); - origin_flags::assert_flags_match(); - parser::assert_parsing_mode_match(); - traversal_flags::assert_traversal_flags_match(); - specified::font::assert_variant_east_asian_matches(); - specified::font::assert_variant_ligatures_matches(); - specified::box_::assert_touch_action_matches(); - - // Initialize the dummy url data - unsafe { DUMMY_URL_DATA = dummy_url_data; } -} - -#[no_mangle] -pub extern "C" fn Servo_InitializeCooperativeThread() { - // Pretend that we're a Servo Layout thread to make some assertions happy. - thread_state::initialize(thread_state::ThreadState::LAYOUT); -} - -#[no_mangle] -pub extern "C" fn Servo_Shutdown() { - // The dummy url will be released after shutdown, so clear the - // reference to avoid use-after-free. - unsafe { DUMMY_URL_DATA = ptr::null_mut(); } - Stylist::shutdown(); -} - -unsafe fn dummy_url_data() -> &'static RefPtr { - RefPtr::from_ptr_ref(&DUMMY_URL_DATA) -} - -#[allow(dead_code)] -fn is_main_thread() -> bool { - unsafe { bindings::Gecko_IsMainThread() } -} - -#[allow(dead_code)] -fn is_in_servo_traversal() -> bool { - unsafe { bindings::Gecko_IsInServoTraversal() } -} - -fn create_shared_context<'a>( - global_style_data: &GlobalStyleData, - guard: &'a SharedRwLockReadGuard, - per_doc_data: &'a PerDocumentStyleDataImpl, - traversal_flags: TraversalFlags, - snapshot_map: &'a ServoElementSnapshotTable, -) -> SharedStyleContext<'a> { - SharedStyleContext { - stylist: &per_doc_data.stylist, - visited_styles_enabled: per_doc_data.visited_styles_enabled(), - options: global_style_data.options.clone(), - guards: StylesheetGuards::same(guard), - timer: Timer::new(), - traversal_flags, - snapshot_map, - } -} - -fn traverse_subtree( - element: GeckoElement, - global_style_data: &GlobalStyleData, - per_doc_data: &PerDocumentStyleDataImpl, - guard: &SharedRwLockReadGuard, - traversal_flags: TraversalFlags, - snapshots: &ServoElementSnapshotTable, -) { - let shared_style_context = create_shared_context( - &global_style_data, - &guard, - &per_doc_data, - traversal_flags, - snapshots, - ); - - let token = RecalcStyleOnly::pre_traverse( - element, - &shared_style_context, - ); - - if !token.should_traverse() { - return; - } - - debug!("Traversing subtree from {:?}", element); - - let thread_pool_holder = &*STYLE_THREAD_POOL; - let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) { - thread_pool_holder.style_thread_pool.as_ref() - } else { - None - }; - - let traversal = RecalcStyleOnly::new(shared_style_context); - driver::traverse_dom(&traversal, token, thread_pool); -} - -/// Traverses the subtree rooted at `root` for restyling. -/// -/// Returns whether the root was restyled. Whether anything else was restyled or -/// not can be inferred from the dirty bits in the rest of the tree. -#[no_mangle] -pub extern "C" fn Servo_TraverseSubtree( - root: RawGeckoElementBorrowed, - raw_data: RawServoStyleSetBorrowed, - snapshots: *const ServoElementSnapshotTable, - raw_flags: ServoTraversalFlags -) -> bool { - let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags); - debug_assert!(!snapshots.is_null()); - - let element = GeckoElement(root); - - debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags); - debug!("{:?}", ShowSubtreeData(element.as_node())); - - if cfg!(debug_assertions) { - if let Some(parent) = element.traversal_parent() { - let data = - parent.borrow_data().expect("Styling element with unstyled parent"); - assert!( - !data.styles.is_display_none(), - "Styling element with display: none parent" - ); - } - } - - let needs_animation_only_restyle = - element.has_animation_only_dirty_descendants() || - element.has_animation_restyle_hints(); - - let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - debug_assert!(!per_doc_data.stylist.stylesheets_have_changed()); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - let was_initial_style = element.get_data().is_none(); - - if needs_animation_only_restyle { - debug!("Servo_TraverseSubtree doing animation-only restyle (aodd={})", - element.has_animation_only_dirty_descendants()); - traverse_subtree( - element, - &global_style_data, - &per_doc_data, - &guard, - traversal_flags | TraversalFlags::AnimationOnly, - unsafe { &*snapshots }, - ); - } - - traverse_subtree( - element, - &global_style_data, - &per_doc_data, - &guard, - traversal_flags, - unsafe { &*snapshots }, - ); - - debug!("Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})", - element.has_dirty_descendants(), - element.has_animation_only_dirty_descendants(), - element.descendants_need_frames(), - element.needs_frame(), - element.borrow_data().unwrap()); - - if was_initial_style { - debug_assert!(!element.borrow_data().unwrap().contains_restyle_data()); - false - } else { - let element_was_restyled = - element.borrow_data().unwrap().contains_restyle_data(); - element_was_restyled - } -} - -/// Checks whether the rule tree has crossed its threshold for unused nodes, and -/// if so, frees them. -#[no_mangle] -pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: RawServoStyleSetBorrowed) { - let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - unsafe { - per_doc_data.stylist.rule_tree().maybe_gc(); - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_Interpolate( - from: RawServoAnimationValueBorrowed, - to: RawServoAnimationValueBorrowed, - progress: f64, -) -> RawServoAnimationValueStrong { - let from_value = AnimationValue::as_arc(&from); - let to_value = AnimationValue::as_arc(&to); - if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) { - Arc::new(value).into_strong() - } else { - RawServoAnimationValueStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_IsInterpolable( - from: RawServoAnimationValueBorrowed, - to: RawServoAnimationValueBorrowed, -) -> bool { - let from_value = AnimationValue::as_arc(&from); - let to_value = AnimationValue::as_arc(&to); - from_value.animate(to_value, Procedure::Interpolate { progress: 0.5 }).is_ok() -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_Add( - a: RawServoAnimationValueBorrowed, - b: RawServoAnimationValueBorrowed, -) -> RawServoAnimationValueStrong { - let a_value = AnimationValue::as_arc(&a); - let b_value = AnimationValue::as_arc(&b); - if let Ok(value) = a_value.animate(b_value, Procedure::Add) { - Arc::new(value).into_strong() - } else { - RawServoAnimationValueStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_Accumulate( - a: RawServoAnimationValueBorrowed, - b: RawServoAnimationValueBorrowed, - count: u64, -) -> RawServoAnimationValueStrong { - let a_value = AnimationValue::as_arc(&a); - let b_value = AnimationValue::as_arc(&b); - if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) { - Arc::new(value).into_strong() - } else { - RawServoAnimationValueStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_GetZeroValue( - value_to_match: RawServoAnimationValueBorrowed, -) -> RawServoAnimationValueStrong { - let value_to_match = AnimationValue::as_arc(&value_to_match); - if let Ok(zero_value) = value_to_match.to_animated_zero() { - Arc::new(zero_value).into_strong() - } else { - RawServoAnimationValueStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValues_ComputeDistance( - from: RawServoAnimationValueBorrowed, - to: RawServoAnimationValueBorrowed, -) -> f64 { - let from_value = AnimationValue::as_arc(&from); - let to_value = AnimationValue::as_arc(&to); - // If compute_squared_distance() failed, this function will return negative value - // in order to check whether we support the specified paced animation values. - from_value.compute_squared_distance(to_value).map(|d| d.sqrt()).unwrap_or(-1.0) -} - -/// Compute one of the endpoints for the interpolation interval, compositing it with the -/// underlying value if needed. -/// An None returned value means, "Just use endpoint_value as-is." -/// It is the responsibility of the caller to ensure that |underlying_value| is provided -/// when it will be used. -fn composite_endpoint( - endpoint_value: Option<&RawOffsetArc>, - composite: CompositeOperation, - underlying_value: Option<&AnimationValue>, -) -> Option { - match endpoint_value { - Some(endpoint_value) => { - match composite { - CompositeOperation::Add => { - underlying_value - .expect("We should have an underlying_value") - .animate(endpoint_value, Procedure::Add).ok() - }, - CompositeOperation::Accumulate => { - underlying_value - .expect("We should have an underlying value") - .animate(endpoint_value, Procedure::Accumulate { count: 1 }) - .ok() - }, - _ => None, - } - }, - None => underlying_value.map(|v| v.clone()), - } -} - -/// Accumulate one of the endpoints of the animation interval. -/// A returned value of None means, "Just use endpoint_value as-is." -fn accumulate_endpoint( - endpoint_value: Option<&RawOffsetArc>, - composited_value: Option, - last_value: &AnimationValue, - current_iteration: u64 -) -> Option { - debug_assert!(endpoint_value.is_some() || composited_value.is_some(), - "Should have a suitable value to use"); - - let count = current_iteration; - match composited_value { - Some(endpoint) => { - last_value - .animate(&endpoint, Procedure::Accumulate { count }) - .ok() - .or(Some(endpoint)) - }, - None => { - last_value - .animate(endpoint_value.unwrap(), Procedure::Accumulate { count }) - .ok() - }, - } -} - -/// Compose the animation segment. We composite it with the underlying_value and last_value if -/// needed. -/// The caller is responsible for providing an underlying value and last value -/// in all situations where there are needed. -fn compose_animation_segment( - segment: RawGeckoAnimationPropertySegmentBorrowed, - underlying_value: Option<&AnimationValue>, - last_value: Option<&AnimationValue>, - iteration_composite: IterationCompositeOperation, - current_iteration: u64, - total_progress: f64, - segment_progress: f64, -) -> AnimationValue { - // Extract keyframe values. - let raw_from_value; - let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() { - raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr }; - Some(AnimationValue::as_arc(&raw_from_value)) - } else { - None - }; - - let raw_to_value; - let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() { - raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr }; - Some(AnimationValue::as_arc(&raw_to_value)) - } else { - None - }; - - let mut composited_from_value = composite_endpoint(keyframe_from_value, - segment.mFromComposite, - underlying_value); - let mut composited_to_value = composite_endpoint(keyframe_to_value, - segment.mToComposite, - underlying_value); - - debug_assert!(keyframe_from_value.is_some() || composited_from_value.is_some(), - "Should have a suitable from value to use"); - debug_assert!(keyframe_to_value.is_some() || composited_to_value.is_some(), - "Should have a suitable to value to use"); - - // Apply iteration composite behavior. - if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 { - let last_value = last_value.unwrap_or_else(|| { - underlying_value.expect("Should have a valid underlying value") - }); - - composited_from_value = accumulate_endpoint(keyframe_from_value, - composited_from_value, - last_value, - current_iteration); - composited_to_value = accumulate_endpoint(keyframe_to_value, - composited_to_value, - last_value, - current_iteration); - } - - // Use the composited value if there is one, otherwise, use the original keyframe value. - let from = composited_from_value.as_ref().unwrap_or_else(|| keyframe_from_value.unwrap()); - let to = composited_to_value.as_ref().unwrap_or_else(|| keyframe_to_value.unwrap()); - - if segment.mToKey == segment.mFromKey { - return if total_progress < 0. { from.clone() } else { to.clone() }; - } - - match from.animate(to, Procedure::Interpolate { progress: segment_progress }) { - Ok(value) => value, - _ => if segment_progress < 0.5 { from.clone() } else { to.clone() }, - } -} - -#[no_mangle] -pub extern "C" fn Servo_ComposeAnimationSegment( - segment: RawGeckoAnimationPropertySegmentBorrowed, - underlying_value: RawServoAnimationValueBorrowedOrNull, - last_value: RawServoAnimationValueBorrowedOrNull, - iteration_composite: IterationCompositeOperation, - progress: f64, - current_iteration: u64 -) -> RawServoAnimationValueStrong { - let underlying_value = AnimationValue::arc_from_borrowed(&underlying_value).map(|v| &**v); - let last_value = AnimationValue::arc_from_borrowed(&last_value).map(|v| &**v); - let result = compose_animation_segment( - segment, - underlying_value, - last_value, - iteration_composite, - current_iteration, - progress, - progress, - ); - Arc::new(result).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationCompose( - raw_value_map: RawServoAnimationValueMapBorrowedMut, - base_values: RawServoAnimationValueTableBorrowed, - css_property: nsCSSPropertyID, - segment: RawGeckoAnimationPropertySegmentBorrowed, - last_segment: RawGeckoAnimationPropertySegmentBorrowed, - computed_timing: RawGeckoComputedTimingBorrowed, - iteration_composite: IterationCompositeOperation, -) { - use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle; - use style::gecko_bindings::bindings::Gecko_GetPositionInSegment; - use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming; - use style::properties::animated_properties::AnimationValueMap; - - let property = match LonghandId::from_nscsspropertyid(css_property) { - Ok(longhand) if longhand.is_animatable() => longhand, - _ => return, - }; - let value_map = AnimationValueMap::from_ffi_mut(raw_value_map); - - // We will need an underlying value if either of the endpoints is null... - let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() || - segment.mToValue.mServo.mRawPtr.is_null() || - // ... or if they have a non-replace composite mode ... - segment.mFromComposite != CompositeOperation::Replace || - segment.mToComposite != CompositeOperation::Replace || - // ... or if we accumulate onto the last value and it is null. - (iteration_composite == IterationCompositeOperation::Accumulate && - computed_timing.mCurrentIteration > 0 && - last_segment.mToValue.mServo.mRawPtr.is_null()); - - // If either of the segment endpoints are null, get the underlying value to - // use from the current value in the values map (set by a lower-priority - // effect), or, if there is no current value, look up the cached base value - // for this property. - let underlying_value = if need_underlying_value { - let previous_composed_value = value_map.get(&property).cloned(); - previous_composed_value.or_else(|| { - let raw_base_style = unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property) }; - AnimationValue::arc_from_borrowed(&raw_base_style).map(|v| &**v).cloned() - }) - } else { - None - }; - - if need_underlying_value && underlying_value.is_none() { - warn!("Underlying value should be valid when we expect to use it"); - return; - } - - let raw_last_value; - let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() { - raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr }; - Some(&**AnimationValue::as_arc(&raw_last_value)) - } else { - None - }; - - let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) }; - let position = if segment.mToKey == segment.mFromKey { - // Note: compose_animation_segment doesn't use this value - // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine. - progress - } else { - unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) } - }; - - let result = compose_animation_segment( - segment, - underlying_value.as_ref(), - last_value, - iteration_composite, - computed_timing.mCurrentIteration, - progress, - position, - ); - value_map.insert(property, result); -} - -macro_rules! get_property_id_from_nscsspropertyid { - ($property_id: ident, $ret: expr) => {{ - match PropertyId::from_nscsspropertyid($property_id) { - Ok(property_id) => property_id, - Err(()) => { return $ret; } - } - }} -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_Serialize( - value: RawServoAnimationValueBorrowed, - property: nsCSSPropertyID, - buffer: *mut nsAString, -) { - let uncomputed_value = AnimationValue::as_arc(&value).uncompute(); - let buffer = unsafe { buffer.as_mut().unwrap() }; - let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal) - .single_value_to_css(&get_property_id_from_nscsspropertyid!(property, ()), buffer, - None, None /* No extra custom properties */); - debug_assert!(rv.is_ok()); -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_GetOpacity( - value: RawServoAnimationValueBorrowed, -) -> f32 { - let value = AnimationValue::as_arc(&value); - if let AnimationValue::Opacity(opacity) = **value { - opacity - } else { - panic!("The AnimationValue should be Opacity"); - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_Opacity( - opacity: f32 -) -> RawServoAnimationValueStrong { - Arc::new(AnimationValue::Opacity(opacity)).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_GetTransform( - value: RawServoAnimationValueBorrowed, - list: *mut structs::RefPtr -) { - let value = AnimationValue::as_arc(&value); - if let AnimationValue::Transform(ref servo_list) = **value { - let list = unsafe { &mut *list }; - if servo_list.0.is_empty() { - unsafe { - list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform())); - } - } else { - gecko_properties::convert_transform(&servo_list.0, list); - } - } else { - panic!("The AnimationValue should be transform"); - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_Transform( - list: *const nsCSSValueSharedList -) -> RawServoAnimationValueStrong { - let list = unsafe { (&*list).mHead.as_ref() }; - let transform = gecko_properties::clone_transform_from_list(list); - Arc::new(AnimationValue::Transform(transform)).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_DeepEqual( - this: RawServoAnimationValueBorrowed, - other: RawServoAnimationValueBorrowed, -) -> bool { - let this_value = AnimationValue::as_arc(&this); - let other_value = AnimationValue::as_arc(&other); - this_value == other_value -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_Uncompute( - value: RawServoAnimationValueBorrowed, -) -> RawServoDeclarationBlockStrong { - let value = AnimationValue::as_arc(&value); - let global_style_data = &*GLOBAL_STYLE_DATA; - Arc::new(global_style_data.shared_lock.wrap( - PropertyDeclarationBlock::with_one(value.uncompute(), Importance::Normal))).into_strong() -} - -// Return the ComputedValues by a base ComputedValues and the rules. -fn resolve_rules_for_element_with_context<'a>( - element: GeckoElement<'a>, - mut context: StyleContext>, - rules: StrongRuleNode -) -> Arc { - use style::style_resolver::{PseudoElementResolution, StyleResolverForElement}; - - // This currently ignores visited styles, which seems acceptable, as - // existing browsers don't appear to animate visited styles. - let inputs = - CascadeInputs { - rules: Some(rules), - visited_rules: None, - }; - - // Actually `PseudoElementResolution` doesn't matter. - StyleResolverForElement::new(element, - &mut context, - RuleInclusion::All, - PseudoElementResolution::IfApplicable) - .cascade_style_and_visited_with_default_parents(inputs).0 -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement( - raw_style_set: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - computed_values: ComputedStyleBorrowed, - snapshots: *const ServoElementSnapshotTable, -) -> ComputedStyleStrong { - debug_assert!(!snapshots.is_null()); - let computed_values = unsafe { ArcBorrow::from_ref(computed_values) }; - - let rules = match computed_values.rules { - None => return computed_values.clone_arc().into(), - Some(ref rules) => rules, - }; - - let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow(); - let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules); - if without_animations_rules == *rules { - return computed_values.clone_arc().into(); - } - - let element = GeckoElement(element); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let shared = create_shared_context(&global_style_data, - &guard, - &doc_data, - TraversalFlags::empty(), - unsafe { &*snapshots }); - let mut tlc = ThreadLocalStyleContext::new(&shared); - let context = StyleContext { - shared: &shared, - thread_local: &mut tlc, - }; - - resolve_rules_for_element_with_context(element, context, without_animations_rules).into() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_GetComputedValuesByAddingAnimation( - raw_style_set: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - computed_values: ComputedStyleBorrowed, - snapshots: *const ServoElementSnapshotTable, - animation_value: RawServoAnimationValueBorrowed, -) -> ComputedStyleStrong { - debug_assert!(!snapshots.is_null()); - let computed_values = unsafe { ArcBorrow::from_ref(computed_values) }; - let rules = match computed_values.rules { - None => return ComputedStyleStrong::null(), - Some(ref rules) => rules, - }; - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let uncomputed_value = AnimationValue::as_arc(&animation_value).uncompute(); - let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow(); - - let with_animations_rules = { - let guards = StylesheetGuards::same(&guard); - let declarations = - Arc::new(global_style_data.shared_lock.wrap( - PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal))); - doc_data.stylist - .rule_tree() - .add_animation_rules_at_transition_level(rules, declarations, &guards) - }; - - let element = GeckoElement(element); - if element.borrow_data().is_none() { - return ComputedStyleStrong::null(); - } - - let shared = create_shared_context(&global_style_data, - &guard, - &doc_data, - TraversalFlags::empty(), - unsafe { &*snapshots }); - let mut tlc: ThreadLocalStyleContext = ThreadLocalStyleContext::new(&shared); - let context = StyleContext { - shared: &shared, - thread_local: &mut tlc, - }; - - resolve_rules_for_element_with_context(element, context, with_animations_rules).into() -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue( - computed_values: ComputedStyleBorrowed, - property_id: nsCSSPropertyID, -) -> RawServoAnimationValueStrong { - let property = match LonghandId::from_nscsspropertyid(property_id) { - Ok(longhand) => longhand, - Err(()) => return Strong::null(), - }; - - match AnimationValue::from_computed_values(property, &computed_values) { - Some(v) => Arc::new(v).into_strong(), - None => Strong::null(), - } -} - -macro_rules! parse_enabled_property_name { - ($prop_name:ident, $found:ident, $default:expr) => {{ - let prop_name = $prop_name.as_ref().unwrap().as_str_unchecked(); - // XXX This can be simplified once Option::filter is stable. - let prop_id = PropertyId::parse(prop_name).ok().and_then(|p| { - if p.enabled_for_all_content() { - Some(p) - } else { - None - } - }); - match prop_id { - Some(p) => { - *$found = true; - p - } - None => { - *$found = false; - return $default; - } - } - }} -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_Property_IsShorthand( - prop_name: *const nsACString, - found: *mut bool -) -> bool { - let prop_id = parse_enabled_property_name!(prop_name, found, false); - prop_id.is_shorthand() -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_Property_IsInherited( - prop_name: *const nsACString, -) -> bool { - let prop_name = prop_name.as_ref().unwrap().as_str_unchecked(); - let prop_id = match PropertyId::parse(prop_name) { - Ok(id) => id, - Err(_) => return false, - }; - let longhand_id = match prop_id { - PropertyId::Custom(_) => return true, - PropertyId::Longhand(id) | - PropertyId::LonghandAlias(id, _) => id, - PropertyId::Shorthand(id) | - PropertyId::ShorthandAlias(id, _) => id.longhands().next().unwrap(), - }; - longhand_id.inherited() -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_Property_SupportsType( - prop_name: *const nsACString, - ty: u32, - found: *mut bool, -) -> bool { - let prop_id = parse_enabled_property_name!(prop_name, found, false); - // This should match the constants in InspectorUtils. - // (Let's don't bother importing InspectorUtilsBinding into bindings - // because it is not used anywhere else, and issue here would be - // caught by the property-db test anyway.) - let ty = match ty { - 1 => CssType::COLOR, - 2 => CssType::GRADIENT, - 3 => CssType::TIMING_FUNCTION, - _ => unreachable!("unknown CSS type {}", ty), - }; - prop_id.supports_type(ty) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty( - prop_name: *const nsACString, - found: *mut bool, - result: *mut nsTArray, -) { - let prop_id = parse_enabled_property_name!(prop_name, found, ()); - // Use B-tree set for unique and sorted result. - let mut values = BTreeSet::<&'static str>::new(); - prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter())); - - let mut extras = vec![]; - if values.contains("transparent") { - // This is a special value devtools use to avoid inserting the - // long list of color keywords. We need to prepend it to values. - extras.push("COLOR"); - } - - let result = result.as_mut().unwrap(); - let len = extras.len() + values.len(); - bindings::Gecko_ResizeTArrayForStrings(result, len as u32); - - for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) { - dest.write_str(src).unwrap(); - } -} - -#[no_mangle] -pub extern "C" fn Servo_Property_IsAnimatable(property: nsCSSPropertyID) -> bool { - use style::properties::animated_properties; - animated_properties::nscsspropertyid_is_animatable(property) -} - -#[no_mangle] -pub extern "C" fn Servo_Property_IsTransitionable(property: nsCSSPropertyID) -> bool { - use style::properties::animated_properties; - animated_properties::nscsspropertyid_is_transitionable(property) -} - -#[no_mangle] -pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool { - match LonghandId::from_nscsspropertyid(property) { - Ok(longhand) => longhand.is_discrete_animatable(), - Err(()) => return false, - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleWorkerThreadCount() -> u32 { - STYLE_THREAD_POOL.num_threads as u32 -} - -#[no_mangle] -pub extern "C" fn Servo_Element_ClearData(element: RawGeckoElementBorrowed) { - unsafe { GeckoElement(element).clear_data() }; -} - -#[no_mangle] -pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs( - malloc_size_of: GeckoMallocSizeOf, - malloc_enclosing_size_of: GeckoMallocSizeOf, - seen_ptrs: *mut SeenPtrs, - element: RawGeckoElementBorrowed, -) -> usize { - let element = GeckoElement(element); - let borrow = element.borrow_data(); - if let Some(data) = borrow { - let have_seen_ptr = move |ptr| { unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) } }; - let mut ops = MallocSizeOfOps::new( - malloc_size_of.unwrap(), - Some(malloc_enclosing_size_of.unwrap()), - Some(Box::new(have_seen_ptr)), - ); - (*data).size_of_excluding_cvs(&mut ops) - } else { - 0 - } -} - -#[no_mangle] -pub extern "C" fn Servo_Element_HasPrimaryComputedValues(element: RawGeckoElementBorrowed) -> bool -{ - let element = GeckoElement(element); - let data = element.borrow_data().expect("Looking for CVs on unstyled element"); - data.has_styles() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_GetPrimaryComputedValues( - element: RawGeckoElementBorrowed, -) -> ComputedStyleStrong { - let element = GeckoElement(element); - let data = element.borrow_data().expect("Getting CVs on unstyled element"); - data.styles.primary().clone().into() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_HasPseudoComputedValues( - element: RawGeckoElementBorrowed, - index: usize, -) -> bool { - let element = GeckoElement(element); - let data = element.borrow_data().expect("Looking for CVs on unstyled element"); - data.styles.pseudos.as_array()[index].is_some() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_GetPseudoComputedValues( - element: RawGeckoElementBorrowed, - index: usize, -) -> ComputedStyleStrong { - let element = GeckoElement(element); - let data = element.borrow_data().expect("Getting CVs that aren't present"); - data.styles.pseudos.as_array()[index].as_ref().expect("Getting CVs that aren't present") - .clone().into() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_IsDisplayNone( - element: RawGeckoElementBorrowed, -) -> bool { - let element = GeckoElement(element); - let data = element.get_data() - .expect("Invoking Servo_Element_IsDisplayNone on unstyled element"); - - // This function is hot, so we bypass the AtomicRefCell. - // - // It would be nice to also assert that we're not in the servo traversal, - // but this function is called at various intermediate checkpoints when - // managing the traversal on the Gecko side. - debug_assert!(is_main_thread()); - unsafe { &*data.as_ptr() }.styles.is_display_none() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_IsDisplayContents( - element: RawGeckoElementBorrowed, -) -> bool { - let element = GeckoElement(element); - let data = element.get_data() - .expect("Invoking Servo_Element_IsDisplayContents on unstyled element"); - - debug_assert!(is_main_thread()); - unsafe { &*data.as_ptr() }.styles.primary().get_box().clone_display().is_contents() -} - -#[no_mangle] -pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: RawGeckoElementBorrowed) -> bool { - let element = GeckoElement(element); - let data = element.borrow_data() - .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element"); - data.flags.contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetContentsStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let origin = match mode { - SheetParsingMode::eAuthorSheetFeatures => Origin::Author, - SheetParsingMode::eUserSheetFeatures => Origin::User, - SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, - SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent, - }; - let shared_lock = &global_style_data.shared_lock; - Arc::new( - StylesheetContents::from_str( - "", - unsafe { dummy_url_data() }.clone(), - origin, - shared_lock, - /* loader = */ None, - &NullReporter, - QuirksMode::NoQuirks, - 0 - ) - ).into_strong() -} - -fn mode_to_origin(mode: SheetParsingMode) -> Origin { - match mode { - SheetParsingMode::eAuthorSheetFeatures => Origin::Author, - SheetParsingMode::eUserSheetFeatures => Origin::User, - SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, - SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent, - } -} - -/// Note: The load_data corresponds to this sheet, and is passed as the parent -/// load data for child sheet loads. It may be null for certain cases where we -/// know we won't have child loads. -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes( - loader: *mut Loader, - stylesheet: *mut DomStyleSheet, - load_data: *mut SheetLoadData, - bytes: *const nsACString, - mode: SheetParsingMode, - extra_data: *mut URLExtraData, - line_number_offset: u32, - quirks_mode: nsCompatibility, - reusable_sheets: *mut LoaderReusableStyleSheets, -) -> RawServoStyleSheetContentsStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let input: &str = unsafe { (*bytes).as_str_unchecked() }; - - let reporter = ErrorReporter::new(stylesheet, loader, extra_data); - let url_data = unsafe { RefPtr::from_ptr_ref(&extra_data) }; - let loader = if loader.is_null() { - None - } else { - Some(StylesheetLoader::new(loader, stylesheet, load_data, reusable_sheets)) - }; - - // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason? - let loader: Option<&StyleStylesheetLoader> = match loader { - None => None, - Some(ref s) => Some(s), - }; - - - Arc::new(StylesheetContents::from_str( - input, url_data.clone(), mode_to_origin(mode), - &global_style_data.shared_lock, loader, &reporter, - quirks_mode.into(), line_number_offset) - ).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync( - load_data: *mut SheetLoadDataHolder, - extra_data: *mut URLExtraData, - bytes: *const nsACString, - mode: SheetParsingMode, - line_number_offset: u32, - quirks_mode: nsCompatibility, -) { - let (load_data, extra_data, bytes) = unsafe { - let mut b = nsCString::new(); - b.assign(&*bytes); - (RefPtr::new(load_data), RefPtr::new(extra_data), b) - }; - let async_parser = AsyncStylesheetParser::new( - load_data, - extra_data, - bytes, - mode_to_origin(mode), - quirks_mode.into(), - line_number_offset - ); - - if let Some(thread_pool) = STYLE_THREAD_POOL.style_thread_pool.as_ref() { - thread_pool.spawn(|| { - async_parser.parse(); - }); - } else { - async_parser.parse(); - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_AppendStyleSheet( - raw_data: RawServoStyleSetBorrowed, - sheet: *const DomStyleSheet, -) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let data = &mut *data; - let guard = global_style_data.shared_lock.read(); - let sheet = unsafe { GeckoStyleSheet::new(sheet) }; - data.stylist.append_stylesheet(sheet, &guard); -} - -#[no_mangle] -pub extern "C" fn Servo_AuthorStyles_Create() -> *mut RawServoAuthorStyles { - Box::into_raw(Box::new(AuthorStyles::::new())) as *mut _ -} - -#[no_mangle] -pub extern "C" fn Servo_AuthorStyles_Drop( - styles: RawServoAuthorStylesOwned, -) { - let _ = styles.into_box::>(); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet( - styles: RawServoAuthorStylesBorrowedMut, - sheet: *const DomStyleSheet, -) { - let styles = AuthorStyles::::from_ffi_mut(styles); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let sheet = GeckoStyleSheet::new(sheet); - styles.stylesheets.append_stylesheet(None, sheet, &guard); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore( - styles: RawServoAuthorStylesBorrowedMut, - sheet: *const DomStyleSheet, - before_sheet: *const DomStyleSheet, -) { - let styles = AuthorStyles::::from_ffi_mut(styles); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - styles.stylesheets.insert_stylesheet_before( - None, - GeckoStyleSheet::new(sheet), - GeckoStyleSheet::new(before_sheet), - &guard, - ); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet( - styles: RawServoAuthorStylesBorrowedMut, - sheet: *const DomStyleSheet, -) { - let styles = AuthorStyles::::from_ffi_mut(styles); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - styles.stylesheets.remove_stylesheet( - None, - GeckoStyleSheet::new(sheet), - &guard, - ); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_ForceDirty( - styles: RawServoAuthorStylesBorrowedMut, -) { - let styles = AuthorStyles::::from_ffi_mut(styles); - styles.stylesheets.force_dirty(); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_Flush( - styles: RawServoAuthorStylesBorrowedMut, - document_set: RawServoStyleSetBorrowed, -) { - let styles = AuthorStyles::::from_ffi_mut(styles); - // Try to avoid the atomic borrow below if possible. - if !styles.stylesheets.dirty() { - return; - } - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - let document_data = - PerDocumentStyleData::from_ffi(document_set).borrow(); - - let stylist = &document_data.stylist; - - // TODO(emilio): This is going to need an element or something to do proper - // invalidation in Shadow roots. - styles.flush::( - stylist.device(), - stylist.quirks_mode(), - &guard, - ); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis( - malloc_size_of: GeckoMallocSizeOf, - malloc_enclosing_size_of: GeckoMallocSizeOf, - styles: RawServoAuthorStylesBorrowed, -) -> usize { - // We cannot `use` MallocSizeOf at the top level, otherwise the compiler - // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of` - // there. - use malloc_size_of::MallocSizeOf; - let malloc_size_of = malloc_size_of.unwrap(); - let malloc_size_of_this = malloc_size_of(styles as *const RawServoAuthorStyles as *const c_void); - - let styles = AuthorStyles::::from_ffi(styles); - let mut ops = MallocSizeOfOps::new(malloc_size_of, - Some(malloc_enclosing_size_of.unwrap()), - None); - malloc_size_of_this + styles.size_of(&mut ops) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged( - document_set: RawServoStyleSetBorrowed, - non_document_styles: *mut nsTArray, - may_affect_default_style: bool, -) -> structs::MediumFeaturesChangedResult { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - // NOTE(emilio): We don't actually need to flush the stylist here and ensure - // it's up to date. - // - // In case it isn't we would trigger a rebuild + restyle as needed too. - // - // We need to ensure the default computed values are up to date though, - // because those can influence the result of media query evaluation. - let mut document_data = - PerDocumentStyleData::from_ffi(document_set).borrow_mut(); - - if may_affect_default_style { - document_data.stylist.device_mut().reset_computed_values(); - } - let guards = StylesheetGuards::same(&guard); - - let origins_in_which_rules_changed = - document_data.stylist.media_features_change_changed_style( - &guards, - document_data.stylist.device(), - ); - - let affects_document_rules = !origins_in_which_rules_changed.is_empty(); - if affects_document_rules { - document_data.stylist.force_stylesheet_origins_dirty(origins_in_which_rules_changed); - } - - let mut affects_non_document_rules = false; - for author_styles in &mut **non_document_styles { - let author_styles = - AuthorStyles::::from_ffi_mut(&mut *author_styles); - let affected_style = author_styles.stylesheets.iter().any(|sheet| { - !author_styles.data.media_feature_affected_matches( - sheet, - &guards.author, - document_data.stylist.device(), - document_data.stylist.quirks_mode(), - ) - }); - if affected_style { - affects_non_document_rules = true; - author_styles.stylesheets.force_dirty(); - } - } - - let uses_viewport_units = - document_data.stylist.device().used_viewport_size(); - - structs::MediumFeaturesChangedResult { - mAffectsDocumentRules: affects_document_rules, - mAffectsNonDocumentRules: affects_non_document_rules, - mUsesViewportUnits: uses_viewport_units, - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_PrependStyleSheet( - raw_data: RawServoStyleSetBorrowed, - sheet: *const DomStyleSheet, -) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let data = &mut *data; - let guard = global_style_data.shared_lock.read(); - let sheet = unsafe { GeckoStyleSheet::new(sheet) }; - data.stylist.prepend_stylesheet(sheet, &guard); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore( - raw_data: RawServoStyleSetBorrowed, - sheet: *const DomStyleSheet, - before_sheet: *const DomStyleSheet -) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let data = &mut *data; - let guard = global_style_data.shared_lock.read(); - let sheet = unsafe { GeckoStyleSheet::new(sheet) }; - data.stylist.insert_stylesheet_before( - sheet, - unsafe { GeckoStyleSheet::new(before_sheet) }, - &guard, - ); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_RemoveStyleSheet( - raw_data: RawServoStyleSetBorrowed, - sheet: *const DomStyleSheet -) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let data = &mut *data; - let guard = global_style_data.shared_lock.read(); - let sheet = unsafe { GeckoStyleSheet::new(sheet) }; - data.stylist.remove_stylesheet(sheet, &guard); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets( - raw_data: RawServoStyleSetBorrowed, - doc_element: RawGeckoElementBorrowedOrNull, - snapshots: *const ServoElementSnapshotTable, -) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let doc_element = doc_element.map(GeckoElement); - - let have_invalidations = - data.flush_stylesheets(&guard, doc_element, snapshots.as_ref()); - - if have_invalidations && doc_element.is_some() { - // The invalidation machinery propagates the bits up, but we still need - // to tell the Gecko restyle root machinery about it. - bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0); - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged( - raw_data: RawServoStyleSetBorrowed, - changed_origins: OriginFlags, -) { - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.stylist.force_stylesheet_origins_dirty(OriginSet::from(changed_origins)); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled( - raw_data: RawServoStyleSetBorrowed, - author_style_disabled: bool, -) { - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let enabled = - if author_style_disabled { - AuthorStylesEnabled::No - } else { - AuthorStylesEnabled::Yes - }; - data.stylist.set_author_styles_enabled(enabled); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_HasRules( - raw_contents: RawServoStyleSheetContentsBorrowed -) -> bool { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - !StylesheetContents::as_arc(&raw_contents) - .rules.read_with(&guard).0.is_empty() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_GetRules( - sheet: RawServoStyleSheetContentsBorrowed -) -> ServoCssRulesStrong { - StylesheetContents::as_arc(&sheet).rules.clone().into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_Clone( - raw_sheet: RawServoStyleSheetContentsBorrowed, - reference_sheet: *const DomStyleSheet, -) -> RawServoStyleSheetContentsStrong { - use style::shared_lock::{DeepCloneParams, DeepCloneWithLock}; - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let contents = StylesheetContents::as_arc(&raw_sheet); - let params = DeepCloneParams { reference_sheet }; - - Arc::new(contents.deep_clone_with_lock( - &global_style_data.shared_lock, - &guard, - ¶ms, - )).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis( - malloc_size_of: GeckoMallocSizeOf, - malloc_enclosing_size_of: GeckoMallocSizeOf, - sheet: RawServoStyleSheetContentsBorrowed -) -> usize { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), - Some(malloc_enclosing_size_of.unwrap()), - None); - StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_GetOrigin( - sheet: RawServoStyleSheetContentsBorrowed, -) -> u8 { - let origin = match StylesheetContents::as_arc(&sheet).origin { - Origin::UserAgent => OriginFlags_UserAgent, - Origin::User => OriginFlags_User, - Origin::Author => OriginFlags_Author, - }; - // We'd like to return `OriginFlags` here, but bindgen bitfield enums don't - // work as return values with the Linux 32-bit ABI at the moment because - // they wrap the value in a struct, so for now just unwrap it. - origin.0 -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_GetSourceMapURL( - sheet: RawServoStyleSheetContentsBorrowed, - result: *mut nsAString -) { - let contents = StylesheetContents::as_arc(&sheet); - let url_opt = contents.source_map_url.read(); - if let Some(ref url) = *url_opt { - write!(unsafe { &mut *result }, "{}", url).unwrap(); - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSheet_GetSourceURL( - sheet: RawServoStyleSheetContentsBorrowed, - result: *mut nsAString -) { - let contents = StylesheetContents::as_arc(&sheet); - let url_opt = contents.source_url.read(); - if let Some(ref url) = *url_opt { - write!(unsafe { &mut *result }, "{}", url).unwrap(); - } -} - -fn read_locked_arc(raw: & as HasFFI>::FFIType, func: F) -> R - where Locked: HasArcFFI, F: FnOnce(&T) -> R -{ - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - func(Locked::::as_arc(&raw).read_with(&guard)) -} - -#[cfg(debug_assertions)] -unsafe fn read_locked_arc_unchecked(raw: & as HasFFI>::FFIType, func: F) -> R - where Locked: HasArcFFI, F: FnOnce(&T) -> R -{ - debug_assert!(is_main_thread() && !is_in_servo_traversal()); - read_locked_arc(raw, func) -} - -#[cfg(not(debug_assertions))] -unsafe fn read_locked_arc_unchecked(raw: & as HasFFI>::FFIType, func: F) -> R - where Locked: HasArcFFI, F: FnOnce(&T) -> R -{ - func(Locked::::as_arc(&raw).read_unchecked()) -} - -fn write_locked_arc(raw: & as HasFFI>::FFIType, func: F) -> R - where Locked: HasArcFFI, F: FnOnce(&mut T) -> R -{ - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut guard = global_style_data.shared_lock.write(); - func(Locked::::as_arc(&raw).write_with(&mut guard)) -} - -#[no_mangle] -pub extern "C" fn Servo_CssRules_ListTypes( - rules: ServoCssRulesBorrowed, - result: nsTArrayBorrowed_uintptr_t, -) { - read_locked_arc(rules, |rules: &CssRules| { - let iter = rules.0.iter().map(|rule| rule.rule_type() as usize); - let (size, upper) = iter.size_hint(); - debug_assert_eq!(size, upper.unwrap()); - unsafe { result.set_len(size as u32) }; - result.iter_mut().zip(iter).fold((), |_, (r, v)| *r = v); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_CssRules_InsertRule( - rules: ServoCssRulesBorrowed, - contents: RawServoStyleSheetContentsBorrowed, - rule: *const nsACString, - index: u32, - nested: bool, - loader: *mut Loader, - gecko_stylesheet: *mut DomStyleSheet, - rule_type: *mut u16, -) -> nsresult { - let loader = if loader.is_null() { - None - } else { - Some(StylesheetLoader::new(loader, gecko_stylesheet, ptr::null_mut(), ptr::null_mut())) - }; - let loader = loader.as_ref().map(|loader| loader as &StyleStylesheetLoader); - let rule = unsafe { rule.as_ref().unwrap().as_str_unchecked() }; - - let global_style_data = &*GLOBAL_STYLE_DATA; - let contents = StylesheetContents::as_arc(&contents); - let result = Locked::::as_arc(&rules).insert_rule( - &global_style_data.shared_lock, - rule, - contents, - index as usize, - nested, - loader - ); - - match result { - Ok(new_rule) => { - *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16; - nsresult::NS_OK - } - Err(err) => err.into(), - } -} - -#[no_mangle] -pub extern "C" fn Servo_CssRules_DeleteRule( - rules: ServoCssRulesBorrowed, - index: u32 -) -> nsresult { - write_locked_arc(rules, |rules: &mut CssRules| { - match rules.remove_rule(index as usize) { - Ok(_) => nsresult::NS_OK, - Err(err) => err.into() - } - }) -} - -macro_rules! impl_basic_rule_funcs_without_getter { - { ($rule_type:ty, $raw_type:ty), - debug: $debug:ident, - to_css: $to_css:ident, - } => { - #[cfg(debug_assertions)] - #[no_mangle] - pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) { - read_locked_arc(rule, |rule: &$rule_type| { - write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap(); - }) - } - - #[cfg(not(debug_assertions))] - #[no_mangle] - pub extern "C" fn $debug(_: &$raw_type, _: *mut nsACString) { - unreachable!() - } - - #[no_mangle] - pub extern "C" fn $to_css(rule: &$raw_type, result: *mut nsAString) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let rule = Locked::<$rule_type>::as_arc(&rule); - rule.read_with(&guard).to_css(&guard, unsafe { result.as_mut().unwrap() }).unwrap(); - } - } -} - -macro_rules! impl_basic_rule_funcs { - { ($name:ident, $rule_type:ty, $raw_type:ty), - getter: $getter:ident, - debug: $debug:ident, - to_css: $to_css:ident, - } => { - #[no_mangle] - pub extern "C" fn $getter( - rules: ServoCssRulesBorrowed, - index: u32, - line: *mut u32, - column: *mut u32, - ) -> Strong<$raw_type> { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let rules = Locked::::as_arc(&rules).read_with(&guard); - let index = index as usize; - - if index >= rules.0.len() { - return Strong::null(); - } - - match rules.0[index] { - CssRule::$name(ref rule) => { - let location = rule.read_with(&guard).source_location; - *unsafe { line.as_mut().unwrap() } = location.line as u32; - *unsafe { column.as_mut().unwrap() } = location.column as u32; - rule.clone().into_strong() - }, - _ => { - Strong::null() - } - } - } - - impl_basic_rule_funcs_without_getter! { ($rule_type, $raw_type), - debug: $debug, - to_css: $to_css, - } - } -} - -macro_rules! impl_group_rule_funcs { - { ($name:ident, $rule_type:ty, $raw_type:ty), - get_rules: $get_rules:ident, - $($basic:tt)+ - } => { - impl_basic_rule_funcs! { ($name, $rule_type, $raw_type), $($basic)+ } - - #[no_mangle] - pub extern "C" fn $get_rules(rule: &$raw_type) -> ServoCssRulesStrong { - read_locked_arc(rule, |rule: &$rule_type| { - rule.rules.clone().into_strong() - }) - } - } -} - -impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule), - getter: Servo_CssRules_GetStyleRuleAt, - debug: Servo_StyleRule_Debug, - to_css: Servo_StyleRule_GetCssText, -} - -impl_basic_rule_funcs! { (Import, ImportRule, RawServoImportRule), - getter: Servo_CssRules_GetImportRuleAt, - debug: Servo_ImportRule_Debug, - to_css: Servo_ImportRule_GetCssText, -} - -impl_basic_rule_funcs_without_getter! { (Keyframe, RawServoKeyframe), - debug: Servo_Keyframe_Debug, - to_css: Servo_Keyframe_GetCssText, -} - -impl_basic_rule_funcs! { (Keyframes, KeyframesRule, RawServoKeyframesRule), - getter: Servo_CssRules_GetKeyframesRuleAt, - debug: Servo_KeyframesRule_Debug, - to_css: Servo_KeyframesRule_GetCssText, -} - -impl_group_rule_funcs! { (Media, MediaRule, RawServoMediaRule), - get_rules: Servo_MediaRule_GetRules, - getter: Servo_CssRules_GetMediaRuleAt, - debug: Servo_MediaRule_Debug, - to_css: Servo_MediaRule_GetCssText, -} - -impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule), - getter: Servo_CssRules_GetNamespaceRuleAt, - debug: Servo_NamespaceRule_Debug, - to_css: Servo_NamespaceRule_GetCssText, -} - -impl_basic_rule_funcs! { (Page, PageRule, RawServoPageRule), - getter: Servo_CssRules_GetPageRuleAt, - debug: Servo_PageRule_Debug, - to_css: Servo_PageRule_GetCssText, -} - -impl_group_rule_funcs! { (Supports, SupportsRule, RawServoSupportsRule), - get_rules: Servo_SupportsRule_GetRules, - getter: Servo_CssRules_GetSupportsRuleAt, - debug: Servo_SupportsRule_Debug, - to_css: Servo_SupportsRule_GetCssText, -} - -impl_group_rule_funcs! { (Document, DocumentRule, RawServoDocumentRule), - get_rules: Servo_DocumentRule_GetRules, - getter: Servo_CssRules_GetDocumentRuleAt, - debug: Servo_DocumentRule_Debug, - to_css: Servo_DocumentRule_GetCssText, -} - -impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, RawServoFontFeatureValuesRule), - getter: Servo_CssRules_GetFontFeatureValuesRuleAt, - debug: Servo_FontFeatureValuesRule_Debug, - to_css: Servo_FontFeatureValuesRule_GetCssText, -} - -impl_basic_rule_funcs! { (FontFace, FontFaceRule, RawServoFontFaceRule), - getter: Servo_CssRules_GetFontFaceRuleAt, - debug: Servo_FontFaceRule_Debug, - to_css: Servo_FontFaceRule_GetCssText, -} - -impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, RawServoCounterStyleRule), - getter: Servo_CssRules_GetCounterStyleRuleAt, - debug: Servo_CounterStyleRule_Debug, - to_css: Servo_CounterStyleRule_GetCssText, -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong { - read_locked_arc(rule, |rule: &StyleRule| { - rule.block.clone().into_strong() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed, - declarations: RawServoDeclarationBlockBorrowed) { - let declarations = Locked::::as_arc(&declarations); - write_locked_arc(rule, |rule: &mut StyleRule| { - rule.block = declarations.clone_arc(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) { - read_locked_arc(rule, |rule: &StyleRule| { - rule.selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_GetSelectorTextAtIndex( - rule: RawServoStyleRuleBorrowed, - index: u32, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &StyleRule| { - let index = index as usize; - if index >= rule.selectors.0.len() { - return; - } - rule.selectors.0[index].to_css(unsafe { result.as_mut().unwrap() }).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: RawServoStyleRuleBorrowed, count: *mut u32) { - read_locked_arc(rule, |rule: &StyleRule| { - *unsafe { count.as_mut().unwrap() } = rule.selectors.0.len() as u32; - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_GetSpecificityAtIndex( - rule: RawServoStyleRuleBorrowed, - index: u32, - specificity: *mut u64 -) { - read_locked_arc(rule, |rule: &StyleRule| { - let specificity = unsafe { specificity.as_mut().unwrap() }; - let index = index as usize; - if index >= rule.selectors.0.len() { - *specificity = 0; - return; - } - *specificity = rule.selectors.0[index].specificity() as u64; - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleRule_SelectorMatchesElement( - rule: RawServoStyleRuleBorrowed, - element: RawGeckoElementBorrowed, - index: u32, - pseudo_type: CSSPseudoElementType, -) -> bool { - read_locked_arc(rule, |rule: &StyleRule| { - let index = index as usize; - if index >= rule.selectors.0.len() { - return false; - } - - let selector = &rule.selectors.0[index]; - let mut matching_mode = MatchingMode::Normal; - - match PseudoElement::from_pseudo_type(pseudo_type) { - Some(pseudo) => { - // We need to make sure that the requested pseudo element type - // matches the selector pseudo element type before proceeding. - match selector.pseudo_element() { - Some(selector_pseudo) if *selector_pseudo == pseudo => { - matching_mode = MatchingMode::ForStatelessPseudoElement - }, - _ => return false, - }; - }, - None => { - // Do not attempt to match if a pseudo element is requested and - // this is not a pseudo element selector, or vice versa. - if selector.has_pseudo_element() { - return false; - } - }, - }; - - let element = GeckoElement(element); - let quirks_mode = element.as_node().owner_doc().quirks_mode(); - let mut ctx = - MatchingContext::new(matching_mode, None, None, quirks_mode); - matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {}) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleRule_SetSelectorText( - sheet: RawServoStyleSheetContentsBorrowed, - rule: RawServoStyleRuleBorrowed, - text: *const nsAString, -) -> bool { - let value_str = (*text).to_string(); - - write_locked_arc(rule, |rule: &mut StyleRule| { - use style::selector_parser::SelectorParser; - - let contents = StylesheetContents::as_arc(&sheet); - let namespaces = contents.namespaces.read(); - let url_data = contents.url_data.read(); - let parser = SelectorParser { - stylesheet_origin: contents.origin, - namespaces: &namespaces, - url_data: Some(&url_data), - }; - - let mut parser_input = ParserInput::new(&value_str); - match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input)) { - Ok(selectors) => { - rule.selectors = selectors; - true - } - Err(_) => false, - } - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_Closest( - element: RawGeckoElementBorrowed, - selectors: RawServoSelectorListBorrowed, -) -> *const structs::RawGeckoElement { - use std::borrow::Borrow; - use style::dom_apis; - - let element = GeckoElement(element); - let quirks_mode = element.as_node().owner_doc().quirks_mode(); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - - dom_apis::element_closest(element, &selectors, quirks_mode) - .map_or(ptr::null(), |e| e.0) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_Matches( - element: RawGeckoElementBorrowed, - selectors: RawServoSelectorListBorrowed, -) -> bool { - use std::borrow::Borrow; - use style::dom_apis; - - let element = GeckoElement(element); - let quirks_mode = element.as_node().owner_doc().quirks_mode(); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - dom_apis::element_matches( - &element, - &selectors, - quirks_mode, - ) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_QueryFirst( - node: RawGeckoNodeBorrowed, - selectors: RawServoSelectorListBorrowed, - may_use_invalidation: bool, -) -> *const structs::RawGeckoElement { - use std::borrow::Borrow; - use style::dom_apis::{self, MayUseInvalidation, QueryFirst}; - - let node = GeckoNode(node); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - let mut result = None; - - let may_use_invalidation = - if may_use_invalidation { - MayUseInvalidation::Yes - } else { - MayUseInvalidation::No - }; - - dom_apis::query_selector::( - node, - &selectors, - &mut result, - may_use_invalidation, - ); - - result.map_or(ptr::null(), |e| e.0) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_QueryAll( - node: RawGeckoNodeBorrowed, - selectors: RawServoSelectorListBorrowed, - content_list: *mut structs::nsSimpleContentList, - may_use_invalidation: bool, -) { - use std::borrow::Borrow; - use style::dom_apis::{self, MayUseInvalidation, QueryAll}; - - let node = GeckoNode(node); - let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow(); - let mut result = SmallVec::new(); - - let may_use_invalidation = - if may_use_invalidation { - MayUseInvalidation::Yes - } else { - MayUseInvalidation::No - }; - - dom_apis::query_selector::( - node, - &selectors, - &mut result, - may_use_invalidation, - ); - - if !result.is_empty() { - // NOTE(emilio): This relies on a slice of GeckoElement having the same - // memory representation than a slice of element pointers. - bindings::Gecko_ContentList_AppendAll( - content_list, - result.as_ptr() as *mut *const _, - result.len(), - ) - } -} - -#[no_mangle] -pub extern "C" fn Servo_ImportRule_GetHref(rule: RawServoImportRuleBorrowed, result: *mut nsAString) { - read_locked_arc(rule, |rule: &ImportRule| { - write!(unsafe { &mut *result }, "{}", rule.url.as_str()).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_ImportRule_GetSheet( - rule: RawServoImportRuleBorrowed, -) -> *const DomStyleSheet { - read_locked_arc(rule, |rule: &ImportRule| { - rule.stylesheet.as_sheet().unwrap().raw() as *const DomStyleSheet - }) -} - -#[no_mangle] -pub extern "C" fn Servo_ImportRule_SetSheet( - rule: RawServoImportRuleBorrowed, - sheet: *mut DomStyleSheet, -) { - write_locked_arc(rule, |rule: &mut ImportRule| { - let sheet = unsafe { GeckoStyleSheet::new(sheet) }; - rule.stylesheet = ImportSheet::new(sheet); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_Keyframe_GetKeyText( - keyframe: RawServoKeyframeBorrowed, - result: *mut nsAString -) { - read_locked_arc(keyframe, |keyframe: &Keyframe| { - keyframe.selector.to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_Keyframe_SetKeyText(keyframe: RawServoKeyframeBorrowed, text: *const nsACString) -> bool { - let text = unsafe { text.as_ref().unwrap().as_str_unchecked() }; - let mut input = ParserInput::new(&text); - if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) { - write_locked_arc(keyframe, |keyframe: &mut Keyframe| { - keyframe.selector = selector; - }); - true - } else { - false - } -} - -#[no_mangle] -pub extern "C" fn Servo_Keyframe_GetStyle(keyframe: RawServoKeyframeBorrowed) -> RawServoDeclarationBlockStrong { - read_locked_arc(keyframe, |keyframe: &Keyframe| keyframe.block.clone().into_strong()) -} - -#[no_mangle] -pub extern "C" fn Servo_Keyframe_SetStyle(keyframe: RawServoKeyframeBorrowed, - declarations: RawServoDeclarationBlockBorrowed) { - let declarations = Locked::::as_arc(&declarations); - write_locked_arc(keyframe, |keyframe: &mut Keyframe| { - keyframe.block = declarations.clone_arc(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_GetName(rule: RawServoKeyframesRuleBorrowed) -> *mut nsAtom { - read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr()) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_KeyframesRule_SetName(rule: RawServoKeyframesRuleBorrowed, name: *mut nsAtom) { - write_locked_arc(rule, |rule: &mut KeyframesRule| { - rule.name = KeyframesName::Ident(CustomIdent(Atom::from_addrefed(name))); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_GetCount(rule: RawServoKeyframesRuleBorrowed) -> u32 { - read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32) -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt( - rule: RawServoKeyframesRuleBorrowed, - index: u32, - line: *mut u32, - column: *mut u32, -) -> RawServoKeyframeStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let key = Locked::::as_arc(&rule).read_with(&guard) - .keyframes[index as usize].clone(); - let location = key.read_with(&guard).source_location; - *unsafe { line.as_mut().unwrap() } = location.line as u32; - *unsafe { column.as_mut().unwrap() } = location.column as u32; - key.into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_FindRule( - rule: RawServoKeyframesRuleBorrowed, - key: *const nsACString, -) -> u32 { - let key = unsafe { key.as_ref().unwrap().as_str_unchecked() }; - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - Locked::::as_arc(&rule).read_with(&guard) - .find_rule(&guard, key).map(|index| index as u32) - .unwrap_or(u32::max_value()) -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_AppendRule( - rule: RawServoKeyframesRuleBorrowed, - contents: RawServoStyleSheetContentsBorrowed, - css: *const nsACString -) -> bool { - let css = unsafe { css.as_ref().unwrap().as_str_unchecked() }; - let contents = StylesheetContents::as_arc(&contents); - let global_style_data = &*GLOBAL_STYLE_DATA; - - match Keyframe::parse(css, &contents, &global_style_data.shared_lock) { - Ok(keyframe) => { - write_locked_arc(rule, |rule: &mut KeyframesRule| { - rule.keyframes.push(keyframe); - }); - true - } - Err(..) => false, - } -} - -#[no_mangle] -pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: RawServoKeyframesRuleBorrowed, index: u32) { - write_locked_arc(rule, |rule: &mut KeyframesRule| { - rule.keyframes.remove(index as usize); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaRule_GetMedia(rule: RawServoMediaRuleBorrowed) -> RawServoMediaListStrong { - read_locked_arc(rule, |rule: &MediaRule| { - rule.media_queries.clone().into_strong() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: RawServoNamespaceRuleBorrowed) -> *mut nsAtom { - read_locked_arc(rule, |rule: &NamespaceRule| { - rule.prefix.as_ref().unwrap_or(&atom!("")).as_ptr() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_NamespaceRule_GetURI(rule: RawServoNamespaceRuleBorrowed) -> *mut nsAtom { - read_locked_arc(rule, |rule: &NamespaceRule| rule.url.0.as_ptr()) -} - -#[no_mangle] -pub extern "C" fn Servo_PageRule_GetStyle(rule: RawServoPageRuleBorrowed) -> RawServoDeclarationBlockStrong { - read_locked_arc(rule, |rule: &PageRule| { - rule.block.clone().into_strong() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_PageRule_SetStyle( - rule: RawServoPageRuleBorrowed, - declarations: RawServoDeclarationBlockBorrowed, -) { - let declarations = Locked::::as_arc(&declarations); - write_locked_arc(rule, |rule: &mut PageRule| { - rule.block = declarations.clone_arc(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_SupportsRule_GetConditionText( - rule: RawServoSupportsRuleBorrowed, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &SupportsRule| { - rule.condition.to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DocumentRule_GetConditionText( - rule: RawServoDocumentRuleBorrowed, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &DocumentRule| { - rule.condition.to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily( - rule: RawServoFontFeatureValuesRuleBorrowed, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &FontFeatureValuesRule| { - rule.font_family_to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText( - rule: RawServoFontFeatureValuesRuleBorrowed, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &FontFeatureValuesRule| { - rule.value_to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> RawServoFontFaceRuleStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - // XXX This is not great. We should split FontFace descriptor data - // from the rule, so that we don't need to create the rule like this - // and the descriptor data itself can be hold in UniquePtr from the - // Gecko side. See bug 1450904. - Arc::new(global_style_data.shared_lock.wrap(FontFaceRule::empty(SourceLocation { - line: 0, - column: 0, - }))).into_strong() -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_Clone( - rule: RawServoFontFaceRuleBorrowed, -) -> RawServoFontFaceRuleStrong { - let clone = read_locked_arc(rule, |rule: &FontFaceRule| rule.clone()); - let global_style_data = &*GLOBAL_STYLE_DATA; - Arc::new(global_style_data.shared_lock.wrap(clone)).into_strong() -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation( - rule: RawServoFontFaceRuleBorrowed, - line: *mut u32, - column: *mut u32, -) { - read_locked_arc(rule, |rule: &FontFaceRule| { - let location = rule.source_location; - *line.as_mut().unwrap() = location.line as u32; - *column.as_mut().unwrap() = location.column as u32; - }); -} - -macro_rules! apply_font_desc_list { - ($apply_macro:ident) => { - $apply_macro! { - valid: [ - eCSSFontDesc_Family => family, - eCSSFontDesc_Style => style, - eCSSFontDesc_Weight => weight, - eCSSFontDesc_Stretch => stretch, - eCSSFontDesc_Src => sources, - eCSSFontDesc_UnicodeRange => unicode_range, - eCSSFontDesc_FontFeatureSettings => feature_settings, - eCSSFontDesc_FontVariationSettings => variation_settings, - eCSSFontDesc_FontLanguageOverride => language_override, - eCSSFontDesc_Display => display, - ] - invalid: [ - eCSSFontDesc_UNKNOWN, - eCSSFontDesc_COUNT, - ] - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_Length( - rule: RawServoFontFaceRuleBorrowed, -) -> u32 { - read_locked_arc(rule, |rule: &FontFaceRule| { - let mut result = 0; - macro_rules! count_values { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - $(if rule.$field.is_some() { - result += 1; - })* - } - } - apply_font_desc_list!(count_values); - result - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter( - rule: RawServoFontFaceRuleBorrowed, - index: u32, -) -> nsCSSFontDesc { - read_locked_arc(rule, |rule: &FontFaceRule| { - let mut count = 0; - macro_rules! lookup_index { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - $(if rule.$field.is_some() { - count += 1; - if count - 1 == index { - return nsCSSFontDesc::$v_enum_name; - } - })* - } - } - apply_font_desc_list!(lookup_index); - return nsCSSFontDesc::eCSSFontDesc_UNKNOWN; - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText( - rule: RawServoFontFaceRuleBorrowed, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &FontFaceRule| { - rule.decl_to_css(result.as_mut().unwrap()).unwrap(); - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptor( - rule: RawServoFontFaceRuleBorrowed, - desc: nsCSSFontDesc, - result: nsCSSValueBorrowedMut, -) { - read_locked_arc(rule, |rule: &FontFaceRule| { - macro_rules! to_css_value { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - match desc { - $( - nsCSSFontDesc::$v_enum_name => { - if let Some(ref value) = rule.$field { - result.set_from(value); - } - } - )* - $( - nsCSSFontDesc::$i_enum_name => { - debug_assert!(false, "not a valid font descriptor"); - } - )* - } - } - } - apply_font_desc_list!(to_css_value) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptorCssText( - rule: RawServoFontFaceRuleBorrowed, - desc: nsCSSFontDesc, - result: *mut nsAString, -) { - read_locked_arc(rule, |rule: &FontFaceRule| { - let mut writer = CssWriter::new(result.as_mut().unwrap()); - macro_rules! to_css_text { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - match desc { - $( - nsCSSFontDesc::$v_enum_name => { - if let Some(ref value) = rule.$field { - value.to_css(&mut writer).unwrap(); - } - } - )* - $( - nsCSSFontDesc::$i_enum_name => { - debug_assert!(false, "not a valid font descriptor"); - } - )* - } - } - } - apply_font_desc_list!(to_css_text) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor( - rule: RawServoFontFaceRuleBorrowed, - desc: nsCSSFontDesc, - value: *const nsACString, - data: *mut URLExtraData, -) -> bool { - let value = value.as_ref().unwrap().as_str_unchecked(); - let mut input = ParserInput::new(&value); - let mut parser = Parser::new(&mut input); - let url_data = RefPtr::from_ptr_ref(&data); - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::FontFace), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - write_locked_arc(rule, |rule: &mut FontFaceRule| { - macro_rules! to_css_text { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - match desc { - $( - nsCSSFontDesc::$v_enum_name => { - if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) { - rule.$field = Some(value); - true - } else { - false - } - } - )* - $( - nsCSSFontDesc::$i_enum_name => { - debug_assert!(false, "not a valid font descriptor"); - false - } - )* - } - } - } - apply_font_desc_list!(to_css_text) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor( - rule: RawServoFontFaceRuleBorrowed, - desc: nsCSSFontDesc, -) { - write_locked_arc(rule, |rule: &mut FontFaceRule| { - macro_rules! reset_desc { - ( - valid: [$($v_enum_name:ident => $field:ident,)*] - invalid: [$($i_enum_name:ident,)*] - ) => { - match desc { - $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)* - $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)* - } - } - } - apply_font_desc_list!(reset_desc) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetName( - rule: RawServoCounterStyleRuleBorrowed, -) -> *mut nsAtom { - read_locked_arc(rule, |rule: &CounterStyleRule| { - rule.name().0.as_ptr() - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_SetName( - rule: RawServoCounterStyleRuleBorrowed, - value: *const nsACString, -) -> bool { - let value = value.as_ref().unwrap().as_str_unchecked(); - let mut input = ParserInput::new(&value); - let mut parser = Parser::new(&mut input); - match parser.parse_entirely(counter_style::parse_counter_style_name_definition) { - Ok(name) => { - write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name)); - true - } - Err(_) => false, - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration( - rule: RawServoCounterStyleRuleBorrowed, -) -> u32 { - read_locked_arc(rule, |rule: &CounterStyleRule| { - rule.generation() - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem( - rule: RawServoCounterStyleRuleBorrowed, -) -> u8 { - use style::counter_style::System; - read_locked_arc(rule, |rule: &CounterStyleRule| { - match *rule.resolved_system() { - System::Cyclic => structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC, - System::Numeric => structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC, - System::Alphabetic => structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC, - System::Symbolic => structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC, - System::Additive => structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE, - System::Fixed { .. } => structs::NS_STYLE_COUNTER_SYSTEM_FIXED, - System::Extends(_) => structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS, - } - }) as u8 -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended( - rule: RawServoCounterStyleRuleBorrowed, -) -> *mut nsAtom { - read_locked_arc(rule, |rule: &CounterStyleRule| { - match *rule.resolved_system() { - counter_style::System::Extends(ref name) => name.0.as_ptr(), - _ => { - debug_assert!(false, "Not extends system"); - ptr::null_mut() - } - } - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue( - rule: RawServoCounterStyleRuleBorrowed, -) -> i32 { - read_locked_arc(rule, |rule: &CounterStyleRule| { - match *rule.resolved_system() { - counter_style::System::Fixed { first_symbol_value } => { - first_symbol_value.map_or(1, |v| v.value()) - } - _ => { - debug_assert!(false, "Not fixed system"); - 0 - } - } - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback( - rule: RawServoCounterStyleRuleBorrowed, -) -> *mut nsAtom { - read_locked_arc(rule, |rule: &CounterStyleRule| { - rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr()) - }) -} - -macro_rules! counter_style_descriptors { - { - valid: [ - $($desc:ident => $getter:ident / $setter:ident,)+ - ] - invalid: [ - $($i_desc:ident,)+ - ] - } => { - #[no_mangle] - pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptor( - rule: RawServoCounterStyleRuleBorrowed, - desc: nsCSSCounterDesc, - result: nsCSSValueBorrowedMut, - ) { - read_locked_arc(rule, |rule: &CounterStyleRule| { - match desc { - $(nsCSSCounterDesc::$desc => { - if let Some(value) = rule.$getter() { - result.set_from(value); - } - })+ - $(nsCSSCounterDesc::$i_desc => unreachable!(),)+ - } - }); - } - - #[no_mangle] - pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText( - rule: RawServoCounterStyleRuleBorrowed, - desc: nsCSSCounterDesc, - result: *mut nsAString, - ) { - let mut writer = CssWriter::new(result.as_mut().unwrap()); - read_locked_arc(rule, |rule: &CounterStyleRule| { - match desc { - $(nsCSSCounterDesc::$desc => { - if let Some(value) = rule.$getter() { - value.to_css(&mut writer).unwrap(); - } - })+ - $(nsCSSCounterDesc::$i_desc => unreachable!(),)+ - } - }); - } - - #[no_mangle] - pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor( - rule: RawServoCounterStyleRuleBorrowed, - desc: nsCSSCounterDesc, - value: *const nsACString, - ) -> bool { - let value = value.as_ref().unwrap().as_str_unchecked(); - let mut input = ParserInput::new(&value); - let mut parser = Parser::new(&mut input); - let url_data = dummy_url_data(); - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::CounterStyle), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - write_locked_arc(rule, |rule: &mut CounterStyleRule| { - match desc { - $(nsCSSCounterDesc::$desc => { - match parser.parse_entirely(|i| Parse::parse(&context, i)) { - Ok(value) => rule.$setter(value), - Err(_) => false, - } - })+ - $(nsCSSCounterDesc::$i_desc => unreachable!(),)+ - } - }) - } - } -} - -counter_style_descriptors! { - valid: [ - eCSSCounterDesc_System => system / set_system, - eCSSCounterDesc_Symbols => symbols / set_symbols, - eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols, - eCSSCounterDesc_Negative => negative / set_negative, - eCSSCounterDesc_Prefix => prefix / set_prefix, - eCSSCounterDesc_Suffix => suffix / set_suffix, - eCSSCounterDesc_Range => range / set_range, - eCSSCounterDesc_Pad => pad / set_pad, - eCSSCounterDesc_Fallback => fallback / set_fallback, - eCSSCounterDesc_SpeakAs => speak_as / set_speak_as, - ] - invalid: [ - eCSSCounterDesc_UNKNOWN, - eCSSCounterDesc_COUNT, - ] -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox( - parent_style_or_null: ComputedStyleBorrowedOrNull, - pseudo_tag: *mut nsAtom, - raw_data: RawServoStyleSetBorrowed, -) -> ComputedStyleStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let guards = StylesheetGuards::same(&guard); - let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let atom = Atom::from_raw(pseudo_tag); - let pseudo = PseudoElement::from_anon_box_atom(&atom) - .expect("Not an anon box pseudo?"); - - let metrics = get_metrics_provider_for_product(); - - // If the pseudo element is PageContent, we should append the precomputed - // pseudo element declerations with specified page rules. - let page_decls = match pseudo { - PseudoElement::PageContent => { - let mut declarations = vec![]; - let iter = data.stylist.iter_extra_data_origins_rev(); - for (data, origin) in iter { - let level = match origin { - Origin::UserAgent => CascadeLevel::UANormal, - Origin::User => CascadeLevel::UserNormal, - Origin::Author => CascadeLevel::SameTreeAuthorNormal, - }; - for rule in data.pages.iter() { - declarations.push(ApplicableDeclarationBlock::from_declarations( - rule.read_with(level.guard(&guards)).block.clone(), - level - )); - } - } - Some(declarations) - }, - _ => None, - }; - - let rule_node = data.stylist.rule_node_for_precomputed_pseudo( - &guards, - &pseudo, - page_decls, - ); - - data.stylist.precomputed_values_for_pseudo_with_rule_node::( - &guards, - &pseudo, - parent_style_or_null.map(|x| &*x), - &metrics, - rule_node - ).into() -} - -#[no_mangle] -pub extern "C" fn Servo_ResolvePseudoStyle( - element: RawGeckoElementBorrowed, - pseudo_type: CSSPseudoElementType, - is_probe: bool, - inherited_style: ComputedStyleBorrowedOrNull, - raw_data: RawServoStyleSetBorrowed, -) -> ComputedStyleStrong { - let element = GeckoElement(element); - let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - debug!("Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}", - element, PseudoElement::from_pseudo_type(pseudo_type), is_probe); - - let data = element.borrow_data(); - - let data = match data.as_ref() { - Some(data) if data.has_styles() => data, - _ => { - // FIXME(bholley, emilio): Assert against this. - // - // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty, - // which goes and does a bunch of work involving style resolution. - // - // Bug 1403865 tracks fixing it, and potentially adding an assert - // here instead. - warn!("Calling Servo_ResolvePseudoStyle on unstyled element"); - return if is_probe { - Strong::null() - } else { - doc_data.default_computed_values().clone().into() - }; - } - }; - - let pseudo = PseudoElement::from_pseudo_type(pseudo_type) - .expect("ResolvePseudoStyle with a non-pseudo?"); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let style = get_pseudo_style( - &guard, - element, - &pseudo, - RuleInclusion::All, - &data.styles, - inherited_style, - &*doc_data, - is_probe, - /* matching_func = */ None, - ); - - match style { - Some(s) => s.into(), - None => { - debug_assert!(is_probe); - Strong::null() - } - } -} - -fn debug_atom_array(atoms: &AtomArray) -> String { - let mut result = String::from("["); - for atom in atoms.iter() { - if atom.mRawPtr.is_null() { - result += "(null), "; - } else { - let atom = unsafe { WeakAtom::new(atom.mRawPtr) }; - write!(result, "{}, ", atom).unwrap(); - } - } - result.push(']'); - result -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle( - element: RawGeckoElementBorrowed, - pseudo_tag: *mut nsAtom, - inherited_style: ComputedStyleBorrowed, - input_word: *const AtomArray, - raw_data: RawServoStyleSetBorrowed -) -> ComputedStyleStrong { - let element = GeckoElement(element); - let data = element.borrow_data() - .expect("Calling ResolveXULTreePseudoStyle on unstyled element?"); - - let pseudo = unsafe { - Atom::with(pseudo_tag, |atom| { - PseudoElement::from_tree_pseudo_atom(atom, Box::new([])) - }).expect("ResolveXULTreePseudoStyle with a non-tree pseudo?") - }; - let input_word = unsafe { input_word.as_ref().unwrap() }; - - let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - debug!("ResolveXULTreePseudoStyle: {:?} {:?} {}", - element, pseudo, debug_atom_array(input_word)); - - let matching_fn = |pseudo: &PseudoElement| { - let args = pseudo.tree_pseudo_args().expect("Not a tree pseudo-element?"); - args.iter().all(|atom| { - input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr) - }) - }; - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - get_pseudo_style( - &guard, - element, - &pseudo, - RuleInclusion::All, - &data.styles, - Some(inherited_style), - &*doc_data, - /* is_probe = */ false, - Some(&matching_fn), - ).unwrap().into() -} - -#[no_mangle] -pub extern "C" fn Servo_SetExplicitStyle( - element: RawGeckoElementBorrowed, - style: ComputedStyleBorrowed, -) { - let element = GeckoElement(element); - debug!("Servo_SetExplicitStyle: {:?}", element); - // We only support this API for initial styling. There's no reason it couldn't - // work for other things, we just haven't had a reason to do so. - debug_assert!(element.get_data().is_none()); - let mut data = unsafe { element.ensure_data() }; - data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc()); -} - -#[no_mangle] -pub extern "C" fn Servo_HasAuthorSpecifiedRules( - style: ComputedStyleBorrowed, - element: RawGeckoElementBorrowed, - pseudo_type: CSSPseudoElementType, - rule_type_mask: u32, - author_colors_allowed: bool, -) -> bool { - let element = GeckoElement(element); - let pseudo = PseudoElement::from_pseudo_type(pseudo_type); - - let guard = (*GLOBAL_STYLE_DATA).shared_lock.read(); - let guards = StylesheetGuards::same(&guard); - - style.rules().has_author_specified_rules(element, - pseudo, - &guards, - rule_type_mask, - author_colors_allowed) -} - -fn get_pseudo_style( - guard: &SharedRwLockReadGuard, - element: GeckoElement, - pseudo: &PseudoElement, - rule_inclusion: RuleInclusion, - styles: &ElementStyles, - inherited_styles: Option<&ComputedValues>, - doc_data: &PerDocumentStyleDataImpl, - is_probe: bool, - matching_func: Option<&Fn(&PseudoElement) -> bool>, -) -> Option> { - let style = match pseudo.cascade_type() { - PseudoElementCascadeType::Eager => { - match *pseudo { - PseudoElement::FirstLetter => { - styles.pseudos.get(&pseudo).map(|pseudo_styles| { - // inherited_styles can be None when doing lazy resolution - // (e.g. for computed style) or when probing. In that case - // we just inherit from our element, which is what Gecko - // does in that situation. What should actually happen in - // the computed style case is a bit unclear. - let inherited_styles = - inherited_styles.unwrap_or(styles.primary()); - let guards = StylesheetGuards::same(guard); - let metrics = get_metrics_provider_for_product(); - let inputs = CascadeInputs::new_from_style(pseudo_styles); - doc_data.stylist.compute_pseudo_element_style_with_inputs( - inputs, - pseudo, - &guards, - Some(inherited_styles), - &metrics, - Some(element), - ) - }) - }, - _ => { - // Unfortunately, we can't assert that inherited_styles, if - // present, is pointer-equal to styles.primary(), or even - // equal in any meaningful way. The way it can fail is as - // follows. Say we append an element with a ::before, - // ::after, or ::first-line to a parent with a ::first-line, - // such that the element ends up on the first line of the - // parent (e.g. it's an inline-block in the case it has a - // ::first-line, or any container in the ::before/::after - // cases). Then gecko will update its frame's style to - // inherit from the parent's ::first-line. The next time we - // try to get the ::before/::after/::first-line style for - // the kid, we'll likely pass in the frame's style as - // inherited_styles, but that's not pointer-identical to - // styles.primary(), because it got reparented. - // - // Now in practice this turns out to be OK, because all the - // cases in which there's a mismatch go ahead and reparent - // styles again as needed to make sure the ::first-line - // affects all the things it should affect. But it makes it - // impossible to assert anything about the two styles - // matching here, unfortunately. - styles.pseudos.get(&pseudo).cloned() - }, - } - } - PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"), - PseudoElementCascadeType::Lazy => { - debug_assert!(inherited_styles.is_none() || - ptr::eq(inherited_styles.unwrap(), - &**styles.primary())); - let base = if pseudo.inherits_from_default_values() { - doc_data.default_computed_values() - } else { - styles.primary() - }; - let guards = StylesheetGuards::same(guard); - let metrics = get_metrics_provider_for_product(); - doc_data.stylist.lazily_compute_pseudo_element_style( - &guards, - element, - &pseudo, - rule_inclusion, - base, - is_probe, - &metrics, - matching_func, - ) - }, - }; - - if is_probe { - return style; - } - - Some(style.unwrap_or_else(|| { - StyleBuilder::for_inheritance( - doc_data.stylist.device(), - Some(styles.primary()), - Some(pseudo), - ).build() - })) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_ComputedValues_Inherit( - raw_data: RawServoStyleSetBorrowed, - pseudo_tag: *mut nsAtom, - parent_style_context: ComputedStyleBorrowedOrNull, - target: structs::InheritTarget -) -> ComputedStyleStrong { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - let for_text = target == structs::InheritTarget::Text; - let atom = Atom::from_raw(pseudo_tag); - let pseudo = PseudoElement::from_anon_box_atom(&atom) - .expect("Not an anon-box? Gah!"); - - let mut style = StyleBuilder::for_inheritance( - data.stylist.device(), - parent_style_context, - Some(&pseudo) - ); - - if for_text { - StyleAdjuster::new(&mut style).adjust_for_text(); - } - - style.build().into() -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_GetStyleBits(values: ComputedStyleBorrowed) -> u64 { - use style::properties::computed_value_flags::ComputedValueFlags; - // FIXME(emilio): We could do this more efficiently I'm quite sure. - let flags = values.flags; - let mut result = 0; - if flags.contains(ComputedValueFlags::IS_RELEVANT_LINK_VISITED) { - result |= structs::NS_STYLE_RELEVANT_LINK_VISITED as u64; - } - if flags.contains(ComputedValueFlags::HAS_TEXT_DECORATION_LINES) { - result |= structs::NS_STYLE_HAS_TEXT_DECORATION_LINES as u64; - } - if flags.contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK) { - result |= structs::NS_STYLE_SUPPRESS_LINEBREAK as u64; - } - if flags.contains(ComputedValueFlags::IS_TEXT_COMBINED) { - result |= structs::NS_STYLE_IS_TEXT_COMBINED as u64; - } - if flags.contains(ComputedValueFlags::IS_IN_PSEUDO_ELEMENT_SUBTREE) { - result |= structs::NS_STYLE_HAS_PSEUDO_ELEMENT_DATA as u64; - } - if flags.contains(ComputedValueFlags::IS_IN_DISPLAY_NONE_SUBTREE) { - result |= structs::NS_STYLE_IN_DISPLAY_NONE_SUBTREE as u64; - } - result -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions( - values: ComputedStyleBorrowed, -) -> bool { - let b = values.get_box(); - b.specifies_animations() || b.specifies_transitions() -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_EqualCustomProperties( - first: ServoComputedDataBorrowed, - second: ServoComputedDataBorrowed -) -> bool { - first.custom_properties == second.custom_properties -} - -#[no_mangle] -pub extern "C" fn Servo_ComputedValues_GetStyleRuleList( - values: ComputedStyleBorrowed, - rules: RawGeckoServoStyleRuleListBorrowedMut, -) { - let rule_node = match values.rules { - Some(ref r) => r, - None => return, - }; - - let mut result = SmallVec::<[_; 10]>::new(); - for node in rule_node.self_and_ancestors() { - let style_rule = match node.style_source().and_then(|x| x.as_rule()) { - Some(rule) => rule, - _ => continue, - }; - - // For the rules with any important declaration, we insert them into - // rule tree twice, one for normal level and another for important - // level. So, we skip the important one to keep the specificity order of - // rules. - if node.importance().important() { - continue; - } - - result.push(style_rule); - } - - unsafe { rules.set_len(result.len() as u32) }; - for (ref src, ref mut dest) in result.into_iter().zip(rules.iter_mut()) { - src.with_arc(|a| { - a.with_raw_offset_arc(|arc| { - **dest = *Locked::::arc_as_borrowed(arc); - }) - }); - } -} - -/// See the comment in `Device` to see why it's ok to pass an owned reference to -/// the pres context (hint: the context outlives the StyleSet, that holds the -/// device alive). -#[no_mangle] -pub extern "C" fn Servo_StyleSet_Init( - pres_context: RawGeckoPresContextOwned, -) -> *mut RawServoStyleSet { - let data = Box::new(PerDocumentStyleData::new(pres_context)); - Box::into_raw(data) as *mut RawServoStyleSet -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: RawServoStyleSetBorrowed) { - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - data.stylist.device_mut().rebuild_cached_data(); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) { - let _ = data.into_box::(); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: RawServoStyleSetBorrowed) { - let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let doc = - &*data.stylist.device().pres_context().mDocument.raw::(); - data.stylist.set_quirks_mode(QuirksMode::from(doc.mCompatMode)); -} - -fn parse_property_into( - declarations: &mut SourcePropertyDeclaration, - property_id: PropertyId, - value: *const nsACString, - data: *mut URLExtraData, - parsing_mode: structs::ParsingMode, - quirks_mode: QuirksMode, - reporter: &R -) -> Result<(), ()> -where - R: ParseErrorReporter -{ - use style_traits::ParsingMode; - let value = unsafe { value.as_ref().unwrap().as_str_unchecked() }; - let url_data = unsafe { RefPtr::from_ptr_ref(&data) }; - let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode); - - parse_one_declaration_into( - declarations, - property_id, - value, - url_data, - reporter, - parsing_mode, - quirks_mode, - ) -} - -#[no_mangle] -pub extern "C" fn Servo_ParseProperty( - property: nsCSSPropertyID, value: *const nsACString, - data: *mut URLExtraData, - parsing_mode: structs::ParsingMode, - quirks_mode: nsCompatibility, - loader: *mut Loader, -) -> RawServoDeclarationBlockStrong { - let id = get_property_id_from_nscsspropertyid!(property, - RawServoDeclarationBlockStrong::null()); - let mut declarations = SourcePropertyDeclaration::new(); - let reporter = ErrorReporter::new(ptr::null_mut(), loader, data); - match parse_property_into(&mut declarations, id, value, data, - parsing_mode, quirks_mode.into(), &reporter) { - Ok(()) => { - let global_style_data = &*GLOBAL_STYLE_DATA; - let mut block = PropertyDeclarationBlock::new(); - block.extend( - declarations.drain(), - Importance::Normal, - DeclarationSource::CssOm, - ); - Arc::new(global_style_data.shared_lock.wrap(block)).into_strong() - } - Err(_) => RawServoDeclarationBlockStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_ParseEasing( - easing: *const nsAString, - data: *mut URLExtraData, - output: nsTimingFunctionBorrowedMut -) -> bool { - use style::properties::longhands::transition_timing_function; - - // FIXME Dummy URL data would work fine here. - let url_data = unsafe { RefPtr::from_ptr_ref(&data) }; - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - let easing = unsafe { (*easing).to_string() }; - let mut input = ParserInput::new(&easing); - let mut parser = Parser::new(&mut input); - let result = - parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p)); - match result { - Ok(parsed_easing) => { - *output = parsed_easing.into(); - true - }, - Err(_) => false - } -} - -#[no_mangle] -pub extern "C" fn Servo_GetProperties_Overriding_Animation( - element: RawGeckoElementBorrowed, - list: RawGeckoCSSPropertyIDListBorrowed, - set: nsCSSPropertyIDSetBorrowedMut, -) { - let element = GeckoElement(element); - let element_data = match element.borrow_data() { - Some(data) => data, - None => return - }; - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let guards = StylesheetGuards::same(&guard); - let (overridden, custom) = - element_data.styles.primary().rules().get_properties_overriding_animations(&guards); - for p in list.iter() { - match PropertyId::from_nscsspropertyid(*p) { - Ok(property) => { - if let PropertyId::Longhand(id) = property { - if overridden.contains(id) { - unsafe { Gecko_AddPropertyToSet(set, *p) }; - } - } - }, - Err(_) => { - if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom { - unsafe { Gecko_AddPropertyToSet(set, *p) }; - } - } - } - } -} - -#[no_mangle] -pub extern "C" fn Servo_MatrixTransform_Operate(matrix_operator: MatrixTransformOperator, - from: *const RawGeckoGfxMatrix4x4, - to: *const RawGeckoGfxMatrix4x4, - progress: f64, - output: *mut RawGeckoGfxMatrix4x4) { - use self::MatrixTransformOperator::{Accumulate, Interpolate}; - use style::values::computed::transform::Matrix3D; - - let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix")); - let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix")); - let result = match matrix_operator { - Interpolate => from.animate(&to, Procedure::Interpolate { progress }), - Accumulate => from.animate(&to, Procedure::Accumulate { count: progress as u64 }), - }; - - let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix"); - if let Ok(result) = result { - *output = result.into(); - } else if progress < 0.5 { - *output = from.clone().into(); - } else { - *output = to.clone().into(); - } -} - -#[no_mangle] -pub extern "C" fn Servo_ParseStyleAttribute( - data: *const nsACString, - raw_extra_data: *mut URLExtraData, - quirks_mode: nsCompatibility, - loader: *mut Loader, -) -> RawServoDeclarationBlockStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let value = unsafe { data.as_ref().unwrap().as_str_unchecked() }; - let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data); - let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) }; - Arc::new(global_style_data.shared_lock.wrap( - parse_style_attribute( - value, - url_data, - &reporter, - quirks_mode.into(), - ) - )).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> RawServoDeclarationBlockStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - Arc::new(global_style_data.shared_lock.wrap(PropertyDeclarationBlock::new())).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_Clone( - declarations: RawServoDeclarationBlockBorrowed, -) -> RawServoDeclarationBlockStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let declarations = Locked::::as_arc(&declarations); - Arc::new(global_style_data.shared_lock.wrap( - declarations.read_with(&guard).clone() - )).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_Equals( - a: RawServoDeclarationBlockBorrowed, - b: RawServoDeclarationBlockBorrowed, -) -> bool { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - *Locked::::as_arc(&a).read_with(&guard).declarations() == - *Locked::::as_arc(&b).read_with(&guard).declarations() -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed, - result: *mut nsAString) { - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - decls.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( - declarations: RawServoDeclarationBlockBorrowed, - property_id: nsCSSPropertyID, buffer: *mut nsAString, - computed_values: ComputedStyleBorrowedOrNull, - custom_properties: RawServoDeclarationBlockBorrowedOrNull, -) { - let property_id = get_property_id_from_nscsspropertyid!(property_id, ()); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let decls = Locked::::as_arc(&declarations).read_with(&guard); - - let custom_properties = Locked::::arc_from_borrowed(&custom_properties); - let custom_properties = custom_properties.map(|block| block.read_with(&guard)); - let buffer = unsafe { buffer.as_mut().unwrap() }; - let rv = decls.single_value_to_css(&property_id, buffer, computed_values, custom_properties); - debug_assert!(rv.is_ok()); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas( - declarations: RawServoDeclarationBlockBorrowed, - buffer: *mut nsAString, -) { - use style::properties::shorthands::font; - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) { - Ok(l) => l, - Err(()) => { - warn!("Unexpected property!"); - return; - } - }; - - let rv = longhands.to_css(&mut CssWriter::new(&mut *buffer)); - debug_assert!(rv.is_ok()); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_Count(declarations: RawServoDeclarationBlockBorrowed) -> u32 { - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - decls.declarations().len() as u32 - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_GetNthProperty( - declarations: RawServoDeclarationBlockBorrowed, - index: u32, - result: *mut nsAString, -) -> bool { - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - if let Some(decl) = decls.declarations().get(index as usize) { - let result = unsafe { result.as_mut().unwrap() }; - result.assign_utf8(&decl.id().name()); - true - } else { - false - } - }) -} - -macro_rules! get_property_id_from_property { - ($property: ident, $ret: expr) => {{ - let property = $property.as_ref().unwrap().as_str_unchecked(); - match PropertyId::parse(property.into()) { - Ok(property_id) => property_id, - Err(_) => { return $ret; } - } - }} -} - -unsafe fn get_property_value( - declarations: RawServoDeclarationBlockBorrowed, - property_id: PropertyId, - value: *mut nsAString, -) { - // This callsite is hot enough that the lock acquisition shows up in profiles. - // Using an unchecked read here improves our performance by ~10% on the - // microbenchmark in bug 1355599. - read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| { - decls.property_value_to_css(&property_id, value.as_mut().unwrap()).unwrap(); - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue( - declarations: RawServoDeclarationBlockBorrowed, - property: *const nsACString, - value: *mut nsAString, -) { - get_property_value( - declarations, - get_property_id_from_property!(property, ()), - value, - ) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: *mut nsAString, -) { - get_property_value(declarations, get_property_id_from_nscsspropertyid!(property, ()), value) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant( - declarations: RawServoDeclarationBlockBorrowed, - property: *const nsACString, -) -> bool { - let property_id = get_property_id_from_property!(property, false); - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - decls.property_priority(&property_id).important() - }) -} - -fn set_property( - declarations: RawServoDeclarationBlockBorrowed, - property_id: PropertyId, - value: *const nsACString, - is_important: bool, - data: *mut URLExtraData, - parsing_mode: structs::ParsingMode, - quirks_mode: QuirksMode, - loader: *mut Loader -) -> bool { - let mut source_declarations = SourcePropertyDeclaration::new(); - let reporter = ErrorReporter::new(ptr::null_mut(), loader, data); - match parse_property_into(&mut source_declarations, property_id, value, data, - parsing_mode, quirks_mode, &reporter) { - Ok(()) => { - let importance = if is_important { Importance::Important } else { Importance::Normal }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.extend( - source_declarations.drain(), - importance, - DeclarationSource::CssOm - ) - }) - }, - Err(_) => false, - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty( - declarations: RawServoDeclarationBlockBorrowed, - property: *const nsACString, - value: *const nsACString, - is_important: bool, - data: *mut URLExtraData, - parsing_mode: structs::ParsingMode, - quirks_mode: nsCompatibility, - loader: *mut Loader, -) -> bool { - set_property( - declarations, - get_property_id_from_property!(property, false), - value, - is_important, - data, - parsing_mode, - quirks_mode.into(), - loader, - ) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue( - declarations: RawServoDeclarationBlockBorrowed, - animation_value: RawServoAnimationValueBorrowed, -) -> bool { - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push( - AnimationValue::as_arc(&animation_value).uncompute(), - Importance::Normal, - DeclarationSource::CssOm, - ) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: *const nsACString, - is_important: bool, - data: *mut URLExtraData, - parsing_mode: structs::ParsingMode, - quirks_mode: nsCompatibility, - loader: *mut Loader, -) -> bool { - set_property( - declarations, - get_property_id_from_nscsspropertyid!(property, false), - value, - is_important, - data, - parsing_mode, - quirks_mode.into(), - loader, - ) -} - -fn remove_property( - declarations: RawServoDeclarationBlockBorrowed, - property_id: PropertyId -) -> bool { - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.remove_property(&property_id) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty( - declarations: RawServoDeclarationBlockBorrowed, - property: *const nsACString, -) -> bool { - remove_property(declarations, get_property_id_from_property!(property, false)) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID -) -> bool { - remove_property(declarations, get_property_id_from_nscsspropertyid!(property, false)) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_Create() -> RawServoMediaListStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into_strong() -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_DeepClone(list: RawServoMediaListBorrowed) -> RawServoMediaListStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - read_locked_arc(list, |list: &MediaList| { - Arc::new(global_style_data.shared_lock.wrap(list.clone())) - .into_strong() - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_Matches( - list: RawServoMediaListBorrowed, - raw_data: RawServoStyleSetBorrowed, -) -> bool { - let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - read_locked_arc(list, |list: &MediaList| { - list.evaluate(per_doc_data.stylist.device(), per_doc_data.stylist.quirks_mode()) - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, -) -> bool { - let property_id = get_property_id_from_nscsspropertyid!(property, false); - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - decls.has_css_wide_keyword(&property_id) - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_GetText(list: RawServoMediaListBorrowed, result: *mut nsAString) { - read_locked_arc(list, |list: &MediaList| { - list.to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_MediaList_SetText( - list: RawServoMediaListBorrowed, - text: *const nsACString, - caller_type: CallerType, -) { - let text = (*text).as_str_unchecked(); - - let mut input = ParserInput::new(&text); - let mut parser = Parser::new(&mut input); - let url_data = dummy_url_data(); - - // TODO(emilio): If the need for `CallerType` appears in more places, - // consider adding an explicit member in `ParserContext` instead of doing - // this (or adding a dummy "chrome://" url data). - // - // For media query parsing it's effectively the same, so for now... - let origin = match caller_type { - CallerType::System => Origin::UserAgent, - CallerType::NonSystem => Origin::Author, - }; - - let context = ParserContext::new( - origin, - url_data, - Some(CssRuleType::Media), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - write_locked_arc(list, |list: &mut MediaList| { - *list = parse_media_query_list( - &context, - &mut parser, - &NullReporter, - ); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_GetLength(list: RawServoMediaListBorrowed) -> u32 { - read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_GetMediumAt( - list: RawServoMediaListBorrowed, - index: u32, - result: *mut nsAString, -) -> bool { - read_locked_arc(list, |list: &MediaList| { - if let Some(media_query) = list.media_queries.get(index as usize) { - media_query.to_css(&mut CssWriter::new(unsafe { result.as_mut().unwrap() })).unwrap(); - true - } else { - false - } - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_AppendMedium( - list: RawServoMediaListBorrowed, - new_medium: *const nsACString, -) { - let new_medium = unsafe { new_medium.as_ref().unwrap().as_str_unchecked() }; - let url_data = unsafe { dummy_url_data() }; - let context = ParserContext::new_for_cssom( - url_data, - Some(CssRuleType::Media), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - write_locked_arc(list, |list: &mut MediaList| { - list.append_medium(&context, new_medium); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_MediaList_DeleteMedium( - list: RawServoMediaListBorrowed, - old_medium: *const nsACString, -) -> bool { - let old_medium = unsafe { old_medium.as_ref().unwrap().as_str_unchecked() }; - let url_data = unsafe { dummy_url_data() }; - let context = ParserContext::new_for_cssom( - url_data, - Some(CssRuleType::Media), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - write_locked_arc(list, |list: &mut MediaList| list.delete_medium(&context, old_medium)) -} - -macro_rules! get_longhand_from_id { - ($id:expr) => { - match PropertyId::from_nscsspropertyid($id) { - Ok(PropertyId::Longhand(long)) => long, - _ => { - panic!("stylo: unknown presentation property with id"); - } - } - }; -} - -macro_rules! match_wrap_declared { - ($longhand:ident, $($property:ident => $inner:expr,)*) => ( - match $longhand { - $( - LonghandId::$property => PropertyDeclaration::$property($inner), - )* - _ => { - panic!("stylo: Don't know how to handle presentation property"); - } - } - ) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, -) -> bool { - read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| { - decls.contains(get_longhand_from_id!(property)) - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: *mut nsAtom, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands::_x_lang::computed_value::T as Lang; - - let long = get_longhand_from_id!(property); - let prop = match_wrap_declared! { long, - XLang => Lang(Atom::from_raw(value)), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -#[allow(unreachable_code)] -pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: i32 -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands; - use style::values::generics::font::FontStyle; - use style::values::specified::BorderStyle; - - let long = get_longhand_from_id!(property); - let value = value as u32; - - let prop = match_wrap_declared! { long, - MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value), - // TextEmphasisPosition => FIXME implement text-emphasis-position - Direction => longhands::direction::SpecifiedValue::from_gecko_keyword(value), - Display => longhands::display::SpecifiedValue::from_gecko_keyword(value), - Float => longhands::float::SpecifiedValue::from_gecko_keyword(value), - VerticalAlign => longhands::vertical_align::SpecifiedValue::from_gecko_keyword(value), - TextAlign => longhands::text_align::SpecifiedValue::from_gecko_keyword(value), - TextEmphasisPosition => longhands::text_emphasis_position::SpecifiedValue::from_gecko_keyword(value), - Clear => longhands::clear::SpecifiedValue::from_gecko_keyword(value), - FontSize => { - // We rely on Gecko passing in font-size values (0...7) here. - longhands::font_size::SpecifiedValue::from_html_size(value as u8) - }, - FontStyle => { - let val = if value == structs::NS_FONT_STYLE_ITALIC { - FontStyle::Italic - } else { - debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL); - FontStyle::Normal - }; - - ToComputedValue::from_computed_value(&val) - }, - FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value), - ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)), - MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value), - WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value), - CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value), - BorderTopStyle => BorderStyle::from_gecko_keyword(value), - BorderRightStyle => BorderStyle::from_gecko_keyword(value), - BorderBottomStyle => BorderStyle::from_gecko_keyword(value), - BorderLeftStyle => BorderStyle::from_gecko_keyword(value), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetIntValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: i32 -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel; - use style::properties::longhands::_x_span::computed_value::T as Span; - - let long = get_longhand_from_id!(property); - let prop = match_wrap_declared! { long, - XSpan => Span(value), - // Gecko uses Integer values to signal that it is relative - MozScriptLevel => MozScriptLevel::Relative(value), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetPixelValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: f32 -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing; - use style::values::specified::{BorderSideWidth, MozLength, BorderCornerRadius}; - use style::values::specified::length::{NoCalcLength, NonNegativeLength, LengthOrPercentage}; - - let long = get_longhand_from_id!(property); - let nocalc = NoCalcLength::from_px(value); - - let prop = match_wrap_declared! { long, - Height => MozLength::LengthOrPercentageOrAuto(nocalc.into()), - Width => MozLength::LengthOrPercentageOrAuto(nocalc.into()), - BorderTopWidth => BorderSideWidth::Length(nocalc.into()), - BorderRightWidth => BorderSideWidth::Length(nocalc.into()), - BorderBottomWidth => BorderSideWidth::Length(nocalc.into()), - BorderLeftWidth => BorderSideWidth::Length(nocalc.into()), - MarginTop => nocalc.into(), - MarginRight => nocalc.into(), - MarginBottom => nocalc.into(), - MarginLeft => nocalc.into(), - PaddingTop => nocalc.into(), - PaddingRight => nocalc.into(), - PaddingBottom => nocalc.into(), - PaddingLeft => nocalc.into(), - BorderSpacing => { - let v = NonNegativeLength::from(nocalc); - Box::new(BorderSpacing::new(v.clone(), v)) - }, - BorderTopLeftRadius => { - let length = LengthOrPercentage::from(nocalc); - Box::new(BorderCornerRadius::new(length.clone(), length)) - }, - BorderTopRightRadius => { - let length = LengthOrPercentage::from(nocalc); - Box::new(BorderCornerRadius::new(length.clone(), length)) - }, - BorderBottomLeftRadius => { - let length = LengthOrPercentage::from(nocalc); - Box::new(BorderCornerRadius::new(length.clone(), length)) - }, - BorderBottomRightRadius => { - let length = LengthOrPercentage::from(nocalc); - Box::new(BorderCornerRadius::new(length.clone(), length)) - }, - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetLengthValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: f32, - unit: structs::nsCSSUnit, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize; - use style::values::specified::MozLength; - use style::values::specified::length::{AbsoluteLength, FontRelativeLength}; - use style::values::specified::length::{LengthOrPercentage, NoCalcLength}; - - let long = get_longhand_from_id!(property); - let nocalc = match unit { - structs::nsCSSUnit::eCSSUnit_EM => NoCalcLength::FontRelative(FontRelativeLength::Em(value)), - structs::nsCSSUnit::eCSSUnit_XHeight => NoCalcLength::FontRelative(FontRelativeLength::Ex(value)), - structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)), - structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)), - structs::nsCSSUnit::eCSSUnit_Centimeter => NoCalcLength::Absolute(AbsoluteLength::Cm(value)), - structs::nsCSSUnit::eCSSUnit_Millimeter => NoCalcLength::Absolute(AbsoluteLength::Mm(value)), - structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)), - structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)), - structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)), - _ => unreachable!("Unknown unit passed to SetLengthValue") - }; - - let prop = match_wrap_declared! { long, - Width => MozLength::LengthOrPercentageOrAuto(nocalc.into()), - FontSize => LengthOrPercentage::from(nocalc).into(), - MozScriptMinSize => MozScriptMinSize(nocalc), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetNumberValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: f32, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel; - use style::properties::longhands::_moz_script_size_multiplier::SpecifiedValue as MozScriptSizeMultiplier; - - let long = get_longhand_from_id!(property); - - let prop = match_wrap_declared! { long, - MozScriptSizeMultiplier => MozScriptSizeMultiplier(value), - // Gecko uses Number values to signal that it is absolute - MozScriptLevel => MozScriptLevel::MozAbsolute(value as i32), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetPercentValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: f32, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::values::computed::Percentage; - use style::values::specified::MozLength; - use style::values::specified::length::LengthOrPercentage; - - let long = get_longhand_from_id!(property); - let pc = Percentage(value); - - let prop = match_wrap_declared! { long, - Height => MozLength::LengthOrPercentageOrAuto(pc.into()), - Width => MozLength::LengthOrPercentageOrAuto(pc.into()), - MarginTop => pc.into(), - MarginRight => pc.into(), - MarginBottom => pc.into(), - MarginLeft => pc.into(), - FontSize => LengthOrPercentage::from(pc).into(), - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetAutoValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::values::specified::{LengthOrPercentageOrAuto, MozLength}; - - let long = get_longhand_from_id!(property); - let auto = LengthOrPercentageOrAuto::Auto; - - let prop = match_wrap_declared! { long, - Height => MozLength::auto(), - Width => MozLength::auto(), - MarginTop => auto, - MarginRight => auto, - MarginBottom => auto, - MarginLeft => auto, - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, -) { - use style::properties::{PropertyDeclaration, LonghandId}; - use style::values::specified::Color; - - let long = get_longhand_from_id!(property); - let cc = Color::currentcolor(); - - let prop = match_wrap_declared! { long, - BorderTopColor => cc, - BorderRightColor => cc, - BorderBottomColor => cc, - BorderLeftColor => cc, - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetColorValue( - declarations: RawServoDeclarationBlockBorrowed, - property: nsCSSPropertyID, - value: structs::nscolor, -) { - use style::gecko::values::convert_nscolor_to_rgba; - use style::properties::{PropertyDeclaration, LonghandId}; - use style::properties::longhands; - use style::values::specified::Color; - - let long = get_longhand_from_id!(property); - let rgba = convert_nscolor_to_rgba(value); - let color = Color::rgba(rgba); - - let prop = match_wrap_declared! { long, - BorderTopColor => color, - BorderRightColor => color, - BorderBottomColor => color, - BorderLeftColor => color, - Color => longhands::color::SpecifiedValue(color), - BackgroundColor => color, - }; - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(prop, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetFontFamily( - declarations: RawServoDeclarationBlockBorrowed, - value: *const nsAString, -) { - use cssparser::{Parser, ParserInput}; - use style::properties::PropertyDeclaration; - use style::properties::longhands::font_family::SpecifiedValue as FontFamily; - - let string = unsafe { (*value).to_string() }; - let mut input = ParserInput::new(&string); - let mut parser = Parser::new(&mut input); - let result = FontFamily::parse_specified(&mut parser); - if let Ok(family) = result { - if parser.is_exhausted() { - let decl = PropertyDeclaration::FontFamily(family); - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(decl, Importance::Normal, DeclarationSource::CssOm); - }) - } - } -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage( - declarations: RawServoDeclarationBlockBorrowed, - value: *const nsAString, - raw_extra_data: *mut URLExtraData, -) { - use style::properties::PropertyDeclaration; - use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage; - use style::values::Either; - use style::values::generics::image::Image; - use style::values::specified::url::SpecifiedImageUrl; - - let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) }; - let string = unsafe { (*value).to_string() }; - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - if let Ok(url) = SpecifiedImageUrl::parse_from_string(string.into(), &context) { - let decl = PropertyDeclaration::BackgroundImage(BackgroundImage( - vec![Either::Second(Image::Url(url))] - )); - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(decl, Importance::Normal, DeclarationSource::CssOm); - }) - } -} - -#[no_mangle] -pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride( - declarations: RawServoDeclarationBlockBorrowed, -) { - use style::properties::PropertyDeclaration; - use style::values::specified::text::TextDecorationLine; - - let mut decoration = TextDecorationLine::none(); - decoration |= TextDecorationLine::COLOR_OVERRIDE; - let decl = PropertyDeclaration::TextDecorationLine(decoration); - write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| { - decls.push(decl, Importance::Normal, DeclarationSource::CssOm); - }) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CSSSupports2( - property: *const nsACString, - value: *const nsACString, -) -> bool { - let id = get_property_id_from_property!(property, false); - - let mut declarations = SourcePropertyDeclaration::new(); - parse_property_into( - &mut declarations, - id, - value, - DUMMY_URL_DATA, - structs::ParsingMode_Default, - QuirksMode::NoQuirks, - &NullReporter, - ).is_ok() -} - -#[no_mangle] -pub extern "C" fn Servo_CSSSupports(cond: *const nsACString) -> bool { - let condition = unsafe { cond.as_ref().unwrap().as_str_unchecked() }; - let mut input = ParserInput::new(&condition); - let mut input = Parser::new(&mut input); - let cond = input.parse_entirely(|i| parse_condition_or_declaration(i)); - if let Ok(cond) = cond { - let url_data = unsafe { dummy_url_data() }; - // NOTE(emilio): The supports API is not associated to any stylesheet, - // so the fact that there are no namespace map here is fine. - let context = ParserContext::new_for_cssom( - url_data, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - cond.eval(&context) - } else { - false - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_NoteExplicitHints( - element: RawGeckoElementBorrowed, - restyle_hint: nsRestyleHint, - change_hint: nsChangeHint, -) { - GeckoElement(element).note_explicit_hints(restyle_hint, change_hint); -} - -#[no_mangle] -pub extern "C" fn Servo_TakeChangeHint( - element: RawGeckoElementBorrowed, - was_restyled: *mut bool, -) -> u32 { - let was_restyled = unsafe { was_restyled.as_mut().unwrap() }; - let element = GeckoElement(element); - - let damage = match element.mutate_data() { - Some(mut data) => { - *was_restyled = data.is_restyle(); - - let damage = data.damage; - data.clear_restyle_state(); - damage - } - None => { - warn!("Trying to get change hint from unstyled element"); - *was_restyled = false; - GeckoRestyleDamage::empty() - } - }; - - debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage); - // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't - // work as return values with the Linux 32-bit ABI at the moment because - // they wrap the value in a struct, so for now just unwrap it. - damage.as_change_hint().0 -} - -#[no_mangle] -pub extern "C" fn Servo_ResolveStyle( - element: RawGeckoElementBorrowed, - _raw_data: RawServoStyleSetBorrowed, -) -> ComputedStyleStrong { - let element = GeckoElement(element); - debug!("Servo_ResolveStyle: {:?}", element); - let data = - element.borrow_data().expect("Resolving style on unstyled element"); - - debug_assert!(element.has_current_styles(&*data), - "Resolving style on {:?} without current styles: {:?}", element, data); - data.styles.primary().clone().into() -} - -#[no_mangle] -pub extern "C" fn Servo_ResolveStyleLazily( - element: RawGeckoElementBorrowed, - pseudo_type: CSSPseudoElementType, - rule_inclusion: StyleRuleInclusion, - snapshots: *const ServoElementSnapshotTable, - raw_data: RawServoStyleSetBorrowed, -) -> ComputedStyleStrong { - debug_assert!(!snapshots.is_null()); - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let element = GeckoElement(element); - let doc_data = PerDocumentStyleData::from_ffi(raw_data); - let data = doc_data.borrow(); - let rule_inclusion = RuleInclusion::from(rule_inclusion); - let pseudo = PseudoElement::from_pseudo_type(pseudo_type); - let finish = |styles: &ElementStyles, is_probe: bool| -> Option> { - match pseudo { - Some(ref pseudo) => { - get_pseudo_style( - &guard, - element, - pseudo, - rule_inclusion, - styles, - /* inherited_styles = */ None, - &*data, - is_probe, - /* matching_func = */ None, - ) - } - None => Some(styles.primary().clone()), - } - }; - - let is_before_or_after = pseudo.as_ref().map_or(false, |p| p.is_before_or_after()); - - // In the common case we already have the style. Check that before setting - // up all the computation machinery. - // - // Also, only probe in the ::before or ::after case, since their styles may - // not be in the `ElementData`, given they may exist but not be applicable - // to generate an actual pseudo-element (like, having a `content: none`). - if rule_inclusion == RuleInclusion::All { - let styles = element.mutate_data().and_then(|d| { - if d.has_styles() { - finish(&d.styles, is_before_or_after) - } else { - None - } - }); - if let Some(result) = styles { - return result.into(); - } - } - - // We don't have the style ready. Go ahead and compute it as necessary. - let shared = create_shared_context(&global_style_data, - &guard, - &data, - TraversalFlags::empty(), - unsafe { &*snapshots }); - let mut tlc = ThreadLocalStyleContext::new(&shared); - let mut context = StyleContext { - shared: &shared, - thread_local: &mut tlc, - }; - - let styles = resolve_style( - &mut context, - element, - rule_inclusion, - pseudo.as_ref() - ); - - finish(&styles, /* is_probe = */ false) - .expect("We're not probing, so we should always get a style back") - .into() -} - -#[no_mangle] -pub extern "C" fn Servo_ReparentStyle( - style_to_reparent: ComputedStyleBorrowed, - parent_style: ComputedStyleBorrowed, - parent_style_ignoring_first_line: ComputedStyleBorrowed, - layout_parent_style: ComputedStyleBorrowed, - element: RawGeckoElementBorrowedOrNull, - raw_data: RawServoStyleSetBorrowed, -) -> ComputedStyleStrong { - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let inputs = CascadeInputs::new_from_style(style_to_reparent); - let metrics = get_metrics_provider_for_product(); - let pseudo = style_to_reparent.pseudo(); - let element = element.map(GeckoElement); - - doc_data.stylist.cascade_style_and_visited( - element, - pseudo.as_ref(), - inputs, - &StylesheetGuards::same(&guard), - Some(parent_style), - Some(parent_style_ignoring_first_line), - Some(layout_parent_style), - &metrics, - /* rule_cache = */ None, - &mut RuleCacheConditions::default(), - ).into() -} - -#[cfg(feature = "gecko_debug")] -fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool { - let p = property.mProperty; - let id = get_property_id_from_nscsspropertyid!(p, false); - id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure -} - -#[cfg(not(feature = "gecko_debug"))] -fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool { - false -} - -fn create_context_for_animation<'a>( - per_doc_data: &'a PerDocumentStyleDataImpl, - font_metrics_provider: &'a FontMetricsProvider, - style: &'a ComputedValues, - parent_style: Option<&'a ComputedValues>, - for_smil_animation: bool, - rule_cache_conditions: &'a mut RuleCacheConditions, -) -> Context<'a> { - Context { - is_root_element: false, - builder: StyleBuilder::for_animation( - per_doc_data.stylist.device(), - style, - parent_style, - ), - font_metrics_provider: font_metrics_provider, - cached_system_font: None, - in_media_query: false, - quirks_mode: per_doc_data.stylist.quirks_mode(), - for_smil_animation, - for_non_inherited_property: None, - rule_cache_conditions: RefCell::new(rule_cache_conditions), - } -} - -struct PropertyAndIndex { - property: PropertyId, - index: usize, -} - -struct PrioritizedPropertyIter<'a> { - properties: &'a [PropertyValuePair], - sorted_property_indices: Vec, - curr: usize, -} - -impl<'a> PrioritizedPropertyIter<'a> { - fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter { - // If we fail to convert a nsCSSPropertyID into a PropertyId we - // shouldn't fail outright but instead by treating that property as the - // 'all' property we make it sort last. - let mut sorted_property_indices: Vec = - properties.iter().enumerate().map(|(index, pair)| { - let property = - PropertyId::from_nscsspropertyid(pair.mProperty) - .unwrap_or(PropertyId::Shorthand(ShorthandId::All)); - - PropertyAndIndex { property, index } - }).collect(); - sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property)); - - PrioritizedPropertyIter { - properties, - sorted_property_indices, - curr: 0, - } - } -} - -impl<'a> Iterator for PrioritizedPropertyIter<'a> { - type Item = &'a PropertyValuePair; - - fn next(&mut self) -> Option<&'a PropertyValuePair> { - if self.curr >= self.sorted_property_indices.len() { - return None - } - self.curr += 1; - Some(&self.properties[self.sorted_property_indices[self.curr - 1].index]) - } -} - -#[no_mangle] -pub extern "C" fn Servo_GetComputedKeyframeValues( - keyframes: RawGeckoKeyframeListBorrowed, - element: RawGeckoElementBorrowed, - style: ComputedStyleBorrowed, - raw_data: RawServoStyleSetBorrowed, - computed_keyframes: RawGeckoComputedKeyframeValuesListBorrowedMut -) { - use style::properties::LonghandIdSet; - - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let metrics = get_metrics_provider_for_product(); - - let element = GeckoElement(element); - let parent_element = element.inheritance_parent(); - let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); - let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x); - - let mut conditions = Default::default(); - let mut context = create_context_for_animation( - &data, - &metrics, - &style, - parent_style, - /* for_smil_animation = */ false, - &mut conditions, - ); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let default_values = data.default_computed_values(); - - let mut raw_custom_properties_block; // To make the raw block alive in the scope. - for (index, keyframe) in keyframes.iter().enumerate() { - let mut custom_properties = None; - for property in keyframe.mPropertyValues.iter() { - // Find the block for custom properties first. - if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable { - raw_custom_properties_block = unsafe { - &*property.mServoDeclarationBlock.mRawPtr.clone() - }; - let guard = Locked::::as_arc( - &raw_custom_properties_block).read_with(&guard); - custom_properties = guard.cascade_custom_properties_with_context(&context); - // There should be one PropertyDeclarationBlock for custom properties. - break; - } - } - - let ref mut animation_values = computed_keyframes[index]; - - let mut seen = LonghandIdSet::new(); - - let mut property_index = 0; - for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) { - if simulate_compute_values_failure(property) { - continue; - } - - let mut maybe_append_animation_value = |property: LonghandId, value: Option| { - if seen.contains(property) { - return; - } - seen.insert(property); - - // This is safe since we immediately write to the uninitialized values. - unsafe { animation_values.set_len((property_index + 1) as u32) }; - animation_values[property_index].mProperty = property.to_nscsspropertyid(); - match value { - Some(v) => { - animation_values[property_index].mValue.mServo.set_arc_leaky(Arc::new(v)); - }, - None => { - animation_values[property_index].mValue.mServo.mRawPtr = ptr::null_mut(); - }, - } - property_index += 1; - }; - - if property.mServoDeclarationBlock.mRawPtr.is_null() { - let property = - LonghandId::from_nscsspropertyid(property.mProperty); - if let Ok(prop) = property { - maybe_append_animation_value(prop, None); - } - continue; - } - - let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() }; - let declarations = Locked::::as_arc(&declarations); - let guard = declarations.read_with(&guard); - let iter = guard.to_animation_value_iter( - &mut context, - &default_values, - custom_properties.as_ref(), - ); - - for value in iter { - let id = value.id(); - maybe_append_animation_value(id, Some(value)); - } - } - } -} - -#[no_mangle] -pub extern "C" fn Servo_GetAnimationValues( - declarations: RawServoDeclarationBlockBorrowed, - element: RawGeckoElementBorrowed, - style: ComputedStyleBorrowed, - raw_data: RawServoStyleSetBorrowed, - animation_values: RawGeckoServoAnimationValueListBorrowedMut, -) { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let metrics = get_metrics_provider_for_product(); - - let element = GeckoElement(element); - let parent_element = element.inheritance_parent(); - let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); - let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x); - - let mut conditions = Default::default(); - let mut context = create_context_for_animation( - &data, - &metrics, - &style, - parent_style, - /* for_smil_animation = */ true, - &mut conditions, - ); - - let default_values = data.default_computed_values(); - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - let declarations = Locked::::as_arc(&declarations); - let guard = declarations.read_with(&guard); - let iter = guard.to_animation_value_iter( - &mut context, - &default_values, - None, // SMIL has no extra custom properties. - ); - for (index, anim) in iter.enumerate() { - unsafe { animation_values.set_len((index + 1) as u32) }; - animation_values[index].set_arc_leaky(Arc::new(anim)); - } -} - -#[no_mangle] -pub extern "C" fn Servo_AnimationValue_Compute( - element: RawGeckoElementBorrowed, - declarations: RawServoDeclarationBlockBorrowed, - style: ComputedStyleBorrowed, - raw_data: RawServoStyleSetBorrowed, -) -> RawServoAnimationValueStrong { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let metrics = get_metrics_provider_for_product(); - - let element = GeckoElement(element); - let parent_element = element.inheritance_parent(); - let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data()); - let parent_style = parent_data.as_ref().map(|d| d.styles.primary()).map(|x| &**x); - - let mut conditions = Default::default(); - let mut context = create_context_for_animation( - &data, - &metrics, - style, - parent_style, - /* for_smil_animation = */ false, - &mut conditions, - ); - - let default_values = data.default_computed_values(); - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let declarations = Locked::::as_arc(&declarations); - // We only compute the first element in declarations. - match declarations.read_with(&guard).declaration_importance_iter().next() { - Some((decl, imp)) if imp == Importance::Normal => { - let animation = AnimationValue::from_declaration( - decl, - &mut context, - None, // No extra custom properties for devtools. - default_values, - ); - animation.map_or(RawServoAnimationValueStrong::null(), |value| { - Arc::new(value).into_strong() - }) - }, - _ => RawServoAnimationValueStrong::null() - } -} - -#[no_mangle] -pub extern "C" fn Servo_AssertTreeIsClean(root: RawGeckoElementBorrowed) { - if !cfg!(feature = "gecko_debug") { - panic!("Calling Servo_AssertTreeIsClean in release build"); - } - - let root = GeckoElement(root); - debug!("Servo_AssertTreeIsClean: "); - debug!("{:?}", ShowSubtreeData(root.as_node())); - - fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) { - debug_assert!(!el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(), - "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}", - el, el.has_dirty_descendants(), el.has_animation_only_dirty_descendants()); - for child in el.traversal_children() { - if let Some(child) = child.as_element() { - assert_subtree_is_clean(child); - } - } - } - - assert_subtree_is_clean(root); -} - -#[no_mangle] -pub extern "C" fn Servo_IsWorkerThread() -> bool { - thread_state::get().is_worker() -} - -enum Offset { - Zero, - One -} - -fn fill_in_missing_keyframe_values( - all_properties: &LonghandIdSet, - timing_function: nsTimingFunctionBorrowed, - longhands_at_offset: &LonghandIdSet, - offset: Offset, - keyframes: RawGeckoKeyframeListBorrowedMut, -) { - // Return early if all animated properties are already set. - if longhands_at_offset.contains_all(all_properties) { - return; - } - - let keyframe = match offset { - Offset::Zero => unsafe { - Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function) - }, - Offset::One => unsafe { - Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function) - }, - }; - - // Append properties that have not been set at this offset. - for property in all_properties.iter() { - if !longhands_at_offset.contains(property) { - unsafe { - Gecko_AppendPropertyValuePair( - &mut (*keyframe).mPropertyValues, - property.to_nscsspropertyid() - ); - } - } - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName( - raw_data: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - name: *mut nsAtom, - inherited_timing_function: nsTimingFunctionBorrowed, - keyframes: RawGeckoKeyframeListBorrowedMut, -) -> bool { - debug_assert!(keyframes.len() == 0, "keyframes should be initially empty"); - - let element = GeckoElement(element); - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let name = Atom::from_raw(name); - - let animation = match data.stylist.get_animation(&name, element) { - Some(animation) => animation, - None => return false, - }; - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - let mut properties_set_at_current_offset = LonghandIdSet::new(); - let mut properties_set_at_start = LonghandIdSet::new(); - let mut properties_set_at_end = LonghandIdSet::new(); - let mut has_complete_initial_keyframe = false; - let mut has_complete_final_keyframe = false; - let mut current_offset = -1.; - - // Iterate over the keyframe rules backwards so we can drop overridden - // properties (since declarations in later rules override those in earlier - // ones). - for step in animation.steps.iter().rev() { - if step.start_percentage.0 != current_offset { - properties_set_at_current_offset.clear(); - current_offset = step.start_percentage.0; - } - - // Override timing_function if the keyframe has an animation-timing-function. - let timing_function = match step.get_animation_timing_function(&guard) { - Some(val) => val.into(), - None => *inherited_timing_function, - }; - - // Look for an existing keyframe with the same offset and timing - // function or else add a new keyframe at the beginning of the keyframe - // array. - let keyframe = Gecko_GetOrCreateKeyframeAtStart( - keyframes, - step.start_percentage.0 as f32, - &timing_function, - ); - - match step.value { - KeyframesStepValue::ComputedValues => { - // In KeyframesAnimation::from_keyframes if there is no 0% or - // 100% keyframe at all, we will create a 'ComputedValues' step - // to represent that all properties animated by the keyframes - // animation should be set to the underlying computed value for - // that keyframe. - for property in animation.properties_changed.iter() { - Gecko_AppendPropertyValuePair( - &mut (*keyframe).mPropertyValues, - property.to_nscsspropertyid(), - ); - } - if current_offset == 0.0 { - has_complete_initial_keyframe = true; - } else if current_offset == 1.0 { - has_complete_final_keyframe = true; - } - }, - KeyframesStepValue::Declarations { ref block } => { - let guard = block.read_with(&guard); - - let mut custom_properties = PropertyDeclarationBlock::new(); - - // Filter out non-animatable properties and properties with - // !important. - for declaration in guard.normal_declaration_iter() { - let id = declaration.id(); - - let id = match id { - PropertyDeclarationId::Longhand(id) => { - // Skip the 'display' property because although it - // is animatable from SMIL, it should not be - // animatable from CSS Animations. - if id == LonghandId::Display { - continue; - } - - if !id.is_animatable() { - continue; - } - - id - } - PropertyDeclarationId::Custom(..) => { - custom_properties.push( - declaration.clone(), - Importance::Normal, - DeclarationSource::CssOm, - ); - continue; - } - }; - - if properties_set_at_current_offset.contains(id) { - continue; - } - - let pair = Gecko_AppendPropertyValuePair( - &mut (*keyframe).mPropertyValues, - id.to_nscsspropertyid(), - ); - - (*pair).mServoDeclarationBlock.set_arc_leaky( - Arc::new(global_style_data.shared_lock.wrap( - PropertyDeclarationBlock::with_one( - declaration.clone(), - Importance::Normal, - ) - )) - ); - - if current_offset == 0.0 { - properties_set_at_start.insert(id); - } else if current_offset == 1.0 { - properties_set_at_end.insert(id); - } - properties_set_at_current_offset.insert(id); - } - - if custom_properties.any_normal() { - let pair = Gecko_AppendPropertyValuePair( - &mut (*keyframe).mPropertyValues, - nsCSSPropertyID::eCSSPropertyExtra_variable, - ); - - (*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new( - global_style_data.shared_lock.wrap(custom_properties) - )); - } - }, - } - } - - // Append property values that are missing in the initial or the final keyframes. - if !has_complete_initial_keyframe { - fill_in_missing_keyframe_values( - &animation.properties_changed, - inherited_timing_function, - &properties_set_at_start, - Offset::Zero, - keyframes, - ); - } - if !has_complete_final_keyframe { - fill_in_missing_keyframe_values( - &animation.properties_changed, - inherited_timing_function, - &properties_set_at_end, - Offset::One, - keyframes, - ); - } - true -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_GetFontFaceRules( - raw_data: RawServoStyleSetBorrowed, - rules: RawGeckoFontFaceRuleListBorrowedMut, -) { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - debug_assert_eq!(rules.len(), 0); - - let len: u32 = data - .stylist - .iter_extra_data_origins() - .map(|(d, _)| d.font_faces.len() as u32) - .sum(); - - // Reversed iterator because Gecko expects rules to appear sorted - // UserAgent first, Author last. - let font_face_iter = data - .stylist - .iter_extra_data_origins_rev() - .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o))); - - unsafe { rules.set_len(len) }; - for (src, dest) in font_face_iter.zip(rules.iter_mut()) { - dest.mRule.set_arc_leaky(src.0.clone()); - dest.mSheetType = src.1.into(); - } -} - -// XXX Ideally this should return a RawServoCounterStyleRuleBorrowedOrNull, -// but we cannot, because the value from AtomicRefCell::borrow() can only -// live in this function, and thus anything derived from it cannot get the -// same lifetime as raw_data in parameter. See bug 1451543. -#[no_mangle] -pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule( - raw_data: RawServoStyleSetBorrowed, - name: *mut nsAtom, -) -> *const RawServoCounterStyleRule { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - Atom::with(name, |name| { - data.stylist - .iter_extra_data_origins() - .filter_map(|(d, _)| d.counter_styles.get(name)) - .next() - .map_or(ptr::null(), |rule| rule.as_borrowed()) - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet( - raw_data: RawServoStyleSetBorrowed, -) -> *mut gfxFontFeatureValueSet { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - - let has_rule = - data.stylist - .iter_extra_data_origins() - .any(|(d, _)| !d.font_feature_values.is_empty()); - - if !has_rule { - return ptr::null_mut(); - } - - let font_feature_values_iter = - data.stylist - .iter_extra_data_origins_rev() - .flat_map(|(d, _)| d.font_feature_values.iter()); - - let set = unsafe { Gecko_ConstructFontFeatureValueSet() }; - for src in font_feature_values_iter { - let rule = src.read_with(&guard); - rule.set_at_rules(set); - } - set -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_ResolveForDeclarations( - raw_data: RawServoStyleSetBorrowed, - parent_style_context: ComputedStyleBorrowedOrNull, - declarations: RawServoDeclarationBlockBorrowed, -) -> ComputedStyleStrong { - let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let guards = StylesheetGuards::same(&guard); - - let parent_style = match parent_style_context { - Some(parent) => &*parent, - None => doc_data.default_computed_values(), - }; - - let declarations = Locked::::as_arc(&declarations); - - doc_data.stylist.compute_for_declarations::( - &guards, - parent_style, - declarations.clone_arc(), - ).into() -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis( - malloc_size_of: GeckoMallocSizeOf, - malloc_enclosing_size_of: GeckoMallocSizeOf, - sizes: *mut ServoStyleSetSizes, - raw_data: RawServoStyleSetBorrowed -) { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut(); - let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), - Some(malloc_enclosing_size_of.unwrap()), - None); - let sizes = unsafe { sizes.as_mut() }.unwrap(); - data.add_size_of(&mut ops, sizes); -} - -#[no_mangle] -pub extern "C" fn Servo_UACache_AddSizeOf( - malloc_size_of: GeckoMallocSizeOf, - malloc_enclosing_size_of: GeckoMallocSizeOf, - sizes: *mut ServoStyleSetSizes -) { - let mut ops = MallocSizeOfOps::new(malloc_size_of.unwrap(), - Some(malloc_enclosing_size_of.unwrap()), - None); - let sizes = unsafe { sizes.as_mut() }.unwrap(); - add_size_of_ua_cache(&mut ops, sizes); -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency( - raw_data: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - local_name: *mut nsAtom, -) -> bool { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let element = GeckoElement(element); - - unsafe { - Atom::with(local_name, |atom| { - data.stylist.any_applicable_rule_data(element, |data| { - data.might_have_attribute_dependency(atom) - }) - }) - } -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_HasStateDependency( - raw_data: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - state: u64, -) -> bool { - let element = GeckoElement(element); - - let state = ElementState::from_bits_truncate(state); - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - data.stylist.any_applicable_rule_data(element, |data| { - data.has_state_dependency(state) - }) -} - -#[no_mangle] -pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency( - raw_data: RawServoStyleSetBorrowed, - state: u64, -) -> bool { - let state = DocumentState::from_bits_truncate(state); - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - - data.stylist.has_document_state_dependency(state) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_GetCustomPropertyValue( - computed_values: ComputedStyleBorrowed, - name: *const nsAString, - value: *mut nsAString, -) -> bool { - let custom_properties = match computed_values.custom_properties() { - Some(p) => p, - None => return false, - }; - - let name = Atom::from(&*name); - let computed_value = match custom_properties.get(&name) { - Some(v) => v, - None => return false, - }; - - computed_value.to_css(&mut CssWriter::new(&mut *value)).unwrap(); - true -} - -#[no_mangle] -pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: ComputedStyleBorrowed) -> u32 { - match computed_values.custom_properties() { - Some(p) => p.len() as u32, - None => 0, - } -} - -#[no_mangle] -pub extern "C" fn Servo_GetCustomPropertyNameAt( - computed_values: ComputedStyleBorrowed, - index: u32, - name: *mut nsAString, -) -> bool { - let custom_properties = match computed_values.custom_properties() { - Some(p) => p, - None => return false, - }; - - let property_name = match custom_properties.get_key_at(index) { - Some(n) => n, - None => return false, - }; - - let name = unsafe { name.as_mut().unwrap() }; - name.assign(&*property_name.as_slice()); - - true -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_ReleaseArcStringData(string: *const RawOffsetArc) { - let string = string as *const RawOffsetArc; - // Cause RawOffsetArc::drop to run, releasing the strong reference to the string data. - let _ = ptr::read(string); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_CloneArcStringData( - string: *const RawOffsetArc, -) -> RawOffsetArc { - let string = string as *const RawOffsetArc; - let cloned = (*string).clone(); - mem::transmute::<_, RawOffsetArc>(cloned) -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_GetArcStringData( - string: *const RustString, - utf8_chars: *mut *const u8, - utf8_len: *mut u32, -) { - let string = &*(string as *const String); - *utf8_len = string.len() as u32; - *utf8_chars = string.as_ptr(); -} - -#[no_mangle] -pub extern "C" fn Servo_ProcessInvalidations( - set: RawServoStyleSetBorrowed, - element: RawGeckoElementBorrowed, - snapshots: *const ServoElementSnapshotTable, -) { - debug_assert!(!snapshots.is_null()); - - let element = GeckoElement(element); - debug_assert!(element.has_snapshot()); - debug_assert!(!element.handled_snapshot()); - - let mut data = element.mutate_data(); - debug_assert!(data.is_some()); - - let global_style_data = &*GLOBAL_STYLE_DATA; - let guard = global_style_data.shared_lock.read(); - let per_doc_data = PerDocumentStyleData::from_ffi(set).borrow(); - let shared_style_context = create_shared_context(&global_style_data, - &guard, - &per_doc_data, - TraversalFlags::empty(), - unsafe { &*snapshots }); - let mut data = data.as_mut().map(|d| &mut **d); - - if let Some(ref mut data) = data { - // FIXME(emilio): Ideally we could share the nth-index-cache across all - // the elements? - let result = data.invalidate_style_if_needed( - element, - &shared_style_context, - None, - &mut NthIndexCache::default(), - ); - - if result.has_invalidated_siblings() { - let parent = element.traversal_parent().expect("How could we invalidate siblings without a common parent?"); - unsafe { - parent.set_dirty_descendants(); - bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0); - } - } else if result.has_invalidated_descendants() { - unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) }; - } else if result.has_invalidated_self() { - unsafe { bindings::Gecko_NoteDirtyElement(element.0) }; - } - } -} - -#[no_mangle] -pub extern "C" fn Servo_HasPendingRestyleAncestor(element: RawGeckoElementBorrowed) -> bool { - let mut element = Some(GeckoElement(element)); - while let Some(e) = element { - if e.has_animations() { - return true; - } - - // If the element needs a frame, it means that we haven't styled it yet - // after it got inserted in the document, and thus we may need to do - // that for transitions and animations to trigger. - if e.needs_frame() { - return true; - } - - if let Some(data) = e.borrow_data() { - if !data.hint.is_empty() { - return true; - } - } - - element = e.traversal_parent(); - } - false -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_Parse( - selector_list: *const nsACString, -) -> *mut RawServoSelectorList { - use style::selector_parser::SelectorParser; - - debug_assert!(!selector_list.is_null()); - - let input = (*selector_list).as_str_unchecked(); - let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input) { - Ok(selector_list) => selector_list, - Err(..) => return ptr::null_mut(), - }; - - Box::into_raw(Box::new(selector_list)) as *mut RawServoSelectorList -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SelectorList_Drop(list: RawServoSelectorListOwned) { - let _ = list.into_box::<::selectors::SelectorList>(); -} - -fn parse_color( - value: &str, - error_reporter: Option<&ErrorReporter>, -) -> Result { - let mut input = ParserInput::new(value); - let mut parser = Parser::new(&mut input); - let url_data = unsafe { dummy_url_data() }; - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - let start_position = parser.position(); - parser.parse_entirely(|i| specified::Color::parse(&context, i)).map_err(|err| { - if let Some(error_reporter) = error_reporter { - match err.kind { - ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => { - let location = err.location.clone(); - let error = ContextualParseError::UnsupportedValue( - parser.slice_from(start_position), - err, - ); - error_reporter.report(location, error); - } - // Ignore other kinds of errors that might be reported, such as - // ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken), - // since Gecko doesn't report those to the error console. - _ => {} - } - } - }) -} - -#[no_mangle] -pub extern "C" fn Servo_IsValidCSSColor( - value: *const nsAString, -) -> bool { - let value = unsafe { (*value).to_string() }; - parse_color(&value, None).is_ok() -} - -#[no_mangle] -pub extern "C" fn Servo_ComputeColor( - raw_data: RawServoStyleSetBorrowedOrNull, - current_color: structs::nscolor, - value: *const nsAString, - result_color: *mut structs::nscolor, - was_current_color: *mut bool, - loader: *mut Loader, -) -> bool { - use style::gecko; - - let current_color = gecko::values::convert_nscolor_to_rgba(current_color); - let value = unsafe { (*value).to_string() }; - let result_color = unsafe { result_color.as_mut().unwrap() }; - - let reporter = unsafe { loader.as_mut() }.map(|loader| { - // Make an ErrorReporter that will report errors as being "from DOM". - ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut()) - }); - - match parse_color(&value, reporter.as_ref()) { - Ok(specified_color) => { - let computed_color = match raw_data { - Some(raw_data) => { - let data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let device = data.stylist.device(); - let quirks_mode = data.stylist.quirks_mode(); - Context::for_media_query_evaluation(device, quirks_mode, |context| { - specified_color.to_computed_color(Some(&context)) - }) - } - None => { - specified_color.to_computed_color(None) - } - }; - - match computed_color { - Some(computed_color) => { - let rgba = computed_color.to_rgba(current_color); - *result_color = gecko::values::convert_rgba_to_nscolor(&rgba); - if !was_current_color.is_null() { - unsafe { - *was_current_color = computed_color.is_currentcolor(); - } - } - true - } - None => false, - } - } - Err(_) => false, - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse( - value: *const nsAString, - result: *mut structs::nsStyleSides, -) -> bool { - let value = value.as_ref().unwrap().to_string(); - let result = result.as_mut().unwrap(); - - let mut input = ParserInput::new(&value); - let mut parser = Parser::new(&mut input); - - let url_data = dummy_url_data(); - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - let margin = parser.parse_entirely(|p| { - IntersectionObserverRootMargin::parse(&context, p) - }); - match margin { - Ok(margin) => { - margin.0.to_gecko_rect(result); - true - } - Err(..) => false, - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_ToString( - rect: *const structs::nsStyleSides, - result: *mut nsAString, -) { - let rect = Rect:::: - from_gecko_rect(rect.as_ref().unwrap()).unwrap(); - let root_margin = IntersectionObserverRootMargin(rect); - let mut writer = CssWriter::new(result.as_mut().unwrap()); - root_margin.to_css(&mut writer).unwrap(); -} - -#[no_mangle] -pub extern "C" fn Servo_ParseTransformIntoMatrix( - value: *const nsAString, - contain_3d: *mut bool, - result: *mut RawGeckoGfxMatrix4x4 -) -> bool { - use style::properties::longhands::transform; - - let string = unsafe { (*value).to_string() }; - let mut input = ParserInput::new(&string); - let mut parser = Parser::new(&mut input); - let context = ParserContext::new( - Origin::Author, - unsafe { dummy_url_data() }, - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks - ); - - let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) { - Ok(t) => t, - Err(..) => return false, - }; - - let (m, is_3d) = match transform.to_transform_3d_matrix(None) { - Ok(result) => result, - Err(..) => return false, - }; - - let result = unsafe { result.as_mut() }.expect("not a valid matrix"); - let contain_3d = unsafe { contain_3d.as_mut() }.expect("not a valid bool"); - *result = m.to_row_major_array(); - *contain_3d = is_3d; - true -} - -#[no_mangle] -pub extern "C" fn Servo_ParseFontShorthandForMatching( - value: *const nsAString, - data: *mut URLExtraData, - family: *mut structs::RefPtr, - style: nsCSSValueBorrowedMut, - stretch: nsCSSValueBorrowedMut, - weight: nsCSSValueBorrowedMut -) -> bool { - use style::properties::shorthands::font; - use style::values::generics::font::FontStyle as GenericFontStyle; - use style::values::specified::font::{FontFamily, FontWeight, FontStyle, SpecifiedFontStyle}; - - let string = unsafe { (*value).to_string() }; - let mut input = ParserInput::new(&string); - let mut parser = Parser::new(&mut input); - let url_data = unsafe { RefPtr::from_ptr_ref(&data) }; - let context = ParserContext::new( - Origin::Author, - url_data, - Some(CssRuleType::FontFace), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) { - Ok(f) => f, - Err(..) => return false, - }; - - // The system font is not acceptable, so we return false. - let family = unsafe { &mut *family }; - match font.font_family { - FontFamily::Values(list) => family.set_move(list.0), - FontFamily::System(_) => return false, - } - - let specified_font_style = match font.font_style { - FontStyle::Specified(ref s) => s, - FontStyle::System(_) => return false, - }; - match *specified_font_style { - GenericFontStyle::Normal => style.set_normal(), - GenericFontStyle::Italic => style.set_enum(structs::NS_FONT_STYLE_ITALIC as i32), - GenericFontStyle::Oblique(ref angle) => { - style.set_font_style(SpecifiedFontStyle::compute_angle(angle).degrees()) - } - } - - if font.font_stretch.get_system().is_some() { - return false; - } - stretch.set_from(&font.font_stretch); - - match font.font_weight { - FontWeight::Absolute(w) => weight.set_font_weight(w.compute().0), - // Resolve relative font weights against the initial of font-weight - // (normal, which is equivalent to 400). - FontWeight::Bolder => weight.set_enum(structs::NS_FONT_WEIGHT_BOLD as i32), - FontWeight::Lighter => weight.set_enum(structs::NS_FONT_WEIGHT_THIN as i32), - FontWeight::System(_) => return false, - } - - true -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SourceSizeList_Parse( - value: *const nsACString, -) -> *mut RawServoSourceSizeList { - let value = (*value).as_str_unchecked(); - let mut input = ParserInput::new(value); - let mut parser = Parser::new(&mut input); - - let context = ParserContext::new( - Origin::Author, - dummy_url_data(), - Some(CssRuleType::Style), - ParsingMode::DEFAULT, - QuirksMode::NoQuirks, - ); - - // NB: Intentionally not calling parse_entirely. - let list = SourceSizeList::parse(&context, &mut parser); - Box::into_raw(Box::new(list)) as *mut _ -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate( - raw_data: RawServoStyleSetBorrowed, - list: RawServoSourceSizeListBorrowedOrNull, -) -> i32 { - let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow(); - let device = doc_data.stylist.device(); - let quirks_mode = doc_data.stylist.quirks_mode(); - - let result = match list { - Some(list) => { - SourceSizeList::from_ffi(list).evaluate(device, quirks_mode) - } - None => { - SourceSizeList::empty().evaluate(device, quirks_mode) - } - }; - - result.0 -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: RawServoSourceSizeListOwned) { - let _ = list.into_box::(); -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges( - root: RawGeckoElementBorrowed, - document_style: RawServoStyleSetBorrowed, - non_document_styles: *const nsTArray, - states_changed: u64, -) { - use style::invalidation::element::document_state::DocumentStateInvalidationProcessor; - use style::invalidation::element::invalidator::TreeStyleInvalidator; - - let document_data = PerDocumentStyleData::from_ffi(document_style).borrow(); - - let iter = - document_data.stylist.iter_origins().map(|(data, _origin)| data) - .chain((*non_document_styles).iter().map(|author_styles| { - let styles: &_ = AuthorStyles::::from_ffi(author_styles); - &styles.data - })); - - let root = GeckoElement(root); - let mut processor = DocumentStateInvalidationProcessor::new( - iter, - DocumentState::from_bits_truncate(states_changed), - root.as_node().owner_doc().quirks_mode(), - ); - - let result = TreeStyleInvalidator::new( - root, - /* stack_limit_checker = */ None, - &mut processor, - ).invalidate(); - - debug_assert!(!result.has_invalidated_siblings(), "How in the world?"); - if result.has_invalidated_descendants() { - bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0); - } else if result.has_invalidated_self() { - bindings::Gecko_NoteDirtyElement(root.0); - } -} - -#[no_mangle] -pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: *const nsACString) -> u64 { - let name = name.as_ref().unwrap().as_str_unchecked(); - match NonTSPseudoClass::parse_non_functional(name) { - None => 0, - // Ignore :any-link since it contains both visited and unvisited state. - Some(NonTSPseudoClass::AnyLink) => 0, - Some(pseudo_class) => pseudo_class.state_flag().bits(), - } -} diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs deleted file mode 100644 index 79150f62bf7..00000000000 --- a/ports/geckolib/lib.rs +++ /dev/null @@ -1,25 +0,0 @@ -/* 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/. */ - - -extern crate cssparser; -#[macro_use] extern crate cstr; -extern crate libc; -#[macro_use] extern crate log; -extern crate malloc_size_of; -extern crate nsstring; -extern crate selectors; -extern crate servo_arc; -extern crate smallvec; -#[macro_use] extern crate style; -extern crate style_traits; - -mod error_reporter; -#[allow(non_snake_case)] -pub mod glue; -mod stylesheet_loader; - -// FIXME(bholley): This should probably go away once we harmonize the allocators. -#[no_mangle] -pub extern "C" fn je_malloc_usable_size(_: *const ::libc::c_void) -> ::libc::size_t { 0 } diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs deleted file mode 100644 index 7ed1db57bc3..00000000000 --- a/ports/geckolib/stylesheet_loader.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* 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 cssparser::SourceLocation; -use nsstring::nsCString; -use servo_arc::Arc; -use style::context::QuirksMode; -use style::error_reporting::NullReporter; -use style::gecko::data::GeckoStyleSheet; -use style::gecko::global_style_data::GLOBAL_STYLE_DATA; -use style::gecko_bindings::bindings; -use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; -use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets}; -use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder}; -use style::gecko_bindings::structs::URLExtraData; -use style::gecko_bindings::sugar::ownership::FFIArcHelpers; -use style::gecko_bindings::sugar::refptr::RefPtr; -use style::media_queries::MediaList; -use style::parser::ParserContext; -use style::shared_lock::{Locked, SharedRwLock}; -use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader}; -use style::stylesheets::StylesheetContents; -use style::stylesheets::import_rule::ImportSheet; -use style::values::CssUrl; - -pub struct StylesheetLoader(*mut Loader, *mut DomStyleSheet, *mut SheetLoadData, *mut LoaderReusableStyleSheets); - -impl StylesheetLoader { - pub fn new( - loader: *mut Loader, - parent: *mut DomStyleSheet, - parent_load_data: *mut SheetLoadData, - reusable_sheets: *mut LoaderReusableStyleSheets, - ) -> Self { - StylesheetLoader(loader, parent, parent_load_data, reusable_sheets) - } -} - -impl StyleStylesheetLoader for StylesheetLoader { - fn request_stylesheet( - &self, - url: CssUrl, - source_location: SourceLocation, - _context: &ParserContext, - lock: &SharedRwLock, - media: Arc>, - ) -> Arc> { - // After we get this raw pointer ImportRule will be moved into a lock and Arc - // and so the Arc pointer inside will also move, - // but the Url it points to or the allocating backing the String inside that Url won’t, - // so this raw pointer will still be valid. - - let child_sheet = unsafe { - Gecko_LoadStyleSheet(self.0, - self.1, - self.2, - self.3, - url.for_ffi(), - media.into_strong()) - }; - - debug_assert!(!child_sheet.is_null(), - "Import rules should always have a strong sheet"); - let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) }; - let stylesheet = ImportSheet::new(sheet); - Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet })) - } -} - -pub struct AsyncStylesheetParser { - load_data: RefPtr, - extra_data: RefPtr, - bytes: nsCString, - origin: Origin, - quirks_mode: QuirksMode, - line_number_offset: u32, -} - -impl AsyncStylesheetParser { - pub fn new( - load_data: RefPtr, - extra_data: RefPtr, - bytes: nsCString, - origin: Origin, - quirks_mode: QuirksMode, - line_number_offset: u32, - ) -> Self { - AsyncStylesheetParser { - load_data, - extra_data, - bytes, - origin, - quirks_mode, - line_number_offset, - } - } - - pub fn parse(self) { - let global_style_data = &*GLOBAL_STYLE_DATA; - let input: &str = unsafe { (*self.bytes).as_str_unchecked() }; - - // Note: Parallel CSS parsing doesn't report CSS errors. When errors - // are being logged, Gecko prevents the parallel parsing path from - // running. - let sheet = Arc::new(StylesheetContents::from_str( - input, self.extra_data.clone(), self.origin, - &global_style_data.shared_lock, Some(&self), &NullReporter, - self.quirks_mode.into(), self.line_number_offset) - ); - - unsafe { - bindings::Gecko_StyleSheet_FinishAsyncParse(self.load_data.get(), sheet.into_strong()); - } - } -} - -impl StyleStylesheetLoader for AsyncStylesheetParser { - fn request_stylesheet( - &self, - url: CssUrl, - source_location: SourceLocation, - _context: &ParserContext, - lock: &SharedRwLock, - media: Arc>, - ) -> Arc> { - let stylesheet = ImportSheet::new_pending(self.origin, self.quirks_mode); - let rule = Arc::new(lock.wrap(ImportRule { url: url.clone(), source_location, stylesheet })); - - unsafe { - bindings::Gecko_LoadStyleSheetAsync( - self.load_data.get(), - url.for_ffi(), - media.into_strong(), - rule.clone().into_strong() - ); - } - - rule - } -} diff --git a/ports/geckolib/tests/Cargo.toml b/ports/geckolib/tests/Cargo.toml deleted file mode 100644 index 0d670f2ec3d..00000000000 --- a/ports/geckolib/tests/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "stylo_tests" -version = "0.0.1" -authors = ["The Servo Project Developers"] -license = "MPL-2.0" - -build = "build.rs" - -[lib] -name = "stylo_tests" -path = "lib.rs" -doctest = false - -[dependencies] -atomic_refcell = "0.1" -cssparser = "0.23.0" -cstr = "0.1.2" -env_logger = { version = "0.5", default-features = false } -euclid = "0.17" -geckoservo = {path = "../../../ports/geckolib"} -libc = "0.2" -log = {version = "0.4", features = ["release_max_level_info"]} -malloc_size_of = {path = "../../../components/malloc_size_of"} -selectors = {path = "../../../components/selectors"} -size_of_test = {path = "../../../components/size_of_test"} -smallvec = "0.6" -style_traits = {path = "../../../components/style_traits"} -style = {path = "../../../components/style", features = ["gecko"]} - -[build-dependencies] -regex = "0.2" diff --git a/ports/geckolib/tests/build.rs b/ports/geckolib/tests/build.rs deleted file mode 100644 index 8de7326b574..00000000000 --- a/ports/geckolib/tests/build.rs +++ /dev/null @@ -1,94 +0,0 @@ -/* 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/. */ - -extern crate regex; - -use regex::Regex; -use std::env; -use std::fs::File; -use std::io::{BufRead, BufReader, Write}; -use std::path::Path; - -fn main() { - // https://github.com/rust-lang/cargo/issues/3544 - let style_out_dir = env::var_os("DEP_FOR SOME REASON THE LINKS KEY IS REQUIRED \ - TO PASS DATA AROUND BETWEEN BUILD SCRIPTS_OUT_DIR").unwrap(); - let root_path = Path::new("../../../"); - let bindings_file = Path::new(&style_out_dir).join("gecko/bindings.rs"); - let glue_file = root_path.join("ports/geckolib/glue.rs"); - - println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-changed={}", glue_file.display()); - println!("cargo:rerun-if-changed={}", bindings_file.display()); - - let env_out_dir = env::var("OUT_DIR").unwrap(); - let out_dir = Path::new(&env_out_dir); - - { - let output = out_dir.join("check_bindings.rs"); - let r = BufReader::new(File::open(bindings_file).unwrap()); - let mut w = File::create(output).unwrap(); - - w.write_all(b"fn assert_types() {\n").unwrap(); - - let matcher = Regex::new(r"fn\s*Servo_([a-zA-Z0-9_]+)\s*\(").unwrap(); - - for line in r.lines() { - let s = line.unwrap(); - for cap in matcher.captures_iter(&s) { - // This causes a mismatch in old libclangs (the ones that are - // used in linux32 mozilla-central) because it generates: - // - // *const nsTArray<*const RawServoStyleSet> - // - // Instead of: - // - // *const nsTArray - // - // Which is not a problem, but would cause this to not compile. - // - // Skip this until libclang is updated there. - // - // Also skip Servo_Element_IsDisplayContents because we - // forward-declare it in Element.h without the type bindgen uses - // to replace it by a reference, and it depends on the include - // order in ServoBindings.h. We have the same problem for - // ComputedStyle_{AddRef / Release}, we just don't hit it - // because they're included later... - if &cap[1] == "InvalidateStyleForDocStateChanges" || - &cap[1] == "Element_IsDisplayContents" - { - continue; - } - w.write_all(format!(" [ Servo_{0}, bindings::Servo_{0} ];\n", &cap[1]).as_bytes()).unwrap(); - } - } - - w.write_all(b"}\n").unwrap(); - } - - { - let output = out_dir.join("glue.rs"); - let r = BufReader::new(File::open(glue_file).unwrap()); - let mut w = File::create(output).unwrap(); - - w.write_all(b"pub use style::gecko::arc_types::*;\n").unwrap(); - - for line in r.lines() { - let s = line.unwrap().replace("pub extern \"C\" fn", "pub unsafe extern \"C\" fn"); - w.write_all(s.as_bytes()).unwrap(); - w.write_all(b"\n").unwrap(); - } - } - - File::create(out_dir.join("bindings.rs")) - .unwrap() - .write_all(format!("include!(concat!({:?}, \"/gecko/structs.rs\"));", - style_out_dir).as_bytes()) - .unwrap(); - - if env::var_os("MOZ_SRC").is_some() { - println!("cargo:rustc-cfg=linking_with_gecko") - } -} diff --git a/ports/geckolib/tests/lib.rs b/ports/geckolib/tests/lib.rs deleted file mode 100644 index 9981611d17a..00000000000 --- a/ports/geckolib/tests/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* 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/. */ - -// Disable this entire crate on Windows when Gecko symbols are not available -// as linking would fail: -// https://github.com/rust-lang/rust/pull/44603#issuecomment-338807312 -// -// On Linux and OS X linking succeeds anyway. -// Presumably these symbol declarations don’t need to be resolved -// as they’re not used in any code called from this crate. -#![cfg(any(linking_with_gecko, not(windows)))] - -extern crate atomic_refcell; -extern crate cssparser; -#[macro_use] extern crate cstr; -extern crate geckoservo; -#[macro_use] extern crate log; -extern crate malloc_size_of; -extern crate selectors; -extern crate smallvec; -#[macro_use] extern crate size_of_test; -#[macro_use] extern crate style; -extern crate style_traits; - -#[cfg(target_pointer_width = "64")] -mod size_of; -mod specified_values; - -mod servo_function_signatures; - -use style::*; - -#[allow(dead_code, improper_ctypes)] -mod bindings { - include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -} diff --git a/ports/geckolib/tests/servo_function_signatures.rs b/ports/geckolib/tests/servo_function_signatures.rs deleted file mode 100644 index 90d925fb1e1..00000000000 --- a/ports/geckolib/tests/servo_function_signatures.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* 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(unused)] - -use self::glue::*; -use style::gecko_bindings::bindings; -use style::gecko_properties::*; - -include!(concat!(env!("OUT_DIR"), "/check_bindings.rs")); - -#[path = "../../../ports/geckolib/error_reporter.rs"] -mod error_reporter; - -#[path = "../../../ports/geckolib/stylesheet_loader.rs"] -mod stylesheet_loader; - -#[allow(non_snake_case, unused_unsafe, private_no_mangle_fns)] -mod glue { - // this module pretends to be glue.rs, with the safe functions swapped for unsafe ones. This is - // a hack to compensate for the fact that `fn` types cannot coerce to `unsafe fn` types. The - // imports are populated with the same things so the type assertion should be equivalent - use geckoservo::*; - include!(concat!(env!("OUT_DIR"), "/glue.rs")); -} diff --git a/ports/geckolib/tests/size_of.rs b/ports/geckolib/tests/size_of.rs deleted file mode 100644 index 8905650dc2a..00000000000 --- a/ports/geckolib/tests/size_of.rs +++ /dev/null @@ -1,51 +0,0 @@ -/* 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 selectors; -use servo_arc::Arc; -use style; -use style::applicable_declarations::ApplicableDeclarationBlock; -use style::data::{ElementData, ElementStyles}; -use style::gecko::selector_parser::{self, SelectorImpl}; -use style::properties::ComputedValues; -use style::rule_tree::{RuleNode, StrongRuleNode}; -use style::values::computed; -use style::values::specified; - -size_of_test!(size_of_selector, selectors::parser::Selector, 8); -size_of_test!(size_of_pseudo_element, selector_parser::PseudoElement, 24); - -size_of_test!(size_of_component, selectors::parser::Component, 32); -size_of_test!(size_of_pseudo_class, selector_parser::NonTSPseudoClass, 24); - -// The size of this is critical to performance on the bloom-basic microbenchmark. -// When iterating over a large Rule array, we want to be able to fast-reject -// selectors (with the inline hashes) with as few cache misses as possible. -size_of_test!(test_size_of_rule, style::stylist::Rule, 32); - -// Large pages generate tens of thousands of ComputedValues. -size_of_test!(test_size_of_cv, ComputedValues, 248); - -size_of_test!(test_size_of_option_arc_cv, Option>, 8); -size_of_test!(test_size_of_option_rule_node, Option, 8); - -size_of_test!(test_size_of_element_styles, ElementStyles, 16); -size_of_test!(test_size_of_element_data, ElementData, 24); - -size_of_test!(test_size_of_property_declaration, style::properties::PropertyDeclaration, 32); - -size_of_test!(test_size_of_application_declaration_block, ApplicableDeclarationBlock, 16); -size_of_test!(test_size_of_rule_node, RuleNode, 72); - -// This is huge, but we allocate it on the stack and then never move it, -// we only pass `&mut SourcePropertyDeclaration` references around. -size_of_test!(test_size_of_parsed_declaration, style::properties::SourcePropertyDeclaration, 608); - -size_of_test!(test_size_of_computed_image, computed::image::Image, 32); -size_of_test!(test_size_of_specified_image, specified::image::Image, 32); - -// FIXME(bz): These can shrink if we move the None_ value inside the -// enum instead of paying an extra word for the Either discriminant. -size_of_test!(test_size_of_computed_image_layer, computed::image::ImageLayer, 32); -size_of_test!(test_size_of_specified_image_layer, specified::image::ImageLayer, 32); diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index dea0fe9da5d..94cb95801bc 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -33,7 +33,6 @@ mod parsing; mod properties; mod rule_tree; mod size_of; -#[path = "../../../ports/geckolib/tests/specified_values.rs"] mod specified_values; mod str; mod stylesheets; diff --git a/ports/geckolib/tests/specified_values.rs b/tests/unit/style/specified_values.rs similarity index 100% rename from ports/geckolib/tests/specified_values.rs rename to tests/unit/style/specified_values.rs