mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Add support for animation of text-shadow and -moz-box-shadow (the first complex value types that we animate). (Bug 523196) r=dholbert sr=bzbarsky
This commit is contained in:
parent
f85d2aae1c
commit
4c0fa8e623
@ -1143,8 +1143,8 @@ CSS_PROP_BORDER(
|
||||
mBoxShadow,
|
||||
eCSSType_ValueList,
|
||||
kBoxShadowTypeKTable,
|
||||
CSS_PROP_NO_OFFSET,
|
||||
eStyleAnimType_None)
|
||||
offsetof(nsStyleBorder, mBoxShadow),
|
||||
eStyleAnimType_Shadow)
|
||||
CSS_PROP_POSITION(
|
||||
-moz-box-sizing,
|
||||
box_sizing,
|
||||
@ -2308,8 +2308,8 @@ CSS_PROP_TEXT(
|
||||
mTextShadow,
|
||||
eCSSType_ValueList,
|
||||
nsnull,
|
||||
CSS_PROP_NO_OFFSET,
|
||||
eStyleAnimType_None)
|
||||
offsetof(nsStyleText, mTextShadow),
|
||||
eStyleAnimType_Shadow)
|
||||
CSS_PROP_TEXT(
|
||||
text-transform,
|
||||
text_transform,
|
||||
|
@ -95,6 +95,9 @@ enum nsStyleAnimType {
|
||||
// nsStyleSVGPaint values
|
||||
eStyleAnimType_PaintServer,
|
||||
|
||||
// nsRefPtr<nsCSSShadowArray> values
|
||||
eStyleAnimType_Shadow,
|
||||
|
||||
// property not animatable
|
||||
eStyleAnimType_None
|
||||
};
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "nsICSSLoader.h"
|
||||
#include "nsCSSDataBlock.h"
|
||||
#include "nsCSSDeclaration.h"
|
||||
#include "nsCSSStruct.h"
|
||||
#include "prlog.h"
|
||||
#include <math.h>
|
||||
|
||||
@ -152,6 +153,67 @@ nsStyleAnimation::ComputeDistance(const Value& aStartValue,
|
||||
diffG * diffG + diffB * diffB);
|
||||
break;
|
||||
}
|
||||
case eUnit_Shadow: {
|
||||
// Call AddWeighted to make us lists of the same length.
|
||||
Value normValue1, normValue2;
|
||||
if (!AddWeighted(1.0, aStartValue, 0.0, aEndValue, normValue1) ||
|
||||
!AddWeighted(0.0, aStartValue, 1.0, aEndValue, normValue2)) {
|
||||
success = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
const nsCSSValueList *shadow1 = normValue1.GetCSSValueListValue();
|
||||
const nsCSSValueList *shadow2 = normValue2.GetCSSValueListValue();
|
||||
|
||||
double distance = 0.0f;
|
||||
while (shadow1 && shadow2) {
|
||||
nsCSSValue::Array *array1 = shadow1->mValue.GetArrayValue();
|
||||
nsCSSValue::Array *array2 = shadow2->mValue.GetArrayValue();
|
||||
for (PRUint32 i = 0; i < 4; ++i) {
|
||||
NS_ABORT_IF_FALSE(array1->Item(i).GetUnit() == eCSSUnit_Pixel,
|
||||
"unexpected unit");
|
||||
NS_ABORT_IF_FALSE(array2->Item(i).GetUnit() == eCSSUnit_Pixel,
|
||||
"unexpected unit");
|
||||
double diff = array1->Item(i).GetFloatValue() -
|
||||
array2->Item(i).GetFloatValue();
|
||||
distance += diff * diff;
|
||||
}
|
||||
|
||||
const nsCSSValue& color1 = array1->Item(4);
|
||||
const nsCSSValue& color2 = array2->Item(4);
|
||||
const nsCSSValue& inset1 = array1->Item(5);
|
||||
const nsCSSValue& inset2 = array2->Item(5);
|
||||
// There are only two possible states of the inset value:
|
||||
// (1) GetUnit() == eCSSUnit_Null
|
||||
// (2) GetUnit() == eCSSUnit_Enumerated &&
|
||||
// GetIntValue() == NS_STYLE_BOX_SHADOW_INSET
|
||||
NS_ABORT_IF_FALSE(color1.GetUnit() == color2.GetUnit() &&
|
||||
inset1 == inset2,
|
||||
"AddWeighted should have failed");
|
||||
|
||||
if (color1.GetUnit() != eCSSUnit_Null) {
|
||||
nsStyleAnimation::Value color1Value
|
||||
(color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
|
||||
nsStyleAnimation::Value color2Value
|
||||
(color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
|
||||
double colorDistance;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool ok =
|
||||
#endif
|
||||
nsStyleAnimation::ComputeDistance(color1Value, color2Value,
|
||||
colorDistance);
|
||||
NS_ABORT_IF_FALSE(ok, "should not fail");
|
||||
distance += colorDistance * colorDistance;
|
||||
}
|
||||
|
||||
shadow1 = shadow1->mNext;
|
||||
shadow2 = shadow2->mNext;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(!shadow1 && !shadow2, "lists of different lengths");
|
||||
aDistance = sqrt(distance);
|
||||
break;
|
||||
}
|
||||
case eUnit_Null:
|
||||
case eUnit_None:
|
||||
success = PR_FALSE;
|
||||
@ -175,6 +237,73 @@ inline PRUint8 ClampColor(double aColor)
|
||||
return NSToIntRound(aColor);
|
||||
}
|
||||
|
||||
static PRBool
|
||||
AddShadowItems(double aCoeff1, const nsCSSValue &aValue1,
|
||||
double aCoeff2, const nsCSSValue &aValue2,
|
||||
nsCSSValueList **&aResultTail)
|
||||
{
|
||||
// X, Y, Radius, Spread, Color, Inset
|
||||
NS_ABORT_IF_FALSE(aValue1.GetUnit() == eCSSUnit_Array,
|
||||
"wrong unit");
|
||||
NS_ABORT_IF_FALSE(aValue2.GetUnit() == eCSSUnit_Array,
|
||||
"wrong unit");
|
||||
nsCSSValue::Array *array1 = aValue1.GetArrayValue();
|
||||
nsCSSValue::Array *array2 = aValue2.GetArrayValue();
|
||||
nsRefPtr<nsCSSValue::Array> resultArray = nsCSSValue::Array::Create(6);
|
||||
if (!resultArray) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < 4; ++i) {
|
||||
NS_ABORT_IF_FALSE(array1->Item(i).GetUnit() == eCSSUnit_Pixel,
|
||||
"unexpected unit");
|
||||
NS_ABORT_IF_FALSE(array2->Item(i).GetUnit() == eCSSUnit_Pixel,
|
||||
"unexpected unit");
|
||||
double pixel1 = array1->Item(i).GetFloatValue();
|
||||
double pixel2 = array2->Item(i).GetFloatValue();
|
||||
resultArray->Item(i).SetFloatValue(aCoeff1 * pixel1 + aCoeff2 * pixel2,
|
||||
eCSSUnit_Pixel);
|
||||
}
|
||||
|
||||
const nsCSSValue& color1 = array1->Item(4);
|
||||
const nsCSSValue& color2 = array2->Item(4);
|
||||
const nsCSSValue& inset1 = array1->Item(5);
|
||||
const nsCSSValue& inset2 = array2->Item(5);
|
||||
if (color1.GetUnit() != color2.GetUnit() ||
|
||||
inset1.GetUnit() != inset2.GetUnit()) {
|
||||
// We don't know how to animate between color and no-color, or
|
||||
// between inset and not-inset.
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
if (color1.GetUnit() != eCSSUnit_Null) {
|
||||
nsStyleAnimation::Value color1Value
|
||||
(color1.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
|
||||
nsStyleAnimation::Value color2Value
|
||||
(color2.GetColorValue(), nsStyleAnimation::Value::ColorConstructor);
|
||||
nsStyleAnimation::Value resultColorValue;
|
||||
#ifdef DEBUG
|
||||
PRBool ok =
|
||||
#endif
|
||||
nsStyleAnimation::AddWeighted(aCoeff1, color1Value, aCoeff2, color2Value,
|
||||
resultColorValue);
|
||||
NS_ABORT_IF_FALSE(ok, "should not fail");
|
||||
resultArray->Item(4).SetColorValue(resultColorValue.GetColorValue());
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(inset1 == inset2, "should match");
|
||||
resultArray->Item(5) = inset1;
|
||||
|
||||
nsCSSValueList *resultItem = new nsCSSValueList;
|
||||
if (!resultItem) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
resultItem->mValue.SetArrayValue(resultArray, eCSSUnit_Array);
|
||||
*aResultTail = resultItem;
|
||||
aResultTail = &resultItem->mNext;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsStyleAnimation::AddWeighted(double aCoeff1, const Value& aValue1,
|
||||
double aCoeff2, const Value& aValue2,
|
||||
@ -242,6 +371,53 @@ nsStyleAnimation::AddWeighted(double aCoeff1, const Value& aValue1,
|
||||
aResultValue.SetColorValue(resultColor);
|
||||
break;
|
||||
}
|
||||
case eUnit_Shadow: {
|
||||
// This is implemented according to:
|
||||
// http://dev.w3.org/csswg/css3-transitions/#animation-of-property-types-
|
||||
// and the third item in the summary of:
|
||||
// http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
|
||||
const nsCSSValueList *shadow1 = aValue1.GetCSSValueListValue();
|
||||
const nsCSSValueList *shadow2 = aValue2.GetCSSValueListValue();
|
||||
nsAutoPtr<nsCSSValueList> result;
|
||||
nsCSSValueList **resultTail = getter_Transfers(result);
|
||||
while (shadow1 && shadow2) {
|
||||
if (!AddShadowItems(aCoeff1, shadow1->mValue,
|
||||
aCoeff2, shadow2->mValue,
|
||||
resultTail)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
shadow1 = shadow1->mNext;
|
||||
shadow2 = shadow2->mNext;
|
||||
}
|
||||
if (shadow1 || shadow2) {
|
||||
const nsCSSValueList *longShadow;
|
||||
double longCoeff;
|
||||
if (shadow1) {
|
||||
longShadow = shadow1;
|
||||
longCoeff = aCoeff1;
|
||||
} else {
|
||||
longShadow = shadow2;
|
||||
longCoeff = aCoeff2;
|
||||
}
|
||||
|
||||
while (longShadow) {
|
||||
// Passing coefficients that add to less than 1 produces the
|
||||
// desired result of interpolating "0 0 0 transparent" with
|
||||
// the current shadow.
|
||||
if (!AddShadowItems(longCoeff, longShadow->mValue,
|
||||
0.0, longShadow->mValue,
|
||||
resultTail)) {
|
||||
return PR_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
longShadow = longShadow->mNext;
|
||||
}
|
||||
}
|
||||
aResultValue.SetCSSValueListValue(result.forget(), eUnit_Shadow,
|
||||
PR_TRUE);
|
||||
break;
|
||||
}
|
||||
case eUnit_Null:
|
||||
case eUnit_None:
|
||||
success = PR_FALSE;
|
||||
@ -402,6 +578,12 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
|
||||
SetColorValue(aComputedValue.GetColorValue());
|
||||
}
|
||||
break;
|
||||
case eUnit_Shadow:
|
||||
NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] ==
|
||||
eCSSType_ValueList, "type mismatch");
|
||||
*static_cast<nsCSSValueList**>(aSpecifiedValue) =
|
||||
aComputedValue.GetCSSValueListValue();
|
||||
break;
|
||||
default:
|
||||
return PR_FALSE;
|
||||
}
|
||||
@ -630,6 +812,54 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
case eStyleAnimType_Shadow: {
|
||||
const nsCSSShadowArray *shadowArray =
|
||||
*static_cast<const nsRefPtr<nsCSSShadowArray>*>(
|
||||
StyleDataAtOffset(styleStruct, ssOffset));
|
||||
if (!shadowArray) {
|
||||
aComputedValue.SetCSSValueListValue(nsnull, eUnit_Shadow, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
nsAutoPtr<nsCSSValueList> result;
|
||||
nsCSSValueList **resultTail = getter_Transfers(result);
|
||||
for (PRUint32 i = 0, i_end = shadowArray->Length(); i < i_end; ++i) {
|
||||
const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i);
|
||||
// X, Y, Radius, Spread, Color, Inset
|
||||
nsRefPtr<nsCSSValue::Array> 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);
|
||||
// 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);
|
||||
if (shadow->mHasColor) {
|
||||
arr->Item(4).SetColorValue(shadow->mColor);
|
||||
}
|
||||
if (shadow->mInset) {
|
||||
arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
|
||||
eCSSUnit_Enumerated);
|
||||
}
|
||||
|
||||
nsCSSValueList *resultItem = new nsCSSValueList;
|
||||
if (!resultItem) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
|
||||
*resultTail = resultItem;
|
||||
resultTail = &resultItem->mNext;
|
||||
}
|
||||
aComputedValue.SetCSSValueListValue(result.forget(), eUnit_Shadow,
|
||||
PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
case eStyleAnimType_None:
|
||||
NS_NOTREACHED("shouldn't use on non-animatable properties");
|
||||
}
|
||||
@ -682,6 +912,9 @@ nsStyleAnimation::Value::operator=(const Value& aOther)
|
||||
case eUnit_Color:
|
||||
mValue.mColor = aOther.mValue.mColor;
|
||||
break;
|
||||
case eUnit_Shadow:
|
||||
mValue.mCSSValueList = aOther.mValue.mCSSValueList
|
||||
? aOther.mValue.mCSSValueList->Clone() : nsnull;
|
||||
}
|
||||
|
||||
return *this;
|
||||
@ -740,9 +973,27 @@ nsStyleAnimation::Value::SetColorValue(nscolor aColor)
|
||||
mValue.mColor = aColor;
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleAnimation::Value::SetCSSValueListValue(nsCSSValueList *aValueList,
|
||||
Unit aUnit,
|
||||
PRBool aTakeOwnership)
|
||||
{
|
||||
FreeValue();
|
||||
NS_ASSERTION(IsCSSValueListUnit(aUnit), "bad unit");
|
||||
mUnit = aUnit;
|
||||
if (aTakeOwnership) {
|
||||
mValue.mCSSValueList = aValueList;
|
||||
} else {
|
||||
mValue.mCSSValueList = aValueList ? aValueList->Clone() : nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsStyleAnimation::Value::FreeValue()
|
||||
{
|
||||
if (IsCSSValueListUnit(mUnit)) {
|
||||
delete mValue.mCSSValueList;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -765,6 +1016,9 @@ nsStyleAnimation::Value::operator==(const Value& aOther) const
|
||||
return mValue.mFloat == aOther.mValue.mFloat;
|
||||
case eUnit_Color:
|
||||
return mValue.mColor == aOther.mValue.mColor;
|
||||
case eUnit_Shadow:
|
||||
return nsCSSValueList::Equal(mValue.mCSSValueList,
|
||||
aOther.mValue.mCSSValueList);
|
||||
}
|
||||
|
||||
NS_NOTREACHED("incomplete case");
|
||||
|
@ -52,6 +52,7 @@ class nsCSSDeclaration;
|
||||
class nsIContent;
|
||||
class nsPresContext;
|
||||
class nsStyleContext;
|
||||
struct nsCSSValueList;
|
||||
|
||||
/**
|
||||
* Utility class to handle animated style values
|
||||
@ -173,7 +174,10 @@ public:
|
||||
* for some types this means that the void* is pointing to memory
|
||||
* owned by the nsStyleAnimation::Value. (For all complex types, the
|
||||
* nsStyleAnimation::Value owns the necessary objects so that the
|
||||
* caller does not need to do anything to free them.)
|
||||
* caller does not need to do anything to free them. However, this
|
||||
* means that callers using the void* variant must keep
|
||||
* |aComputedValue| alive longer than the structure into which they've
|
||||
* filled the value.)
|
||||
*
|
||||
* @param aProperty The property whose value we're uncomputing.
|
||||
* @param aPresContext The presentation context for the document in
|
||||
@ -215,7 +219,8 @@ public:
|
||||
eUnit_Coord,
|
||||
eUnit_Percent,
|
||||
eUnit_Float,
|
||||
eUnit_Color
|
||||
eUnit_Color,
|
||||
eUnit_Shadow // nsCSSValueList* (may be null)
|
||||
};
|
||||
|
||||
class Value {
|
||||
@ -225,6 +230,7 @@ public:
|
||||
nscoord mCoord;
|
||||
float mFloat;
|
||||
nscolor mColor;
|
||||
nsCSSValueList* mCSSValueList;
|
||||
} mValue;
|
||||
public:
|
||||
Unit GetUnit() const {
|
||||
@ -254,6 +260,10 @@ public:
|
||||
NS_ASSERTION(mUnit == eUnit_Color, "unit mismatch");
|
||||
return mValue.mColor;
|
||||
}
|
||||
nsCSSValueList* GetCSSValueListValue() const {
|
||||
NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValueList;
|
||||
}
|
||||
|
||||
explicit Value(Unit aUnit = eUnit_Null) : mUnit(aUnit) {
|
||||
NS_ASSERTION(aUnit == eUnit_Null || aUnit == eUnit_Normal ||
|
||||
@ -279,6 +289,8 @@ public:
|
||||
void SetPercentValue(float aPercent);
|
||||
void SetFloatValue(float aFloat);
|
||||
void SetColorValue(nscolor aColor);
|
||||
void SetCSSValueListValue(nsCSSValueList *aValue, Unit aUnit,
|
||||
PRBool aTakeOwnership);
|
||||
|
||||
Value& operator=(const Value& aOther);
|
||||
|
||||
@ -288,6 +300,10 @@ public:
|
||||
|
||||
private:
|
||||
void FreeValue();
|
||||
|
||||
static PRBool IsCSSValueListUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_Shadow;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -64,7 +64,11 @@ using mozilla::TimeDuration;
|
||||
struct ElementPropertyTransition
|
||||
{
|
||||
nsCSSProperty mProperty;
|
||||
nsStyleAnimation::Value mStartValue, mEndValue;
|
||||
// We need to have mCurrentValue as a member of this structure because
|
||||
// the result of the calls to |Interpolate| might hold data that this
|
||||
// object's owning style rule needs to keep alive (after calling
|
||||
// UncomputeValue on it in MapRuleInfoInto).
|
||||
nsStyleAnimation::Value mStartValue, mEndValue, mCurrentValue;
|
||||
TimeStamp mStartTime; // actual start plus transition delay
|
||||
|
||||
// data from the relevant nsTransition
|
||||
@ -227,12 +231,11 @@ ElementTransitionsStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
|
||||
|
||||
double valuePortion =
|
||||
pt.mTimingFunction.GetSplineValue(timePortion);
|
||||
nsStyleAnimation::Value value;
|
||||
#ifdef DEBUG
|
||||
PRBool ok =
|
||||
#endif
|
||||
nsStyleAnimation::Interpolate(pt.mStartValue, pt.mEndValue,
|
||||
valuePortion, value);
|
||||
valuePortion, pt.mCurrentValue);
|
||||
NS_ABORT_IF_FALSE(ok, "could not interpolate values");
|
||||
|
||||
void *prop =
|
||||
@ -241,7 +244,7 @@ ElementTransitionsStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
|
||||
ok =
|
||||
#endif
|
||||
nsStyleAnimation::UncomputeValue(pt.mProperty, aRuleData->mPresContext,
|
||||
value, prop);
|
||||
pt.mCurrentValue, prop);
|
||||
NS_ABORT_IF_FALSE(ok, "could not store computed value");
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ function any_unit_to_num(str)
|
||||
}
|
||||
|
||||
var supported_properties = {
|
||||
"-moz-box-shadow": [ test_shadow_transition ],
|
||||
"-moz-column-gap": [ test_length_transition ],
|
||||
"-moz-column-rule-color": [ test_color_transition ],
|
||||
"-moz-column-width": [ test_length_transition ],
|
||||
@ -99,6 +100,7 @@ var supported_properties = {
|
||||
"stroke-opacity" : [ test_float_zeroToOne_transition ],
|
||||
"stroke-width": [ test_length_transition, test_percent_transition ],
|
||||
"text-indent": [ test_length_transition, test_percent_transition ],
|
||||
"text-shadow": [ test_shadow_transition ],
|
||||
"top": [ test_length_transition, test_percent_transition ],
|
||||
"vertical-align": [ test_length_transition, test_percent_transition ],
|
||||
"width": [ test_length_transition, test_percent_transition ],
|
||||
@ -275,6 +277,49 @@ function test_color_transition(prop) {
|
||||
"color-valued property " + prop + ": interpolation of colors");
|
||||
}
|
||||
|
||||
function test_shadow_transition(prop) {
|
||||
var spreadStr = (prop == "-moz-box-shadow") ? " 0px" : "";
|
||||
|
||||
div.style.setProperty("-moz-transition-property", "none", "");
|
||||
div.style.setProperty(prop, "none", "");
|
||||
is(cs.getPropertyValue(prop), "none",
|
||||
"shadow-valued property " + prop + ": computed value before transition");
|
||||
div.style.setProperty("-moz-transition-property", prop, "");
|
||||
div.style.setProperty(prop, "4px 8px 3px red", "");
|
||||
is(cs.getPropertyValue(prop), "rgba(255, 0, 0, 0.5) 2px 4px 1.5px" + spreadStr,
|
||||
"shadow-valued property " + prop + ": interpolation of shadows");
|
||||
|
||||
div.style.setProperty("-moz-transition-property", "none", "");
|
||||
div.style.setProperty(prop, "green 4px 4px, 2px 2px blue", "");
|
||||
is(cs.getPropertyValue(prop), "rgb(0, 128, 0) 4px 4px 0px" + spreadStr + ", rgb(0, 0, 255) 2px 2px 0px" + spreadStr,
|
||||
"shadow-valued property " + prop + ": computed value before transition");
|
||||
div.style.setProperty("-moz-transition-property", prop, "");
|
||||
div.style.setProperty(prop, "8px 8px 8px red", "");
|
||||
is(cs.getPropertyValue(prop), "rgb(128, 64, 0) 6px 6px 4px" + spreadStr + ", rgba(0, 0, 255, 0.5) 1px 1px 0px" + spreadStr,
|
||||
"shadow-valued property " + prop + ": interpolation of shadows");
|
||||
|
||||
if (prop == "-moz-box-shadow") {
|
||||
div.style.setProperty(prop, "8px 8px 8px red inset", "");
|
||||
is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 0px inset",
|
||||
"shadow-valued property " + prop + ": non-interpolable cases");
|
||||
div.style.setProperty(prop, "8px 8px 8px 8px red inset", "");
|
||||
is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 4px inset",
|
||||
"shadow-valued property " + prop + ": interpolation of spread");
|
||||
// Leave in same state whether in the |if| or not.
|
||||
div.style.setProperty(prop, "8px 8px 8px red", "");
|
||||
is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 0px",
|
||||
"shadow-valued property " + prop + ": non-interpolable cases");
|
||||
}
|
||||
|
||||
var defaultColor = cs.getPropertyValue("color") + " ";
|
||||
div.style.setProperty(prop, "2px 2px 2px", "");
|
||||
is(cs.getPropertyValue(prop), defaultColor + "2px 2px 2px" + spreadStr,
|
||||
"shadow-valued property " + prop + ": non-interpolable cases");
|
||||
div.style.setProperty(prop, "4px 8px 6px", "");
|
||||
is(cs.getPropertyValue(prop), defaultColor + "3px 5px 4px" + spreadStr,
|
||||
"shadow-valued property " + prop + ": interpolation without color");
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user