From 56e70aec517b3791be252f52d45135bf8421c861 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Thu, 15 Sep 2016 16:03:41 +0900 Subject: [PATCH 1/4] Bug 1302949 - Add a method to parse a property-value pair into a declaration block; r=Manishearth The property may be a shorthand property in which case the declaration block will contain the expanded longhand properties and values. MozReview-Commit-ID: KxqlYgbIZqL --- components/style/gecko_bindings/bindings.rs | 12 +++++ ports/geckolib/Cargo.lock | 2 + ports/geckolib/Cargo.toml | 1 + ports/geckolib/glue.rs | 55 ++++++++++++++++++++- ports/geckolib/lib.rs | 1 + tests/unit/stylo/Cargo.toml | 1 + tests/unit/stylo/lib.rs | 1 + 7 files changed, 71 insertions(+), 2 deletions(-) diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 3781bbe81d4..46131cf6908 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -847,6 +847,18 @@ extern "C" { reference: RawServoStyleSheetBorrowed); } +extern "C" { + pub fn Servo_ParseProperty(property_bytes: *const u8, + property_length: u32, + value_bytes: *const u8, + value_length: u32, + base_bytes: *const u8, + base_length: u32, + base: *mut ThreadSafeURIHolder, + referrer: *mut ThreadSafeURIHolder, + principal: *mut ThreadSafePrincipalHolder) + -> ServoDeclarationBlockStrong; +} extern "C" { pub fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32, cache: *mut nsHTMLCSSStyleSheet) diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index 8b9e70c0d8f..17b8d28f868 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -3,6 +3,7 @@ name = "geckoservo" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -407,6 +408,7 @@ name = "stylo_tests" version = "0.0.1" dependencies = [ "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "geckoservo 0.0.1", diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 50260374172..ebe538fabb9 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["staticlib", "rlib"] [dependencies] app_units = "0.3" +cssparser = {version = "0.7"} env_logger = "0.3" euclid = "0.10.1" lazy_static = "0.2" diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 4d710c7376c..33a78d874b2 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; +use cssparser::Parser; use env_logger; use euclid::Size2D; use parking_lot::RwLock; @@ -37,8 +38,10 @@ use style::gecko_bindings::structs::nsRestyleHint; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; use style::parallel; -use style::parser::ParserContextExtraData; -use style::properties::{ComputedValues, parse_one_declaration}; +use style::parser::{ParserContext, ParserContextExtraData}; +use style::properties::{ComputedValues, Importance, PropertyDeclaration}; +use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock}; +use style::properties::parse_one_declaration; use style::selector_impl::PseudoElementCascadeType; use style::sequential; use style::string_cache::Atom; @@ -338,6 +341,54 @@ pub extern "C" fn Servo_StyleSet_Drop(data: RawServoStyleSetOwned) -> () { let _ = data.into_box::(); } + +#[no_mangle] +pub extern "C" fn Servo_ParseProperty(property_bytes: *const u8, + property_length: u32, + value_bytes: *const u8, + value_length: u32, + base_bytes: *const u8, + base_length: u32, + base: *mut ThreadSafeURIHolder, + referrer: *mut ThreadSafeURIHolder, + principal: *mut ThreadSafePrincipalHolder) + -> ServoDeclarationBlockStrong { + // All this string wrangling is temporary until the Gecko string bindings land (bug 1294742). + let name = unsafe { from_utf8_unchecked(slice::from_raw_parts(property_bytes, + property_length as usize)) }; + let value_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(value_bytes, + value_length as usize)) }; + let base_str = unsafe { from_utf8_unchecked(slice::from_raw_parts(base_bytes, + base_length as usize)) }; + let base_url = Url::parse(base_str).unwrap(); + let extra_data = ParserContextExtraData { + base: Some(GeckoArcURI::new(base)), + referrer: Some(GeckoArcURI::new(referrer)), + principal: Some(GeckoArcPrincipal::new(principal)), + }; + + let context = ParserContext::new_with_extra_data(Origin::Author, &base_url, + Box::new(StdoutErrorReporter), + extra_data); + + let mut results = vec![]; + match PropertyDeclaration::parse(name, &context, &mut Parser::new(value_str), + &mut results, false) { + PropertyDeclarationParseResult::ValidOrIgnoredDeclaration => {}, + _ => return ServoDeclarationBlockStrong::null(), + } + + let results = results.into_iter().map(|r| (r, Importance::Normal)).collect(); + + Arc::new(GeckoDeclarationBlock { + declarations: Some(Arc::new(RwLock::new(PropertyDeclarationBlock { + declarations: results, + important_count: 0, + }))), + cache: AtomicPtr::new(ptr::null_mut()), + immutable: AtomicBool::new(false), + }).into_strong() +} #[no_mangle] pub extern "C" fn Servo_ParseStyleAttribute(bytes: *const u8, length: u32, cache: *mut nsHTMLCSSStyleSheet) diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index 0b6493db278..cdfca9b8653 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -5,6 +5,7 @@ #[macro_use]extern crate style; extern crate app_units; +extern crate cssparser; extern crate env_logger; extern crate euclid; extern crate libc; diff --git a/tests/unit/stylo/Cargo.toml b/tests/unit/stylo/Cargo.toml index 300f31cea64..87dc62cd042 100644 --- a/tests/unit/stylo/Cargo.toml +++ b/tests/unit/stylo/Cargo.toml @@ -13,6 +13,7 @@ doctest = false [dependencies] app_units = "0.3" +cssparser = {version = "0.7"} env_logger = "0.3" euclid = "0.10.1" lazy_static = "0.2" diff --git a/tests/unit/stylo/lib.rs b/tests/unit/stylo/lib.rs index d4d3711279c..8690c17f517 100644 --- a/tests/unit/stylo/lib.rs +++ b/tests/unit/stylo/lib.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate app_units; +extern crate cssparser; extern crate env_logger; extern crate euclid; extern crate geckoservo; From 61bcc3a2ef6c92ce7b43732821cdb9eb03a5755b Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Thu, 15 Sep 2016 16:09:54 +0900 Subject: [PATCH 2/4] Bug 1302949 - Add a method to Gecko bindings for comparing declaration blocks; r=Manishearth MozReview-Commit-ID: EtX2oLXdGNm --- components/style/gecko/wrapper.rs | 10 ++++++++++ components/style/gecko_bindings/bindings.rs | 5 +++++ ports/geckolib/glue.rs | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index f2a7532883c..407ff4694e4 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -70,6 +70,16 @@ pub struct GeckoDeclarationBlock { pub immutable: AtomicBool, } +impl PartialEq for GeckoDeclarationBlock { + fn eq(&self, other: &GeckoDeclarationBlock) -> bool { + match (&self.declarations, &other.declarations) { + (&None, &None) => true, + (&Some(ref s), &Some(ref other)) => *s.read() == *other.read(), + _ => false, + } + } +} + unsafe impl HasFFI for GeckoDeclarationBlock { type FFIType = bindings::ServoDeclarationBlock; } diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 46131cf6908..92675468073 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -872,6 +872,11 @@ extern "C" { pub fn Servo_DeclarationBlock_Release(declarations: ServoDeclarationBlockBorrowed); } +extern "C" { + pub fn Servo_DeclarationBlock_Equals(a: ServoDeclarationBlockBorrowed, + b: ServoDeclarationBlockBorrowed) + -> bool; +} extern "C" { pub fn Servo_DeclarationBlock_GetCache(declarations: ServoDeclarationBlockBorrowed) diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 33a78d874b2..499c9c9d4e1 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -413,6 +413,13 @@ pub extern "C" fn Servo_DeclarationBlock_Release(declarations: ServoDeclarationB unsafe { GeckoDeclarationBlock::release(declarations) }; } +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_Equals(a: ServoDeclarationBlockBorrowed, + b: ServoDeclarationBlockBorrowed) + -> bool { + GeckoDeclarationBlock::as_arc(&a) == GeckoDeclarationBlock::as_arc(&b) +} + #[no_mangle] pub extern "C" fn Servo_DeclarationBlock_GetCache(declarations: ServoDeclarationBlockBorrowed) -> *mut nsHTMLCSSStyleSheet { From 1c78e1cb20a4ab93003dbbe92a725fb094203b43 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Thu, 15 Sep 2016 16:55:08 +0900 Subject: [PATCH 3/4] Bug 1302949 - Add a method to serialize a declaration block as a single value; r=Manishearth MozReview-Commit-ID: 59CCT0P4CBm --- components/style/gecko_bindings/bindings.rs | 6 ++++ ports/geckolib/glue.rs | 37 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 92675468073..52cfec65d74 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -165,6 +165,7 @@ use gecko_bindings::structs::nsINode; use gecko_bindings::structs::nsIDocument; use gecko_bindings::structs::nsIPrincipal; use gecko_bindings::structs::nsIURI; +use gecko_bindings::structs::nsString; use gecko_bindings::structs::RawGeckoNode; use gecko_bindings::structs::RawGeckoElement; use gecko_bindings::structs::RawGeckoDocument; @@ -399,6 +400,11 @@ extern "C" { *const ::std::os::raw::c_char, aLength: u32) -> bool; } +extern "C" { + pub fn Gecko_Utf8SliceToString(aString: *mut nsString, + aBuffer: *const u8, + aBufferLen: usize); +} extern "C" { pub fn Gecko_FontFamilyList_Clear(aList: *mut FontFamilyList); } diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 499c9c9d4e1..50c4e923cb8 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use cssparser::Parser; +use cssparser::{Parser, ToCss}; use env_logger; use euclid::Size2D; use parking_lot::RwLock; @@ -30,11 +30,13 @@ use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedVal use style::gecko_bindings::bindings::{ServoDeclarationBlockBorrowed, ServoDeclarationBlockStrong}; use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder}; use style::gecko_bindings::bindings::{nsHTMLCSSStyleSheet, ServoComputedValuesBorrowedOrNull}; +use style::gecko_bindings::bindings::Gecko_Utf8SliceToString; use style::gecko_bindings::bindings::RawServoStyleSetBorrowedMut; use style::gecko_bindings::ptr::{GeckoArcPrincipal, GeckoArcURI}; use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom}; use style::gecko_bindings::structs::ServoElementSnapshot; use style::gecko_bindings::structs::nsRestyleHint; +use style::gecko_bindings::structs::nsString; use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasBoxFFI}; use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, Strong}; use style::parallel; @@ -436,6 +438,39 @@ pub extern "C" fn Servo_DeclarationBlock_ClearCachePointer(declarations: ServoDe GeckoDeclarationBlock::as_arc(&declarations).cache.store(ptr::null_mut(), Ordering::Relaxed) } +#[no_mangle] +pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue( + declarations: ServoDeclarationBlockBorrowed, + buffer: *mut nsString) +{ + let mut string = String::new(); + + if let Some(ref declarations) = GeckoDeclarationBlock::as_arc(&declarations).declarations { + declarations.read().to_css(&mut string).unwrap(); + // FIXME: We are expecting |declarations| to be a declaration block with either a single + // longhand property-declaration or a series of longhand property-declarations that make + // up a single shorthand property. As a result, it should be possible to serialize + // |declarations| as a single declaration. However, we only want to return the *value* from + // that single declaration. For now, we just manually strip the property name, colon, + // leading spacing, and trailing space. In future we should find a more robust way to do + // this. + // + // See https://github.com/servo/servo/issues/13423 + debug_assert!(string.find(':').is_some()); + let position = string.find(':').unwrap(); + // Get the value after the first colon and any following whitespace. + let value = &string[(position + 1)..].trim_left(); + debug_assert!(value.ends_with(';')); + let length = value.len() - 1; // Strip last semicolon. + + // FIXME: Once we have nsString bindings for Servo (bug 1294742), we should be able to drop + // this and fill in |buffer| directly. + unsafe { + Gecko_Utf8SliceToString(buffer, value.as_ptr(), length); + } + } +} + #[no_mangle] pub extern "C" fn Servo_CSSSupports(property: *const u8, property_length: u32, value: *const u8, value_length: u32) -> bool { From 45e0b90d63b8749a9e0420bb56dbab5db3d5eade Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Fri, 16 Sep 2016 10:58:53 +0900 Subject: [PATCH 4/4] Bug 1302949 - Add a method to restyle with an added declaration; r=Manishearth MozReview-Commit-ID: AbX0PCjjEM6 --- components/style/gecko_bindings/bindings.rs | 5 ++++ ports/geckolib/glue.rs | 33 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 52cfec65d74..3529dce9b87 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -952,6 +952,11 @@ extern "C" { pub fn Servo_RestyleSubtree(node: RawGeckoNodeBorrowed, set: RawServoStyleSetBorrowedMut); } +extern "C" { + pub fn Servo_RestyleWithAddedDeclaration(declarations: ServoDeclarationBlockBorrowed, + previous_style: ServoComputedValuesBorrowed) + -> ServoComputedValuesStrong; +} extern "C" { pub fn Servo_GetStyleFont(computed_values: ServoComputedValuesBorrowedOrNull) diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 50c4e923cb8..f7237b59561 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -43,8 +43,9 @@ use style::parallel; use style::parser::{ParserContext, ParserContextExtraData}; use style::properties::{ComputedValues, Importance, PropertyDeclaration}; use style::properties::{PropertyDeclarationParseResult, PropertyDeclarationBlock}; -use style::properties::parse_one_declaration; +use style::properties::{cascade, parse_one_declaration}; use style::selector_impl::PseudoElementCascadeType; +use style::selector_matching::ApplicableDeclarationBlock; use style::sequential; use style::string_cache::Atom; use style::stylesheets::{Origin, Stylesheet}; @@ -96,6 +97,7 @@ fn restyle_subtree(node: GeckoNode, raw_data: RawServoStyleSetBorrowedMut) { LocalStyleContextCreationInfo::new(per_doc_data.new_animations_sender.clone()); let shared_style_context = SharedStyleContext { + // FIXME (bug 1303229): Use the actual viewport size here viewport_size: Size2D::new(Au(0), Au(0)), screen_size_changed: false, generation: 0, @@ -125,6 +127,35 @@ pub extern "C" fn Servo_RestyleSubtree(node: RawGeckoNodeBorrowed, restyle_subtree(node, raw_data); } +#[no_mangle] +pub extern "C" fn Servo_RestyleWithAddedDeclaration(declarations: ServoDeclarationBlockBorrowed, + previous_style: ServoComputedValuesBorrowed) + -> ServoComputedValuesStrong +{ + match GeckoDeclarationBlock::as_arc(&declarations).declarations { + Some(ref declarations) => { + let declaration_block = ApplicableDeclarationBlock { + mixed_declarations: declarations.clone(), + importance: Importance::Normal, + source_order: 0, + specificity: ::std::u32::MAX, + }; + let previous_style = ComputedValues::as_arc(&previous_style); + + // FIXME (bug 1303229): Use the actual viewport size here + let (computed, _) = cascade(Size2D::new(Au(0), Au(0)), + &[declaration_block], + false, + Some(previous_style), + None, + None, + Box::new(StdoutErrorReporter)); + Arc::new(computed).into_strong() + }, + None => ServoComputedValuesStrong::null(), + } +} + #[no_mangle] pub extern "C" fn Servo_StyleWorkerThreadCount() -> u32 { *NUM_THREADS as u32