diff --git a/components/style/build_gecko.rs b/components/style/build_gecko.rs index 708ed8c381c..21f8b05dbf6 100644 --- a/components/style/build_gecko.rs +++ b/components/style/build_gecko.rs @@ -251,6 +251,7 @@ mod bindings { ]; let whitelist = [ "RawGecko.*", + "mozilla::ServoStyleSheet", "mozilla::ServoElementSnapshot.*", "mozilla::ConsumeStyleBehavior", "mozilla::css::SheetParsingMode", @@ -527,6 +528,8 @@ mod bindings { "nsStyleXUL", "nscoord", "nsresult", + "Loader", + "ServoStyleSheet", ]; struct ArrayType { cpp_type: &'static str, @@ -541,6 +544,7 @@ mod bindings { "RawServoStyleSheet", "RawServoDeclarationBlock", "RawServoStyleRule", + "RawServoImportRule", ]; struct ServoOwnedType { name: &'static str, diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 62e069e9cb1..73cbc31c634 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -11,7 +11,7 @@ use app_units::Au; use gecko::values::{convert_rgba_to_nscolor, StyleCoordHelpers}; use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue}; -use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule}; +use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule, RawServoImportRule}; use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules}; use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage}; use gecko_bindings::structs::nsresult; @@ -19,7 +19,7 @@ use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut}; use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI}; use parking_lot::RwLock; use properties::{ComputedValues, PropertyDeclarationBlock}; -use stylesheets::{CssRules, RulesMutateError, Stylesheet, StyleRule}; +use stylesheets::{CssRules, RulesMutateError, Stylesheet, StyleRule, ImportRule}; use values::computed::{CalcLengthOrPercentage, Gradient, Image, LengthOrPercentage, LengthOrPercentageOrAuto}; unsafe impl HasFFI for Stylesheet { @@ -46,6 +46,11 @@ unsafe impl HasFFI for RwLock { } unsafe impl HasArcFFI for RwLock {} +unsafe impl HasFFI for RwLock { + type FFIType = RawServoImportRule; +} +unsafe impl HasArcFFI for RwLock {} + impl From for nsStyleCoord_CalcValue { fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue { let has_percentage = other.percentage.is_some(); diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index c8c4bdf686f..389df0e845f 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -143,6 +143,8 @@ unsafe impl Send for nsStyleXUL {} unsafe impl Sync for nsStyleXUL {} use gecko_bindings::structs::nscoord; use gecko_bindings::structs::nsresult; +use gecko_bindings::structs::Loader; +use gecko_bindings::structs::ServoStyleSheet; pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray; pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong; pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues; @@ -169,6 +171,11 @@ pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule; pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>; enum RawServoStyleRuleVoid { } pub struct RawServoStyleRule(RawServoStyleRuleVoid); +pub type RawServoImportRuleStrong = ::gecko_bindings::sugar::ownership::Strong; +pub type RawServoImportRuleBorrowed<'a> = &'a RawServoImportRule; +pub type RawServoImportRuleBorrowedOrNull<'a> = Option<&'a RawServoImportRule>; +enum RawServoImportRuleVoid { } +pub struct RawServoImportRule(RawServoImportRuleVoid); pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned; pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull; pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet; @@ -236,6 +243,12 @@ extern "C" { extern "C" { pub fn Servo_StyleRule_Release(ptr: RawServoStyleRuleBorrowed); } +extern "C" { + pub fn Servo_ImportRule_AddRef(ptr: RawServoImportRuleBorrowed); +} +extern "C" { + pub fn Servo_ImportRule_Release(ptr: RawServoImportRuleBorrowed); +} extern "C" { pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned); } @@ -314,6 +327,13 @@ extern "C" { pub fn Gecko_GetDocumentElement(document: RawGeckoDocumentBorrowed) -> RawGeckoElementBorrowedOrNull; } +extern "C" { + pub fn Gecko_LoadStyleSheet(loader: *mut Loader, + parent: *mut ServoStyleSheet, + import_rule: RawServoImportRuleStrong, + url_bytes: *const u8, url_length: u32, + media_bytes: *const u8, media_length: u32); +} extern "C" { pub fn Gecko_MaybeCreateStyleChildrenIterator(node: RawGeckoNodeBorrowed) -> StyleChildrenIteratorOwnedOrNull; @@ -970,7 +990,10 @@ extern "C" { -> RawServoStyleSheetStrong; } extern "C" { - pub fn Servo_StyleSheet_FromUTF8Bytes(data: *const nsACString_internal, + pub fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, + gecko_stylesheet: + *mut ServoStyleSheet, + data: *const nsACString_internal, parsing_mode: SheetParsingMode, base_url: *const nsACString_internal, @@ -980,6 +1003,22 @@ extern "C" { *mut ThreadSafePrincipalHolder) -> RawServoStyleSheetStrong; } +extern "C" { + pub fn Servo_ImportRule_GetSheet(import_rule: RawServoImportRuleBorrowed) + -> RawServoStyleSheetStrong; +} +extern "C" { + pub fn Servo_StyleSheet_ClearAndUpdate(stylesheet: + RawServoStyleSheetBorrowed, + loader: *mut Loader, + gecko_stylesheet: + *mut ServoStyleSheet, + data: *const nsACString_internal, + base: *mut ThreadSafeURIHolder, + referrer: *mut ThreadSafeURIHolder, + principal: + *mut ThreadSafePrincipalHolder); +} extern "C" { pub fn Servo_StyleSheet_HasRules(sheet: RawServoStyleSheetBorrowed) -> bool; diff --git a/components/style/gecko_bindings/structs_debug.rs b/components/style/gecko_bindings/structs_debug.rs index a6e593b08a1..f2d52e59283 100644 --- a/components/style/gecko_bindings/structs_debug.rs +++ b/components/style/gecko_bindings/structs_debug.rs @@ -1005,6 +1005,7 @@ pub mod root { pub const NS_STYLE_DISPLAY_MODE_BROWSER: ::std::os::raw::c_uint = 0; pub const NS_STYLE_DISPLAY_MODE_MINIMAL_UI: ::std::os::raw::c_uint = 1; pub const NS_STYLE_DISPLAY_MODE_STANDALONE: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_DISPLAY_MODE_FULLSCREEN: ::std::os::raw::c_uint = 3; pub const NS_STYLE_INHERIT_MASK: ::std::os::raw::c_uint = 16777215; pub const NS_STYLE_HAS_TEXT_DECORATION_LINES: ::std::os::raw::c_uint = 16777216; @@ -2362,6 +2363,14 @@ pub mod root { assert_eq!(::std::mem::size_of::() , 88usize); assert_eq!(::std::mem::align_of::() , 8usize); } + #[repr(C)] + #[derive(Debug, Copy)] + pub struct ServoStyleSheet { + pub _address: u8, + } + impl Clone for ServoStyleSheet { + fn clone(&self) -> Self { *self } + } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Side { @@ -2593,7 +2602,7 @@ pub mod root { * The FramePropertyTable is optimized for storing 0 or 1 properties on * a given frame. Storing very large numbers of properties on a single * frame will not be efficient. - * + * * Property values are passed as void* but do not actually have to be * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to * store int32_t values. Null/zero values can be stored and retrieved. diff --git a/components/style/gecko_bindings/structs_release.rs b/components/style/gecko_bindings/structs_release.rs index 6b815c495c3..0ff3efce55f 100644 --- a/components/style/gecko_bindings/structs_release.rs +++ b/components/style/gecko_bindings/structs_release.rs @@ -1005,6 +1005,7 @@ pub mod root { pub const NS_STYLE_DISPLAY_MODE_BROWSER: ::std::os::raw::c_uint = 0; pub const NS_STYLE_DISPLAY_MODE_MINIMAL_UI: ::std::os::raw::c_uint = 1; pub const NS_STYLE_DISPLAY_MODE_STANDALONE: ::std::os::raw::c_uint = 2; + pub const NS_STYLE_DISPLAY_MODE_FULLSCREEN: ::std::os::raw::c_uint = 3; pub const NS_STYLE_INHERIT_MASK: ::std::os::raw::c_uint = 16777215; pub const NS_STYLE_HAS_TEXT_DECORATION_LINES: ::std::os::raw::c_uint = 16777216; @@ -2345,6 +2346,14 @@ pub mod root { assert_eq!(::std::mem::size_of::() , 80usize); assert_eq!(::std::mem::align_of::() , 8usize); } + #[repr(C)] + #[derive(Debug, Copy)] + pub struct ServoStyleSheet { + pub _address: u8, + } + impl Clone for ServoStyleSheet { + fn clone(&self) -> Self { *self } + } #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum Side { @@ -2576,7 +2585,7 @@ pub mod root { * The FramePropertyTable is optimized for storing 0 or 1 properties on * a given frame. Storing very large numbers of properties on a single * frame will not be efficient. - * + * * Property values are passed as void* but do not actually have to be * valid pointers. You can use NS_INT32_TO_PTR/NS_PTR_TO_INT32 to * store int32_t values. Null/zero values can be stored and retrieved. diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index c198d53c71d..6c17f8caaef 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -36,12 +36,15 @@ use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedVal use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong}; use style::gecko_bindings::bindings::{nsACString, nsAString}; use style::gecko_bindings::bindings::RawGeckoElementBorrowed; +use style::gecko_bindings::bindings::RawServoImportRuleBorrowed; use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull; use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t; use style::gecko_bindings::structs; use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom, nsCSSPropertyID}; use style::gecko_bindings::structs::{ThreadSafePrincipalHolder, ThreadSafeURIHolder}; use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint}; +use style::gecko_bindings::structs::Loader; +use style::gecko_bindings::structs::ServoStyleSheet; use style::gecko_bindings::structs::nsresult; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; @@ -55,7 +58,8 @@ use style::restyle_hints::RestyleHint; use style::selector_parser::PseudoElementCascadeType; use style::sequential; use style::string_cache::Atom; -use style::stylesheets::{CssRule, CssRules, Origin, Stylesheet, StyleRule}; +use style::stylesheets::{CssRule, CssRules, Origin, Stylesheet, StyleRule, ImportRule}; +use style::stylesheets::StylesheetLoader as StyleStylesheetLoader; use style::thread_state; use style::timer::Timer; use style::traversal::{resolve_style, DomTraversal}; @@ -225,9 +229,8 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl SheetParsingMode::eUserSheetFeatures => Origin::User, SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent, }; - let loader = StylesheetLoader::new(); let sheet = Arc::new(Stylesheet::from_str( - "", url, origin, Default::default(), Some(&loader), + "", url, origin, Default::default(), None, Box::new(StdoutErrorReporter), extra_data)); unsafe { transmute(sheet) @@ -235,7 +238,9 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl } #[no_mangle] -pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(data: *const nsACString, +pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(loader: *mut Loader, + stylesheet: *mut ServoStyleSheet, + data: *const nsACString, mode: SheetParsingMode, base_url: *const nsACString, base: *mut ThreadSafeURIHolder, @@ -257,15 +262,61 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(data: *const nsACString, referrer: Some(GeckoArcURI::new(referrer)), principal: Some(GeckoArcPrincipal::new(principal)), }}; - let loader = StylesheetLoader::new(); + let loader = if loader.is_null() { + None + } else { + Some(StylesheetLoader::new(loader, stylesheet)) + }; + + // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason? + let loader: Option<&StyleStylesheetLoader> = match loader { + None => None, + Some(ref s) => Some(s), + }; + let sheet = Arc::new(Stylesheet::from_str( - input, url, origin, Default::default(), Some(&loader), + input, url, origin, Default::default(), loader, Box::new(StdoutErrorReporter), extra_data)); unsafe { transmute(sheet) } } +#[no_mangle] +pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheetBorrowed, + loader: *mut Loader, + gecko_stylesheet: *mut ServoStyleSheet, + data: *const nsACString, + base: *mut ThreadSafeURIHolder, + referrer: *mut ThreadSafeURIHolder, + principal: *mut ThreadSafePrincipalHolder) +{ + let input = unsafe { data.as_ref().unwrap().as_str_unchecked() }; + let extra_data = unsafe { ParserContextExtraData { + base: Some(GeckoArcURI::new(base)), + referrer: Some(GeckoArcURI::new(referrer)), + principal: Some(GeckoArcPrincipal::new(principal)), + }}; + + let loader = if loader.is_null() { + None + } else { + Some(StylesheetLoader::new(loader, gecko_stylesheet)) + }; + + // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason? + let loader: Option<&StyleStylesheetLoader> = match loader { + None => None, + Some(ref s) => Some(s), + }; + + let sheet = Stylesheet::as_arc(&stylesheet); + sheet.rules.write().0.clear(); + + Stylesheet::update_from_str(&sheet, input, loader, + Box::new(StdoutErrorReporter), extra_data); +} + #[no_mangle] pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed, raw_sheet: RawServoStyleSheetBorrowed, @@ -457,6 +508,16 @@ pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowe rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap(); } +#[no_mangle] +pub extern "C" fn Servo_ImportRule_AddRef(rule: RawServoImportRuleBorrowed) -> () { + unsafe { RwLock::::addref(rule) }; +} + +#[no_mangle] +pub extern "C" fn Servo_ImportRule_Release(rule: RawServoImportRuleBorrowed) -> () { + unsafe { RwLock::::release(rule) }; +} + #[no_mangle] pub extern "C" fn Servo_ComputedValues_GetForAnonymousBox(parent_style_or_null: ServoComputedValuesBorrowedOrNull, pseudo_tag: *mut nsIAtom, @@ -832,6 +893,14 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed, } } +#[no_mangle] +pub extern "C" fn Servo_ImportRule_GetSheet(import_rule: + RawServoImportRuleBorrowed) + -> RawServoStyleSheetStrong { + let import_rule = RwLock::::as_arc(&import_rule); + unsafe { transmute(import_rule.read().stylesheet.clone()) } +} + #[no_mangle] pub extern "C" fn Servo_CheckChangeHint(element: RawGeckoElementBorrowed) -> nsChangeHint { diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 9db89333747..a48559d6857 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -3,19 +3,45 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use parking_lot::RwLock; +use std::mem; use std::sync::Arc; +use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; +use style::gecko_bindings::structs::{Loader, ServoStyleSheet}; use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader}; +use style_traits::ToCss; -pub struct StylesheetLoader; +pub struct StylesheetLoader(*mut Loader, *mut ServoStyleSheet); impl StylesheetLoader { - pub fn new() -> Self { - StylesheetLoader + pub fn new(loader: *mut Loader, parent: *mut ServoStyleSheet) -> Self { + StylesheetLoader(loader, parent) } } impl StyleStylesheetLoader for StylesheetLoader { - fn request_stylesheet(&self, _import: &Arc>) { - // FIXME(emilio): Implement `@import` in stylo. + fn request_stylesheet(&self, import_rule: &Arc>) { + let import = import_rule.read(); + let (spec_bytes, spec_len) = import.url.as_slice_components() + .expect("Import only loads valid URLs"); + + // TODO(emilio): We probably want to share media representation with + // Gecko in Stylo. + // + // This also allows us to get rid of a bunch of extra work to evaluate + // and ensure parity, and shouldn't be much Gecko work given we always + // evaluate them on the main thread. + // + // Meanwhile, this works. + let media = import.stylesheet.media.read().to_css_string(); + + unsafe { + Gecko_LoadStyleSheet(self.0, + self.1, + mem::transmute(import_rule.clone()), + spec_bytes, + spec_len as u32, + media.as_bytes().as_ptr(), + media.len() as u32); + } } }