Bug 1332657 - Part 2: Implement clone_transform. r?heycam,manishearth
The implementation of clone_transform is an adaptation of set_transform.
MozReview-Commit-ID: ESE1ha0x666
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1065,59 +1065,111 @@ Gecko_NewCSSValueSharedList(uint32_t aLe
}
void
Gecko_CSSValue_SetAbsoluteLength(nsCSSValueBorrowedMut aCSSValue, nscoord aLen)
{
aCSSValue->SetIntegerCoordValue(aLen);
}
+nscoord
+Gecko_CSSValue_GetAbsoluteLength(nsCSSValueBorrowed aCSSValue)
+{
+ // SetIntegerCoordValue() which is used in Gecko_CSSValue_SetAbsoluteLength()
+ // converts values by nsPresContext::AppUnitsToFloatCSSPixels() and stores
+ // values in eCSSUnit_Pixel unit. We need to convert the values back to app
+ // units by GetPixelLength().
+ MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Pixel,
+ "The unit should be eCSSUnit_Pixel");
+ return aCSSValue->GetPixelLength();
+}
+
void
Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut aCSSValue, float aNumber)
{
aCSSValue->SetFloatValue(aNumber, eCSSUnit_Number);
}
+float
+Gecko_CSSValue_GetNumber(nsCSSValueBorrowed aCSSValue)
+{
+ return aCSSValue->GetFloatValue();
+}
+
void
Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut aCSSValue, nsCSSKeyword aKeyword)
{
aCSSValue->SetEnumValue(aKeyword);
}
+nsCSSKeyword
+Gecko_CSSValue_GetKeyword(nsCSSValueBorrowed aCSSValue)
+{
+ return aCSSValue->GetKeywordValue();
+}
+
void
Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut aCSSValue, float aPercent)
{
aCSSValue->SetPercentValue(aPercent);
}
+float
+Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed aCSSValue)
+{
+ return aCSSValue->GetPercentValue();
+}
+
void
Gecko_CSSValue_SetAngle(nsCSSValueBorrowedMut aCSSValue, float aRadians)
{
aCSSValue->SetFloatValue(aRadians, eCSSUnit_Radian);
}
+float
+Gecko_CSSValue_GetAngle(nsCSSValueBorrowed aCSSValue)
+{
+ // Unfortunately nsCSSValue.GetAngleValueInRadians() returns double,
+ // so we use GetAngleValue() instead.
+ MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Radian,
+ "The unit should be eCSSUnit_Radian");
+ return aCSSValue->GetAngleValue();
+}
+
void
Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut aCSSValue, nsStyleCoord::CalcValue aCalc)
{
aCSSValue->SetCalcValue(&aCalc);
}
+nsStyleCoord::CalcValue
+Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue)
+{
+ return aCSSValue->GetCalcValue();
+}
+
void
Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut aCSSValue, int32_t aLen)
{
nsCSSValue::Array* arr = nsCSSValue::Array::Create(aLen);
aCSSValue->SetArrayValue(arr, eCSSUnit_Function);
}
nsCSSValueBorrowedMut
Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut aCSSValue, int32_t aIndex)
{
return &aCSSValue->GetArrayValue()->Item(aIndex);
}
+nsCSSValueBorrowed
+Gecko_CSSValue_GetArrayItemConst(nsCSSValueBorrowed aCSSValue, int32_t aIndex)
+{
+ return &aCSSValue->GetArrayValue()->Item(aIndex);
+}
+
bool
Gecko_PropertyId_IsPrefEnabled(nsCSSPropertyID id)
{
return nsCSSProps::IsEnabled(id);
}
void
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -293,24 +293,35 @@ NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsSty
nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
nsStyleQuoteValues* Gecko_NewStyleQuoteValues(uint32_t len);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleQuoteValues, QuoteValues);
nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len);
+
+// Getter for nsCSSValue
+nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut css_value, int32_t index);
+// const version of the above function.
+nsCSSValueBorrowed Gecko_CSSValue_GetArrayItemConst(nsCSSValueBorrowed css_value, int32_t index);
+nscoord Gecko_CSSValue_GetAbsoluteLength(nsCSSValueBorrowed css_value);
+float Gecko_CSSValue_GetAngle(nsCSSValueBorrowed css_value);
+nsCSSKeyword Gecko_CSSValue_GetKeyword(nsCSSValueBorrowed aCSSValue);
+float Gecko_CSSValue_GetNumber(nsCSSValueBorrowed css_value);
+float Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed css_value);
+nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue);
+
void Gecko_CSSValue_SetAbsoluteLength(nsCSSValueBorrowedMut css_value, nscoord len);
void Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut css_value, float number);
void Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut css_value, nsCSSKeyword keyword);
void Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut css_value, float percent);
void Gecko_CSSValue_SetAngle(nsCSSValueBorrowedMut css_value, float radians);
void Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut css_value, nsStyleCoord::CalcValue calc);
void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut css_value, int32_t len);
-nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut css_value, int32_t index);
void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
bool Gecko_PropertyId_IsPrefEnabled(nsCSSPropertyID id);
const nsMediaFeature* Gecko_GetMediaFeatures();
// Style-struct management.
#define STYLE_STRUCT(name, checkdata_cb) \
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -828,16 +828,56 @@ void nsCSSValue::SetCalcValue(const nsSt
arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
arr2->Item(0).SetIntegerCoordValue(aCalc->mLength);
arr2->Item(1).SetPercentValue(aCalc->mPercent);
}
SetArrayValue(arr, eCSSUnit_Calc);
}
+nsStyleCoord::CalcValue
+nsCSSValue::GetCalcValue() const
+{
+ MOZ_ASSERT(mUnit == eCSSUnit_Calc,
+ "The unit should be eCSSUnit_Calc");
+
+ const nsCSSValue::Array* array = GetArrayValue();
+ MOZ_ASSERT(array->Count() == 1,
+ "There should be a 1-length array");
+
+ const nsCSSValue& rootValue = array->Item(0);
+
+ nsStyleCoord::CalcValue result;
+
+ if (rootValue.GetUnit() == eCSSUnit_Pixel) {
+ result.mLength = rootValue.GetFloatValue();
+ result.mPercent = 0.0f;
+ result.mHasPercent = false;
+ } else {
+ MOZ_ASSERT(rootValue.GetUnit() == eCSSUnit_Calc_Plus,
+ "Calc unit should be eCSSUnit_Calc_Plus");
+
+ const nsCSSValue::Array *calcPlusArray = rootValue.GetArrayValue();
+ MOZ_ASSERT(array->Count() == 2,
+ "eCSSUnit_Calc_Plus should have a 2-length array");
+
+ const nsCSSValue& length = calcPlusArray->Item(0);
+ const nsCSSValue& percent = calcPlusArray->Item(1);
+ MOZ_ASSERT(length.GetUnit() == eCSSUnit_Pixel,
+ "The first value should be eCSSUnit_Pixel");
+ MOZ_ASSERT(percent.GetUnit() == eCSSUnit_Percent,
+ "The first value should be eCSSUnit_Percent");
+ result.mLength = length.GetFloatValue();
+ result.mPercent = percent.GetPercentValue();
+ result.mHasPercent = true;
+ }
+
+ return result;
+}
+
void nsCSSValue::StartImageLoad(nsIDocument* aDocument) const
{
MOZ_ASSERT(eCSSUnit_URL == mUnit, "Not a URL value!");
mozilla::css::ImageValue* image =
new mozilla::css::ImageValue(mValue.mURL->GetURI(),
mValue.mURL->mString,
mValue.mURL->mBaseURI,
mValue.mURL->mReferrer,
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -933,16 +933,18 @@ public:
void SetNormalValue();
void SetSystemFontValue();
void SetDummyValue();
void SetDummyInheritValue();
// Converts an nsStyleCoord::CalcValue back into a CSSValue
void SetCalcValue(const nsStyleCoord::CalcValue* aCalc);
+ nsStyleCoord::CalcValue GetCalcValue() const;
+
// These are a little different - they allocate storage for you and
// return a handle.
nsCSSRect& SetRectValue();
nsCSSValueList* SetListValue();
nsCSSValuePairList* SetPairListValue();
// These take ownership of the passed-in resource.
void AdoptListValue(mozilla::UniquePtr<nsCSSValueList> aValue);
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -1,19 +1,27 @@
/* 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/. */
//! Little helpers for `nsCSSValue`.
+use app_units::Au;
use gecko_bindings::bindings::Gecko_CSSValue_Drop;
+use gecko_bindings::bindings::Gecko_CSSValue_GetAbsoluteLength;
+use gecko_bindings::bindings::Gecko_CSSValue_GetCalc;
+use gecko_bindings::bindings::Gecko_CSSValue_GetPercentage;
+use gecko_bindings::bindings::Gecko_CSSValue_SetAbsoluteLength;
+use gecko_bindings::bindings::Gecko_CSSValue_SetCalc;
+use gecko_bindings::bindings::Gecko_CSSValue_SetPercentage;
use gecko_bindings::structs::{nsCSSValue, nsCSSUnit, nsCSSValue_Array};
use std::mem;
use std::ops::Index;
use std::slice;
+use values::computed::LengthOrPercentage;
impl nsCSSValue {
/// Create a CSSValue with null unit, useful to be used as a return value.
#[inline]
pub fn null() -> Self {
unsafe { mem::zeroed() }
}
@@ -37,16 +45,47 @@ impl nsCSSValue {
/// builds.
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Divided as u32);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
&*array
}
+
+ /// Sets LengthOrPercentage value to this nsCSSValue.
+ pub unsafe fn set_lop(&mut self, lop: LengthOrPercentage) {
+ match lop {
+ LengthOrPercentage::Length(au) => {
+ Gecko_CSSValue_SetAbsoluteLength(self, au.0)
+ }
+ LengthOrPercentage::Percentage(pc) => {
+ Gecko_CSSValue_SetPercentage(self, pc)
+ }
+ LengthOrPercentage::Calc(calc) => {
+ Gecko_CSSValue_SetCalc(self, calc.into())
+ }
+ }
+ }
+
+ /// Returns LengthOrPercentage value.
+ pub unsafe fn get_lop(&self) -> LengthOrPercentage {
+ match self.mUnit {
+ nsCSSUnit::eCSSUnit_Pixel => {
+ LengthOrPercentage::Length(Au(Gecko_CSSValue_GetAbsoluteLength(self)))
+ },
+ nsCSSUnit::eCSSUnit_Percent => {
+ LengthOrPercentage::Percentage(Gecko_CSSValue_GetPercentage(self))
+ },
+ nsCSSUnit::eCSSUnit_Calc => {
+ LengthOrPercentage::Calc(Gecko_CSSValue_GetCalc(self).into())
+ },
+ x => panic!("The unit should not be {:?}", x),
+ }
+ }
}
impl Drop for nsCSSValue {
fn drop(&mut self) {
unsafe { Gecko_CSSValue_Drop(self) };
}
}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1312,17 +1312,17 @@ fn static_assert() {
# Generate contents of pattern from items
pattern = ", ".join([b + str(a+1) for (a,b) in enumerate(items)])
# First %s substituted with the call to GetArrayItem, the second
# %s substituted with the corresponding variable
css_value_setters = {
"length" : "bindings::Gecko_CSSValue_SetAbsoluteLength(%s, %s.0)",
"percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s)",
- "lop" : "set_lop(%s, %s)",
+ "lop" : "%s.set_lop(%s)",
"angle" : "bindings::Gecko_CSSValue_SetAngle(%s, %s.0)",
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
}
%>
ComputedOperation::${name.title()}(${pattern}) => {
bindings::Gecko_CSSValue_SetFunction(gecko_value, ${len(items) + 1});
bindings::Gecko_CSSValue_SetKeyword(
bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0),
@@ -1336,31 +1336,16 @@ fn static_assert() {
% endfor
}
</%def>
pub fn set_transform(&mut self, other: longhands::transform::computed_value::T) {
use gecko_bindings::structs::nsCSSKeyword::*;
use gecko_bindings::sugar::refptr::RefPtr;
use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation;
- use values::computed::LengthOrPercentage;
-
- unsafe fn set_lop(value: &mut structs::nsCSSValue, lop: LengthOrPercentage) {
- match lop {
- LengthOrPercentage::Length(au) => {
- bindings::Gecko_CSSValue_SetAbsoluteLength(value, au.0)
- }
- LengthOrPercentage::Percentage(pc) => {
- bindings::Gecko_CSSValue_SetPercentage(value, pc)
- }
- LengthOrPercentage::Calc(calc) => {
- bindings::Gecko_CSSValue_SetCalc(value, calc.into())
- }
- }
- }
let vec = if let Some(v) = other.0 {
v
} else {
unsafe {
self.gecko.mSpecifiedTransform.clear();
}
return;
@@ -1391,16 +1376,81 @@ fn static_assert() {
debug_assert!(iter.next().is_none());
unsafe { self.gecko.mSpecifiedTransform.set_move(list) };
}
pub fn copy_transform_from(&mut self, other: &Self) {
unsafe { self.gecko.mSpecifiedTransform.set(&other.gecko.mSpecifiedTransform); }
}
+ <%def name="computed_operation_arm(name, keyword, items)">
+ <%
+ # %s is substituted with the call to GetArrayItem.
+ css_value_getters = {
+ "length" : "Au(bindings::Gecko_CSSValue_GetAbsoluteLength(%s))",
+ "lop" : "%s.get_lop()",
+ "angle" : "Angle(bindings::Gecko_CSSValue_GetAngle(%s))",
+ "number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
+ }
+ %>
+ eCSSKeyword_${keyword} => {
+ ComputedOperation::${name.title()}(
+ % if name == "matrix":
+ ComputedMatrix {
+ % endif
+ % for index, item in enumerate(items):
+ % if name == "matrix":
+ m${index / 4 + 1}${index % 4 + 1}:
+ % endif
+ ${css_value_getters[item] % (
+ "bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d)" % (index + 1)
+ )},
+ % endfor
+ % if name == "matrix":
+ }
+ % endif
+ )
+ },
+ </%def>
+ pub fn clone_transform(&self) -> longhands::transform::computed_value::T {
+ use app_units::Au;
+ use gecko_bindings::structs::nsCSSKeyword::*;
+ use properties::longhands::transform::computed_value;
+ use properties::longhands::transform::computed_value::ComputedMatrix;
+ use properties::longhands::transform::computed_value::ComputedOperation;
+ use values::computed::Angle;
+
+ if self.gecko.mSpecifiedTransform.mRawPtr.is_null() {
+ return computed_value::T(None);
+ }
+
+ let mut result = vec![];
+ let mut cur = unsafe { (*self.gecko.mSpecifiedTransform.to_safe().get()).mHead };
+ while !cur.is_null() {
+ let gecko_value = unsafe { &(*cur).mValue };
+ let transform_function = unsafe {
+ bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0))
+ };
+ let servo = unsafe {
+ match transform_function {
+ ${computed_operation_arm("matrix", "matrix3d", ["number"] * 16)}
+ ${computed_operation_arm("skew", "skew", ["angle"] * 2)}
+ ${computed_operation_arm("translate", "translate3d", ["lop", "lop", "length"])}
+ ${computed_operation_arm("scale", "scale3d", ["number"] * 3)}
+ ${computed_operation_arm("rotate", "rotate3d", ["number"] * 3 + ["angle"])}
+ ${computed_operation_arm("perspective", "perspective", ["length"])}
+ _ => panic!("We shouldn't set any other transform function types"),
+ }
+ };
+ result.push(servo);
+ unsafe { cur = (&*cur).mNext };
+ }
+ computed_value::T(Some(result))
+ }
+
pub fn set_animation_name(&mut self, v: longhands::animation_name::computed_value::T) {
use nsstring::nsCString;
unsafe { self.gecko.mAnimations.ensure_len(v.0.len()) };
if v.0.len() > 0 {
self.gecko.mAnimationNameCount = v.0.len() as u32;
for (servo, gecko) in v.0.into_iter().zip(self.gecko.mAnimations.iter_mut()) {
gecko.mName.assign_utf8(&nsCString::from(servo.0.to_string()));