diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 895ecd3d41c7..e13308b3b484 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1190,8 +1190,8 @@ CSS_PROP_DISPLAY( mClip, eCSSType_Rect, nsnull, - CSS_PROP_NO_OFFSET, - eStyleAnimType_None) + offsetof(nsStyleDisplay, mClip), + eStyleAnimType_Custom) CSS_PROP_COLOR( color, color, @@ -1523,8 +1523,8 @@ CSS_PROP_LIST( mImageRegion, eCSSType_Rect, nsnull, - CSS_PROP_NO_OFFSET, - eStyleAnimType_None) + offsetof(nsStyleList, mImageRegion), + eStyleAnimType_Custom) CSS_PROP_UIRESET( ime-mode, ime_mode, diff --git a/layout/style/nsStyleAnimation.cpp b/layout/style/nsStyleAnimation.cpp index 90c13b7822c3..02a1114fc9b4 100644 --- a/layout/style/nsStyleAnimation.cpp +++ b/layout/style/nsStyleAnimation.cpp @@ -244,6 +244,42 @@ nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty, aDistance = sqrt(squareDistance); break; } + case eUnit_CSSRect: { + const nsCSSRect *rect1 = aStartValue.GetCSSRectValue(); + const nsCSSRect *rect2 = aEndValue.GetCSSRectValue(); + if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() || + rect1->mRight.GetUnit() != rect2->mRight.GetUnit() || + rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() || + rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) { + // At least until we have calc() + return PR_FALSE; + } + + double squareDistance = 0.0; + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(nsCSSRect::sides); ++i) { + nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i]; + NS_ABORT_IF_FALSE((rect1->*member).GetUnit() == + (rect2->*member).GetUnit(), + "should have returned above"); + double diff; + switch ((rect1->*member).GetUnit()) { + case eCSSUnit_Pixel: + diff = (rect1->*member).GetFloatValue() - + (rect2->*member).GetFloatValue(); + break; + case eCSSUnit_Auto: + diff = 0; + break; + default: + NS_ABORT_IF_FALSE(PR_FALSE, "unexpected unit"); + return PR_FALSE; + } + squareDistance += diff * diff; + } + + aDistance = sqrt(squareDistance); + break; + } case eUnit_Dasharray: { // NOTE: This produces results on substantially different scales // for length values and percentage values, which might even be @@ -366,6 +402,13 @@ nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty, return success; } +inline void +nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue) +{ + aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord), + eCSSUnit_Pixel); +} + #define MAX_PACKED_COLOR_COMPONENT 255 inline PRUint8 ClampColor(double aColor) @@ -586,6 +629,50 @@ nsStyleAnimation::AddWeighted(nsCSSProperty aProperty, eUnit_CSSValuePair); break; } + case eUnit_CSSRect: { + const nsCSSRect *rect1 = aValue1.GetCSSRectValue(); + const nsCSSRect *rect2 = aValue2.GetCSSRectValue(); + if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() || + rect1->mRight.GetUnit() != rect2->mRight.GetUnit() || + rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() || + rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) { + // At least until we have calc() + return PR_FALSE; + } + + nsAutoPtr result(new nsCSSRect); + if (!result) { + return PR_FALSE; + } + for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(nsCSSRect::sides); ++i) { + nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i]; + NS_ABORT_IF_FALSE((rect1->*member).GetUnit() == + (rect2->*member).GetUnit(), + "should have returned above"); + switch ((rect1->*member).GetUnit()) { + case eCSSUnit_Pixel: + (result->*member).SetFloatValue( + aCoeff1 * (rect1->*member).GetFloatValue() + + aCoeff2 * (rect2->*member).GetFloatValue(), + eCSSUnit_Pixel); + break; + case eCSSUnit_Auto: + if (float(aCoeff1 + aCoeff2) != 1.0f) { + // Interpolating between two auto values makes sense; + // adding in other ratios does not. + return PR_FALSE; + } + (result->*member).SetAutoValue(); + break; + default: + NS_ABORT_IF_FALSE(PR_FALSE, "unexpected unit"); + return PR_FALSE; + } + } + + aResultValue.SetAndAdoptCSSRectValue(result.forget(), eUnit_CSSRect); + break; + } case eUnit_Dasharray: { const nsCSSValueList *list1 = aValue1.GetCSSValueListValue(); const nsCSSValueList *list2 = aValue2.GetCSSValueListValue(); @@ -896,10 +983,8 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty, case eUnit_Coord: { NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] == eCSSType_Value, "type mismatch"); - float pxVal = aPresContext->AppUnitsToFloatCSSPixels( - aComputedValue.GetCoordValue()); - static_cast(aSpecifiedValue)-> - SetFloatValue(pxVal, eCSSUnit_Pixel); + nscoordToCSSValue(aComputedValue.GetCoordValue(), + *static_cast(aSpecifiedValue)); break; } case eUnit_Percent: @@ -936,6 +1021,12 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty, *static_cast(aSpecifiedValue) = *aComputedValue.GetCSSValuePairValue(); break; + case eUnit_CSSRect: + NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] == + eCSSType_Rect, "type mismatch"); + *static_cast(aSpecifiedValue) = + *aComputedValue.GetCSSRectValue(); + break; case eUnit_Dasharray: case eUnit_Shadow: NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] == @@ -1063,9 +1154,7 @@ StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue) { switch (aCoord.GetUnit()) { case eStyleUnit_Coord: - aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels( - aCoord.GetCoordValue()), - eCSSUnit_Pixel); + nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue); break; case eStyleUnit_Percent: aCSSValue.SetPercentValue(aCoord.GetPercentValue()); @@ -1164,14 +1253,8 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty, if (!pair) { return PR_FALSE; } - pair->mXValue.SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels( - styleTableBorder->mBorderSpacingX), - eCSSUnit_Pixel); - pair->mYValue.SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels( - styleTableBorder->mBorderSpacingY), - eCSSUnit_Pixel); + nscoordToCSSValue(styleTableBorder->mBorderSpacingX, pair->mXValue); + nscoordToCSSValue(styleTableBorder->mBorderSpacingY, pair->mYValue); aComputedValue.SetAndAdoptCSSValuePairValue(pair, eUnit_CSSValuePair); break; @@ -1270,6 +1353,64 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty, return PR_TRUE; } + case eCSSProperty_image_region: { + const nsStyleList *list = + static_cast(styleStruct); + const nsRect &srect = list->mImageRegion; + if (srect.IsEmpty()) { + aComputedValue.SetAutoValue(); + break; + } + + nsCSSRect *vrect = new nsCSSRect; + if (!vrect) { + return PR_FALSE; + } + nscoordToCSSValue(srect.x, vrect->mLeft); + nscoordToCSSValue(srect.y, vrect->mTop); + nscoordToCSSValue(srect.XMost(), vrect->mRight); + nscoordToCSSValue(srect.YMost(), vrect->mBottom); + aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect); + break; + } + + case eCSSProperty_clip: { + const nsStyleDisplay *display = + static_cast(styleStruct); + if (!(display->mClipFlags & NS_STYLE_CLIP_RECT)) { + aComputedValue.SetAutoValue(); + break; + } + + nsCSSRect *vrect = new nsCSSRect; + if (!vrect) { + return PR_FALSE; + } + const nsRect &srect = display->mClip; + if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) { + vrect->mTop.SetAutoValue(); + } else { + nscoordToCSSValue(srect.y, vrect->mTop); + } + if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) { + vrect->mRight.SetAutoValue(); + } else { + nscoordToCSSValue(srect.XMost(), vrect->mRight); + } + if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) { + vrect->mBottom.SetAutoValue(); + } else { + nscoordToCSSValue(srect.YMost(), vrect->mBottom); + } + if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) { + vrect->mLeft.SetAutoValue(); + } else { + nscoordToCSSValue(srect.x, vrect->mLeft); + } + aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect); + break; + } + default: NS_ABORT_IF_FALSE(PR_FALSE, "missing property implementation"); return PR_FALSE; @@ -1376,20 +1517,12 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty, const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i); // X, Y, Radius, Spread, Color, Inset nsRefPtr arr = nsCSSValue::Array::Create(6); - arr->Item(0).SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels(shadow->mXOffset), - eCSSUnit_Pixel); - arr->Item(1).SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels(shadow->mYOffset), - eCSSUnit_Pixel); - arr->Item(2).SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels(shadow->mRadius), - eCSSUnit_Pixel); + nscoordToCSSValue(shadow->mXOffset, arr->Item(0)); + nscoordToCSSValue(shadow->mYOffset, arr->Item(1)); + nscoordToCSSValue(shadow->mRadius, arr->Item(2)); // NOTE: This code sometimes stores mSpread: 0 even when // the parser would be required to leave it null. - arr->Item(3).SetFloatValue( - nsPresContext::AppUnitsToFloatCSSPixels(shadow->mSpread), - eCSSUnit_Pixel); + nscoordToCSSValue(shadow->mSpread, arr->Item(3)); if (shadow->mHasColor) { arr->Item(4).SetColorValue(shadow->mColor); } @@ -1482,6 +1615,13 @@ nsStyleAnimation::Value::operator=(const Value& aOther) mUnit = eUnit_Null; } break; + case eUnit_CSSRect: + NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null"); + mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect); + if (!mValue.mCSSRect) { + mUnit = eUnit_Null; + } + break; case eUnit_Dasharray: case eUnit_Shadow: NS_ABORT_IF_FALSE(mUnit != eUnit_Dasharray || aOther.mValue.mCSSValueList, @@ -1591,6 +1731,16 @@ nsStyleAnimation::Value::SetAndAdoptCSSValuePairValue( mValue.mCSSValuePair = aValuePair; // take ownership } +void +nsStyleAnimation::Value::SetAndAdoptCSSRectValue(nsCSSRect *aRect, Unit aUnit) +{ + FreeValue(); + NS_ABORT_IF_FALSE(IsCSSRectUnit(aUnit), "bad unit"); + NS_ABORT_IF_FALSE(aRect != nsnull, "value pairs may not be null"); + mUnit = aUnit; + mValue.mCSSRect = aRect; // take ownership +} + void nsStyleAnimation::Value::SetAndAdoptCSSValueListValue( nsCSSValueList *aValueList, Unit aUnit) @@ -1610,6 +1760,8 @@ nsStyleAnimation::Value::FreeValue() delete mValue.mCSSValueList; } else if (IsCSSValuePairUnit(mUnit)) { delete mValue.mCSSValuePair; + } else if (IsCSSRectUnit(mUnit)) { + delete mValue.mCSSRect; } else if (IsStringUnit(mUnit)) { NS_ABORT_IF_FALSE(mValue.mString, "expecting non-null string"); mValue.mString->Release(); @@ -1641,6 +1793,8 @@ nsStyleAnimation::Value::operator==(const Value& aOther) const return mValue.mColor == aOther.mValue.mColor; case eUnit_CSSValuePair: return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair; + case eUnit_CSSRect: + return *mValue.mCSSRect == *aOther.mValue.mCSSRect; case eUnit_Dasharray: case eUnit_Shadow: return nsCSSValueList::Equal(mValue.mCSSValueList, diff --git a/layout/style/nsStyleAnimation.h b/layout/style/nsStyleAnimation.h index 97cb6d53c9c2..1a50c779fbd9 100644 --- a/layout/style/nsStyleAnimation.h +++ b/layout/style/nsStyleAnimation.h @@ -56,6 +56,7 @@ class nsPresContext; class nsStyleContext; struct nsCSSValueList; struct nsCSSValuePair; +struct nsCSSRect; /** * Utility class to handle animated style values @@ -234,6 +235,7 @@ public: eUnit_Float, eUnit_Color, eUnit_CSSValuePair, // nsCSSValuePair* (never null) + eUnit_CSSRect, // nsCSSRect* (never null) eUnit_Dasharray, // nsCSSValueList* (never null) eUnit_Shadow, // nsCSSValueList* (may be null) eUnit_UnparsedString // nsStringBuffer* (never null) @@ -248,6 +250,7 @@ public: float mFloat; nscolor mColor; nsCSSValuePair* mCSSValuePair; + nsCSSRect* mCSSRect; nsCSSValueList* mCSSValueList; nsStringBuffer* mString; } mValue; @@ -287,6 +290,10 @@ public: NS_ASSERTION(IsCSSValuePairUnit(mUnit), "unit mismatch"); return mValue.mCSSValuePair; } + nsCSSRect* GetCSSRectValue() const { + NS_ASSERTION(IsCSSRectUnit(mUnit), "unit mismatch"); + return mValue.mCSSRect; + } nsCSSValueList* GetCSSValueListValue() const { NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch"); return mValue.mCSSValueList; @@ -336,6 +343,7 @@ public: // "SetAndAdopt*". void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit); void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit); + void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit); Value& operator=(const Value& aOther); @@ -356,6 +364,9 @@ public: static PRBool IsCSSValuePairUnit(Unit aUnit) { return aUnit == eUnit_CSSValuePair; } + static PRBool IsCSSRectUnit(Unit aUnit) { + return aUnit == eUnit_CSSRect; + } static PRBool IsCSSValueListUnit(Unit aUnit) { return aUnit == eUnit_Dasharray || aUnit == eUnit_Shadow; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 42799c4e7c0b..1c0cd11bacde 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1302,14 +1302,7 @@ struct nsStyleDisplay { // We guarantee that if mBinding is non-null, so are mBinding->mURI and // mBinding->mOriginPrincipal. nsRefPtr mBinding; // [reset] -#if 0 - // XXX This is how it is defined in the CSS2 spec, but the errata - // changed it to be consistent with the positioning draft and how - // Nav and IE implement it - nsMargin mClip; // [reset] offsets from respective edge -#else nsRect mClip; // [reset] offsets from upper-left border edge -#endif float mOpacity; // [reset] PRUint8 mDisplay; // [reset] see nsStyleConsts.h NS_STYLE_DISPLAY_* PRUint8 mOriginalDisplay; // [reset] saved mDisplay for position:absolute/fixed diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index a54c71c820aa..1a5d6999622b 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -59,6 +59,7 @@ var supported_properties = { "-moz-column-rule-color": [ test_color_transition ], "-moz-column-rule-width": [ test_length_transition ], "-moz-column-width": [ test_length_transition ], + "-moz-image-region": [ test_rect_transition ], "-moz-outline-radius-bottomleft": [ test_radius_transition ], "-moz-outline-radius-bottomright": [ test_radius_transition ], "-moz-outline-radius-topleft": [ test_radius_transition ], @@ -76,6 +77,7 @@ var supported_properties = { "border-top-color": [ test_color_transition ], "border-top-width": [ test_length_transition ], "bottom": [ test_length_transition, test_percent_transition ], + "clip": [ test_rect_transition ], "color": [ test_color_transition ], "fill": [ test_color_transition ], "fill-opacity" : [ test_float_zeroToOne_transition ], @@ -526,6 +528,26 @@ function test_length_percent_pair_transition(prop) { "length-valued property " + prop + ": interpolation of lengths"); } +function test_rect_transition(prop) { + div.style.setProperty("-moz-transition-property", "none", ""); + div.style.setProperty(prop, "rect(4px, 16px, 12px, 8px)", ""); + is(cs.getPropertyValue(prop), "rect(4px, 16px, 12px, 8px)", + "rect-valued property " + prop + ": computed value before transition"); + div.style.setProperty("-moz-transition-property", prop, ""); + div.style.setProperty(prop, "rect(0px, 6px, 4px, 2px)", ""); + is(cs.getPropertyValue(prop), "rect(2px, 11px, 8px, 5px)", + "rect-valued property " + prop + ": interpolation of rects"); + if (prop == "clip") { + div.style.setProperty(prop, "rect(0px, 6px, 4px, auto)", ""); + is(cs.getPropertyValue(prop), "rect(0px, 6px, 4px, auto)", + "rect-valued property " + prop + ": can't interpolate auto components"); + div.style.setProperty(prop, "rect(0px, 6px, 4px, 2px)", ""); + } + div.style.setProperty(prop, "auto", ""); + is(cs.getPropertyValue(prop), "auto", + "rect-valued property " + prop + ": can't interpolate auto components"); +} +