Bug 1467536: Add a Servo API to get the serialized style of a property. r?xidorn
This is intended to be used by GetComputedStyle when there's no layout
dependency.
MozReview-Commit-ID: 3GAbjo1uQ34
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -810,28 +810,31 @@ SERVO_BINDING_FUNC(Servo_StyleSet_GetCom
const mozilla::ServoElementSnapshotTable* snapshots,
RawServoAnimationValueBorrowed animation)
// For canvas font.
SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
RawServoDeclarationBlockBorrowed declarations,
nsAString* buffer)
-// Get custom property value.
+// GetComputedStyle APIs.
SERVO_BINDING_FUNC(Servo_GetCustomPropertyValue, bool,
ComputedStyleBorrowed computed_values,
const nsAString* name, nsAString* value)
SERVO_BINDING_FUNC(Servo_GetCustomPropertiesCount, uint32_t,
ComputedStyleBorrowed computed_values)
SERVO_BINDING_FUNC(Servo_GetCustomPropertyNameAt, bool,
ComputedStyleBorrowed, uint32_t index,
nsAString* name)
+SERVO_BINDING_FUNC(Servo_GetPropertyValue, void,
+ ComputedStyleBorrowed computed_values,
+ nsCSSPropertyID property, nsAString* value)
SERVO_BINDING_FUNC(Servo_ProcessInvalidations, void,
RawServoStyleSetBorrowed set,
RawGeckoElementBorrowed element,
const mozilla::ServoElementSnapshotTable* snapshots)
SERVO_BINDING_FUNC(Servo_HasPendingRestyleAncestor, bool,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -17,18 +17,17 @@ use custom_properties::CustomPropertiesB
use servo_arc::{Arc, UniqueArc};
use smallbitvec::SmallBitVec;
use std::borrow::Cow;
use std::{ops, ptr};
use std::cell::RefCell;
use std::fmt::{self, Write};
use std::mem::{self, ManuallyDrop};
-#[cfg(feature = "servo")] use cssparser::RGBA;
-use cssparser::{Parser, TokenSerializationType};
+use cssparser::{Parser, RGBA, TokenSerializationType};
use cssparser::ParserInput;
#[cfg(feature = "servo")] use euclid::SideOffsets2D;
use context::QuirksMode;
use font_metrics::FontMetricsProvider;
#[cfg(feature = "gecko")] use gecko_bindings::bindings;
#[cfg(feature = "gecko")] use gecko_bindings::structs::{self, nsCSSPropertyID};
#[cfg(feature = "servo")] use logical_geometry::LogicalMargin;
#[cfg(feature = "servo")] use computed_values;
@@ -40,17 +39,17 @@ use parser::ParserContext;
use rule_cache::{RuleCache, RuleCacheConditions};
use selector_parser::PseudoElement;
use selectors::parser::SelectorParseErrorKind;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use shared_lock::StylesheetGuards;
use style_traits::{CssWriter, KeywordsCollectFn, ParseError, ParsingMode};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
use stylesheets::{CssRuleType, Origin, UrlExtraData};
-#[cfg(feature = "servo")] use values::Either;
+use values::Either;
use values::generics::text::LineHeight;
use values::computed;
use values::computed::NonNegativeLength;
use values::serialize_atom_name;
use rule_tree::{CascadeLevel, StrongRuleNode};
use self::computed_value_flags::*;
use str::{CssString, CssStringBorrow, CssStringWriter};
use style_adjuster::StyleAdjuster;
@@ -826,23 +825,23 @@ bitflags! {
/// absolutely positioned elements.
const ABSPOS_CB = 1 << 2;
/// This longhand property applies to ::first-letter.
const APPLIES_TO_FIRST_LETTER = 1 << 3;
/// This longhand property applies to ::first-line.
const APPLIES_TO_FIRST_LINE = 1 << 4;
/// This longhand property applies to ::placeholder.
const APPLIES_TO_PLACEHOLDER = 1 << 5;
+ /// This property's getComputedStyle implementation requires layout
+ /// to be flushed.
+ const GETCS_NEEDS_LAYOUT_FLUSH = 1 << 6;
/* The following flags are currently not used in Rust code, they
* only need to be listed in corresponding properties so that
* they can be checked in the C++ side via ServoCSSPropList.h. */
- /// This property's getComputedStyle implementation requires layout
- /// to be flushed.
- const GETCS_NEEDS_LAYOUT_FLUSH = 0;
/// This property can be animated on the compositor.
const CAN_ANIMATE_ON_COMPOSITOR = 0;
}
}
/// An identifier for a given longhand property.
#[derive(Clone, Copy, Eq, Hash, MallocSizeOf, PartialEq)]
#[repr(u16)]
@@ -2606,16 +2605,69 @@ impl ComputedValues {
pub fn visited_rules(&self) -> Option<<&StrongRuleNode> {
self.visited_style.as_ref().and_then(|s| s.rules.as_ref())
}
/// Gets a reference to the custom properties map (if one exists).
pub fn custom_properties(&self) -> Option<<&Arc<::custom_properties::CustomPropertiesMap>> {
self.custom_properties.as_ref()
}
+
+ /// Writes the value of the given longhand as a string in `dest`.
+ ///
+ /// Note that the value will usually be the computed value, except for
+ /// colors, where it's resolved.
+ pub fn get_longhand_property_value<W>(
+ &self,
+ property_id: LonghandId,
+ dest: &mut CssWriter<W>
+ ) -> fmt::Result
+ where
+ W: Write,
+ {
+ // TODO(emilio): Is it worth to merge branches here just like
+ // PropertyDeclaration::to_css does?
+ //
+ // We'd need to get a concept of ~resolved value, which may not be worth
+ // it.
+ match property_id {
+ % for prop in data.longhands:
+ LonghandId::${prop.camel_case} => {
+ let style_struct =
+ self.get_${prop.style_struct.ident.strip("_")}();
+ let value =
+ style_struct
+ % if prop.logical:
+ .clone_${prop.ident}(self.writing_mode);
+ % else:
+ .clone_${prop.ident}();
+ % endif
+
+ % if prop.predefined_type == "Color":
+ let value = self.resolve_color(value);
+ % endif
+
+ value.to_css(dest)
+ }
+ % endfor
+ }
+ }
+
+ /// Resolves the currentColor keyword.
+ ///
+ /// Any color value from computed values (except for the 'color' property
+ /// itself) should go through this method.
+ ///
+ /// Usage example:
+ /// let top_color =
+ /// style.resolve_color(style.get_border().clone_border_top_color());
+ #[inline]
+ pub fn resolve_color(&self, color: computed::Color) -> RGBA {
+ color.to_rgba(self.get_color().clone_color())
+ }
}
#[cfg(feature = "servo")]
impl ComputedValues {
/// Create a new refcounted `ComputedValues`
pub fn new(
_: &Device,
_: Option<<&ComputedValues>,
@@ -2718,28 +2770,16 @@ impl ComputedValuesInner {
}
/// Whether the current style is multicolumn.
#[inline]
pub fn is_multicol(&self) -> bool {
self.get_column().is_multicol()
}
- /// Resolves the currentColor keyword.
- ///
- /// Any color value from computed values (except for the 'color' property
- /// itself) should go through this method.
- ///
- /// Usage example:
- /// let top_color = style.resolve_color(style.Border.border_top_color);
- #[inline]
- pub fn resolve_color(&self, color: computed::Color) -> RGBA {
- color.to_rgba(self.get_color().color)
- }
-
/// Get the logical computed inline size.
#[inline]
pub fn content_inline_size(&self) -> computed::LengthOrPercentageOrAuto {
let position_style = self.get_position();
if self.writing_mode.is_vertical() {
position_style.height
} else {
position_style.width
@@ -2894,29 +2934,29 @@ impl ComputedValuesInner {
// Neither perspective nor transform present
false
}
/// Serializes the computed value of this property as a string.
pub fn computed_value_to_string(&self, property: PropertyDeclarationId) -> String {
match property {
- % for style_struct in data.active_style_structs():
- % for longhand in style_struct.longhands:
- PropertyDeclarationId::Longhand(LonghandId::${longhand.camel_case}) => {
- self.${style_struct.ident}.${longhand.ident}.to_css_string()
- }
- % endfor
- % endfor
+ PropertyDeclarationId::Longhand(id) => {
+ let mut s = String::new();
+ self.get_longhand_property_value(
+ property,
+ &mut CssWriter::new(&mut s)
+ ).unwrap();
+ s
+ }
PropertyDeclarationId::Custom(name) => {
self.custom_properties
.as_ref()
.and_then(|map| map.get(name))
- .map(|value| value.to_css_string())
- .unwrap_or(String::new())
+ .map_or(String::new(), |value| value.to_css_string())
}
}
}
}
% if product == "gecko":
pub use ::servo_arc::RawOffsetArc as BuilderArc;
/// Clone an arc, returning a regular arc
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -5077,16 +5077,35 @@ pub extern "C" fn Servo_StyleSet_HasDocu
) -> 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_GetPropertyValue(
+ computed_values: ComputedStyleBorrowed,
+ prop: nsCSSPropertyID,
+ value: *mut nsAString,
+) {
+ use style::properties::PropertyFlags;
+
+ let longhand = LonghandId::from_nscsspropertyid(prop).expect("Not a longhand?");
+ debug_assert!(
+ !longhand.flags().contains(PropertyFlags::GETCS_NEEDS_LAYOUT_FLUSH),
+ "We're not supposed to serialize layout-dependent properties"
+ );
+ computed_values.get_longhand_property_value(
+ longhand,
+ &mut CssWriter::new(&mut *value),
+ ).unwrap();
+}
+
+#[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,