mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Implement step-start, step-end, and steps() timing functions. (Bug 435442, patch 0) r=bzbarsky
This commit is contained in:
parent
b69ea14b1d
commit
7bee896472
@ -647,6 +647,8 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
|
||||
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN 2
|
||||
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT 3
|
||||
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT 4
|
||||
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START 5
|
||||
#define NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END 6
|
||||
|
||||
// See nsStyleText
|
||||
// Note: these values pickup after the text-align values because there
|
||||
|
@ -437,6 +437,8 @@ CSS_KEY(square, square)
|
||||
CSS_KEY(start, start)
|
||||
CSS_KEY(static, static)
|
||||
CSS_KEY(status-bar, status_bar)
|
||||
CSS_KEY(step-end, step_end)
|
||||
CSS_KEY(step-start, step_start)
|
||||
CSS_KEY(stretch, stretch)
|
||||
CSS_KEY(stretch-to-fit, stretch_to_fit)
|
||||
CSS_KEY(stroke, stroke)
|
||||
|
@ -113,7 +113,7 @@ namespace css = mozilla::css;
|
||||
#define VARIANT_NORMAL 0x080000 // M
|
||||
#define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
|
||||
#define VARIANT_GRADIENT 0x200000 // eCSSUnit_Gradient
|
||||
#define VARIANT_CUBIC_BEZIER 0x400000 // CSS transition timing function
|
||||
#define VARIANT_TIMING_FUNCTION 0x400000 // cubic-bezier() and steps()
|
||||
#define VARIANT_ALL 0x800000 //
|
||||
#define VARIANT_IMAGE_RECT 0x01000000 // eCSSUnit_Function
|
||||
// This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:
|
||||
@ -154,7 +154,6 @@ namespace css = mozilla::css;
|
||||
#define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
|
||||
#define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
|
||||
#define VARIANT_LPN (VARIANT_LP | VARIANT_NUMBER)
|
||||
#define VARIANT_TIMING_FUNCTION (VARIANT_KEYWORD | VARIANT_CUBIC_BEZIER)
|
||||
#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD)
|
||||
#define VARIANT_UO (VARIANT_URL | VARIANT_NONE)
|
||||
#define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)
|
||||
@ -517,6 +516,7 @@ protected:
|
||||
PRBool ParseTransitionTimingFunctionValueComponent(float& aComponent,
|
||||
char aStop,
|
||||
PRBool aCheckRange);
|
||||
PRBool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue);
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
PRBool ParsePaint(nsCSSProperty aPropID);
|
||||
@ -4215,7 +4215,7 @@ CSSParserImpl::TranslateDimension(nsCSSValue& aValue,
|
||||
VARIANT_NORMAL | \
|
||||
VARIANT_SYSFONT | \
|
||||
VARIANT_GRADIENT | \
|
||||
VARIANT_CUBIC_BEZIER | \
|
||||
VARIANT_TIMING_FUNCTION | \
|
||||
VARIANT_ALL | \
|
||||
VARIANT_CALC
|
||||
|
||||
@ -4487,15 +4487,22 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (((aVariantMask & VARIANT_CUBIC_BEZIER) != 0) &&
|
||||
if (((aVariantMask & VARIANT_TIMING_FUNCTION) != 0) &&
|
||||
(eCSSToken_Function == tk->mType)) {
|
||||
if (tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")) {
|
||||
if (tk->mIdent.LowerCaseEqualsLiteral("cubic-bezier")) {
|
||||
if (!ParseTransitionTimingFunctionValues(aValue)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (tk->mIdent.LowerCaseEqualsLiteral("steps")) {
|
||||
if (!ParseTransitionStepTimingFunctionValues(aValue)) {
|
||||
SkipUntil(')');
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
if ((aVariantMask & VARIANT_CALC) &&
|
||||
(eCSSToken_Function == tk->mType) &&
|
||||
@ -7956,6 +7963,48 @@ CSSParserImpl::ParseTransitionTimingFunctionValueComponent(float& aComponent,
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
CSSParserImpl::ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue)
|
||||
{
|
||||
NS_ASSERTION(!mHavePushBack &&
|
||||
mToken.mType == eCSSToken_Function &&
|
||||
mToken.mIdent.LowerCaseEqualsLiteral("steps"),
|
||||
"unexpected initial state");
|
||||
|
||||
nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(2);
|
||||
|
||||
if (!ParsePositiveNonZeroVariant(val->Item(0), VARIANT_INTEGER, nsnull)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRInt32 type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;
|
||||
if (ExpectSymbol(',', PR_TRUE)) {
|
||||
if (!GetToken(PR_TRUE)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
type = -1;
|
||||
if (mToken.mType == eCSSToken_Ident) {
|
||||
if (mToken.mIdent.LowerCaseEqualsLiteral("start")) {
|
||||
type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START;
|
||||
} else if (mToken.mIdent.LowerCaseEqualsLiteral("end")) {
|
||||
type = NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END;
|
||||
}
|
||||
}
|
||||
if (type == -1) {
|
||||
UngetToken();
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
val->Item(1).SetIntValue(type, eCSSUnit_Enumerated);
|
||||
|
||||
if (!ExpectSymbol(')', PR_TRUE)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
aValue.SetArrayValue(val, eCSSUnit_Steps);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static nsCSSValueList*
|
||||
AppendValueToList(nsCSSValue& aContainer,
|
||||
nsCSSValueList* aTail,
|
||||
|
@ -2288,7 +2288,7 @@ CSS_PROP_DISPLAY(
|
||||
CSS_PROP_DOMPROP_PREFIXED(TransitionTimingFunction),
|
||||
CSS_PROPERTY_PARSE_VALUE_LIST |
|
||||
CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
|
||||
VARIANT_TIMING_FUNCTION, // used by list parsing
|
||||
VARIANT_KEYWORD | VARIANT_TIMING_FUNCTION, // used by list parsing
|
||||
kTransitionTimingFunctionKTable,
|
||||
CSS_PROP_NO_OFFSET,
|
||||
eStyleAnimType_None)
|
||||
|
@ -1262,6 +1262,8 @@ const PRInt32 nsCSSProps::kTransitionTimingFunctionKTable[] = {
|
||||
eCSSKeyword_ease_in, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN,
|
||||
eCSSKeyword_ease_out, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT,
|
||||
eCSSKeyword_ease_in_out, NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT,
|
||||
eCSSKeyword_step_start, NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START,
|
||||
eCSSKeyword_step_end, NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END,
|
||||
eCSSKeyword_UNKNOWN,-1
|
||||
};
|
||||
|
||||
|
@ -691,11 +691,12 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
|
||||
nsStyleUtil::AppendEscapedCSSIdent(buffer, aResult);
|
||||
}
|
||||
}
|
||||
else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Cubic_Bezier) {
|
||||
else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Steps) {
|
||||
switch (unit) {
|
||||
case eCSSUnit_Counter: aResult.AppendLiteral("counter("); break;
|
||||
case eCSSUnit_Counters: aResult.AppendLiteral("counters("); break;
|
||||
case eCSSUnit_Cubic_Bezier: aResult.AppendLiteral("cubic-bezier("); break;
|
||||
case eCSSUnit_Steps: aResult.AppendLiteral("steps("); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@ -717,6 +718,21 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
|
||||
else
|
||||
aResult.AppendLiteral(", ");
|
||||
}
|
||||
if (unit == eCSSUnit_Steps && i == 1) {
|
||||
NS_ABORT_IF_FALSE(array->Item(i).GetUnit() == eCSSUnit_Enumerated &&
|
||||
(array->Item(i).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
|
||||
array->Item(i).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
|
||||
"unexpected value");
|
||||
if (array->Item(i).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) {
|
||||
aResult.AppendLiteral("start");
|
||||
} else {
|
||||
aResult.AppendLiteral("end");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
nsCSSProperty prop =
|
||||
((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) &&
|
||||
i == array->Count() - 1)
|
||||
@ -981,6 +997,7 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult) const
|
||||
case eCSSUnit_Array: break;
|
||||
case eCSSUnit_Attr:
|
||||
case eCSSUnit_Cubic_Bezier:
|
||||
case eCSSUnit_Steps:
|
||||
case eCSSUnit_Counter:
|
||||
case eCSSUnit_Counters: aResult.Append(PRUnichar(')')); break;
|
||||
case eCSSUnit_Local_Font: break;
|
||||
|
@ -115,7 +115,8 @@ enum nsCSSUnit {
|
||||
eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value
|
||||
eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value
|
||||
eCSSUnit_Cubic_Bezier = 23, // (nsCSSValue::Array*) a list of float values
|
||||
eCSSUnit_Function = 24, // (nsCSSValue::Array*) a function with
|
||||
eCSSUnit_Steps = 24, // (nsCSSValue::Array*) a list of (integer, enumerated)
|
||||
eCSSUnit_Function = 25, // (nsCSSValue::Array*) a function with
|
||||
// parameters. First elem of array is name,
|
||||
// the rest of the values are arguments.
|
||||
|
||||
@ -127,14 +128,14 @@ enum nsCSSUnit {
|
||||
// exists so we can distinguish calc(2em) from 2em as specified values
|
||||
// (but we drop this distinction for nsStyleCoord when we store
|
||||
// computed values).
|
||||
eCSSUnit_Calc = 25, // (nsCSSValue::Array*) calc() value
|
||||
eCSSUnit_Calc = 30, // (nsCSSValue::Array*) calc() value
|
||||
// Plus, Minus, Times_* and Divided have arrays with exactly 2
|
||||
// elements. a + b + c + d is grouped as ((a + b) + c) + d
|
||||
eCSSUnit_Calc_Plus = 26, // (nsCSSValue::Array*) + node within calc()
|
||||
eCSSUnit_Calc_Minus = 27, // (nsCSSValue::Array*) - within calc
|
||||
eCSSUnit_Calc_Times_L = 28, // (nsCSSValue::Array*) num * val within calc
|
||||
eCSSUnit_Calc_Times_R = 29, // (nsCSSValue::Array*) val * num within calc
|
||||
eCSSUnit_Calc_Divided = 30, // (nsCSSValue::Array*) / within calc
|
||||
eCSSUnit_Calc_Plus = 31, // (nsCSSValue::Array*) + node within calc()
|
||||
eCSSUnit_Calc_Minus = 32, // (nsCSSValue::Array*) - within calc
|
||||
eCSSUnit_Calc_Times_L = 33, // (nsCSSValue::Array*) num * val within calc
|
||||
eCSSUnit_Calc_Times_R = 34, // (nsCSSValue::Array*) val * num within calc
|
||||
eCSSUnit_Calc_Divided = 35, // (nsCSSValue::Array*) / within calc
|
||||
|
||||
eCSSUnit_URL = 40, // (nsCSSValue::URL*) value
|
||||
eCSSUnit_Image = 41, // (nsCSSValue::Image*) value
|
||||
|
@ -3882,6 +3882,35 @@ nsComputedDOMStyle::DoGetTransitionProperty()
|
||||
return valueList;
|
||||
}
|
||||
|
||||
void
|
||||
nsComputedDOMStyle::AppendTimingFunction(nsDOMCSSValueList *aValueList,
|
||||
const nsTimingFunction& aTimingFunction)
|
||||
{
|
||||
nsROCSSPrimitiveValue* timingFunction = GetROCSSPrimitiveValue();
|
||||
aValueList->AppendCSSValue(timingFunction);
|
||||
|
||||
if (aTimingFunction.mType == nsTimingFunction::Function) {
|
||||
// set the value from the cubic-bezier control points
|
||||
// (We could try to regenerate the keywords if we want.)
|
||||
timingFunction->SetString(
|
||||
nsPrintfCString(64, "cubic-bezier(%f, %f, %f, %f)",
|
||||
aTimingFunction.mFunc.mX1,
|
||||
aTimingFunction.mFunc.mY1,
|
||||
aTimingFunction.mFunc.mX2,
|
||||
aTimingFunction.mFunc.mY2));
|
||||
} else {
|
||||
nsString tmp;
|
||||
tmp.AppendLiteral("steps(");
|
||||
tmp.AppendInt(aTimingFunction.mSteps);
|
||||
if (aTimingFunction.mType == nsTimingFunction::StepStart) {
|
||||
tmp.AppendLiteral(", start)");
|
||||
} else {
|
||||
tmp.AppendLiteral(", end)");
|
||||
}
|
||||
timingFunction->SetString(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
nsIDOMCSSValue*
|
||||
nsComputedDOMStyle::DoGetTransitionTimingFunction()
|
||||
{
|
||||
@ -3893,16 +3922,8 @@ nsComputedDOMStyle::DoGetTransitionTimingFunction()
|
||||
"first item must be explicit");
|
||||
PRUint32 i = 0;
|
||||
do {
|
||||
const nsTransition *transition = &display->mTransitions[i];
|
||||
nsROCSSPrimitiveValue* timingFunction = GetROCSSPrimitiveValue();
|
||||
valueList->AppendCSSValue(timingFunction);
|
||||
|
||||
// set the value from the cubic-bezier control points
|
||||
// (We could try to regenerate the keywords if we want.)
|
||||
const nsTimingFunction& tf = transition->GetTimingFunction();
|
||||
timingFunction->SetString(
|
||||
nsPrintfCString(64, "cubic-bezier(%f, %f, %f, %f)",
|
||||
tf.mX1, tf.mY1, tf.mX2, tf.mY2));
|
||||
AppendTimingFunction(valueList,
|
||||
display->mTransitions[i].GetTimingFunction());
|
||||
} while (++i < display->mTransitionTimingFunctionCount);
|
||||
|
||||
return valueList;
|
||||
|
@ -168,6 +168,8 @@ private:
|
||||
void GetImageRectString(nsIURI* aURI,
|
||||
const nsStyleSides& aCropRect,
|
||||
nsString& aString);
|
||||
void AppendTimingFunction(nsDOMCSSValueList *aValueList,
|
||||
const nsTimingFunction& aTimingFunction);
|
||||
|
||||
/* Properties queryable as CSSValues.
|
||||
* To avoid a name conflict with nsIDOM*CSS2Properties, these are all
|
||||
|
@ -3838,6 +3838,28 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
|
||||
array->Item(3).GetFloatValue()));
|
||||
}
|
||||
break;
|
||||
case eCSSUnit_Steps:
|
||||
{
|
||||
nsCSSValue::Array* array =
|
||||
timingFunction.list->mValue.GetArrayValue();
|
||||
NS_ASSERTION(array && array->Count() == 2,
|
||||
"Need 2 items");
|
||||
NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer,
|
||||
"unexpected first value");
|
||||
NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
|
||||
(array->Item(1).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
|
||||
array->Item(1).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END),
|
||||
"unexpected second value");
|
||||
transition->SetTimingFunction(
|
||||
nsTimingFunction((
|
||||
array->Item(1).GetIntValue() ==
|
||||
NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END)
|
||||
? nsTimingFunction::StepEnd : nsTimingFunction::StepStart,
|
||||
array->Item(0).GetIntValue()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Invalid transition property unit");
|
||||
}
|
||||
|
@ -1921,6 +1921,20 @@ nsStyleBackground::Layer::operator==(const Layer& aOther) const
|
||||
//
|
||||
void nsTimingFunction::AssignFromKeyword(PRInt32 aTimingFunctionType)
|
||||
{
|
||||
switch (aTimingFunctionType) {
|
||||
case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
|
||||
mType = StepStart;
|
||||
mSteps = 1;
|
||||
return;
|
||||
case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
|
||||
mType = StepEnd;
|
||||
mSteps = 1;
|
||||
return;
|
||||
default:
|
||||
mType = Function;
|
||||
break;
|
||||
}
|
||||
|
||||
PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0);
|
||||
PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1);
|
||||
PR_STATIC_ASSERT(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2);
|
||||
@ -1937,10 +1951,10 @@ void nsTimingFunction::AssignFromKeyword(PRInt32 aTimingFunctionType)
|
||||
|
||||
NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5,
|
||||
"keyword out of range");
|
||||
mX1 = timingFunctionValues[aTimingFunctionType][0];
|
||||
mY1 = timingFunctionValues[aTimingFunctionType][1];
|
||||
mX2 = timingFunctionValues[aTimingFunctionType][2];
|
||||
mY2 = timingFunctionValues[aTimingFunctionType][3];
|
||||
mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
|
||||
mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
|
||||
mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
|
||||
mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
|
||||
}
|
||||
|
||||
nsTransition::nsTransition(const nsTransition& aCopy)
|
||||
|
@ -1309,6 +1309,8 @@ struct nsStyleVisibility {
|
||||
};
|
||||
|
||||
struct nsTimingFunction {
|
||||
enum Type { Function, StepStart, StepEnd };
|
||||
|
||||
explicit nsTimingFunction(PRInt32 aTimingFunctionType
|
||||
= NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)
|
||||
{
|
||||
@ -1316,26 +1318,60 @@ struct nsTimingFunction {
|
||||
}
|
||||
|
||||
nsTimingFunction(float x1, float y1, float x2, float y2)
|
||||
: mX1(x1)
|
||||
, mY1(y1)
|
||||
, mX2(x2)
|
||||
, mY2(y2)
|
||||
{}
|
||||
|
||||
float mX1;
|
||||
float mY1;
|
||||
float mX2;
|
||||
float mY2;
|
||||
|
||||
PRBool operator==(const nsTimingFunction& aOther) const
|
||||
: mType(Function)
|
||||
{
|
||||
return !(*this != aOther);
|
||||
mFunc.mX1 = x1;
|
||||
mFunc.mY1 = y1;
|
||||
mFunc.mX2 = x2;
|
||||
mFunc.mY2 = y2;
|
||||
}
|
||||
|
||||
PRBool operator!=(const nsTimingFunction& aOther) const
|
||||
nsTimingFunction(Type aType, PRUint32 aSteps)
|
||||
: mType(aType)
|
||||
{
|
||||
return mX1 != aOther.mX1 || mY1 != aOther.mY1 ||
|
||||
mX2 != aOther.mX2 || mY2 != aOther.mY2;
|
||||
NS_ABORT_IF_FALSE(mType == StepStart || mType == StepEnd, "wrong type");
|
||||
mSteps = aSteps;
|
||||
}
|
||||
|
||||
nsTimingFunction(const nsTimingFunction& aOther)
|
||||
: mType(aOther.mType)
|
||||
{
|
||||
if (mType == Function) {
|
||||
mFunc.mX1 = aOther.mFunc.mX1;
|
||||
mFunc.mY1 = aOther.mFunc.mY1;
|
||||
mFunc.mX2 = aOther.mFunc.mX2;
|
||||
mFunc.mY2 = aOther.mFunc.mY2;
|
||||
} else {
|
||||
mSteps = aOther.mSteps;
|
||||
}
|
||||
}
|
||||
|
||||
Type mType;
|
||||
union {
|
||||
struct {
|
||||
float mX1;
|
||||
float mY1;
|
||||
float mX2;
|
||||
float mY2;
|
||||
} mFunc;
|
||||
PRUint32 mSteps;
|
||||
};
|
||||
|
||||
bool operator==(const nsTimingFunction& aOther) const
|
||||
{
|
||||
if (mType != aOther.mType) {
|
||||
return false;
|
||||
}
|
||||
if (mType == Function) {
|
||||
return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
|
||||
mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
|
||||
}
|
||||
return mSteps == aOther.mSteps;
|
||||
}
|
||||
|
||||
bool operator!=(const nsTimingFunction& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -65,6 +65,59 @@ namespace dom = mozilla::dom;
|
||||
* Per-Element data *
|
||||
*****************************************************************************/
|
||||
|
||||
class ComputedTimingFunction {
|
||||
public:
|
||||
typedef nsTimingFunction::Type Type;
|
||||
void Init(const nsTimingFunction &aFunction);
|
||||
double GetValue(double aPortion) const;
|
||||
private:
|
||||
Type mType;
|
||||
nsSMILKeySpline mTimingFunction;
|
||||
PRUint32 mSteps;
|
||||
};
|
||||
|
||||
void
|
||||
ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
|
||||
{
|
||||
mType = aFunction.mType;
|
||||
if (mType == nsTimingFunction::Function) {
|
||||
mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
|
||||
aFunction.mFunc.mX2, aFunction.mFunc.mY2);
|
||||
} else {
|
||||
mSteps = aFunction.mSteps;
|
||||
}
|
||||
}
|
||||
|
||||
static inline double
|
||||
StepEnd(PRUint32 aSteps, double aPortion)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range");
|
||||
PRUint32 step = PRUint32(aPortion * aSteps); // floor
|
||||
return double(step) / double(aSteps);
|
||||
}
|
||||
|
||||
double
|
||||
ComputedTimingFunction::GetValue(double aPortion) const
|
||||
{
|
||||
switch (mType) {
|
||||
case nsTimingFunction::Function:
|
||||
return mTimingFunction.GetSplineValue(aPortion);
|
||||
case nsTimingFunction::StepStart:
|
||||
// There are diagrams in the spec that seem to suggest this check
|
||||
// and the bounds point should not be symmetric with StepEnd, but
|
||||
// should actually step up at rather than immediately after the
|
||||
// fraction points. However, we rely on rounding negative values
|
||||
// up to zero, so we can't do that. And it's not clear the spec
|
||||
// really meant it.
|
||||
return 1.0 - StepEnd(mSteps, 1.0 - aPortion);
|
||||
default:
|
||||
NS_ABORT_IF_FALSE(PR_FALSE, "bad type");
|
||||
// fall through
|
||||
case nsTimingFunction::StepEnd:
|
||||
return StepEnd(mSteps, aPortion);
|
||||
}
|
||||
}
|
||||
|
||||
struct ElementPropertyTransition
|
||||
{
|
||||
nsCSSProperty mProperty;
|
||||
@ -73,7 +126,7 @@ struct ElementPropertyTransition
|
||||
|
||||
// data from the relevant nsTransition
|
||||
TimeDuration mDuration;
|
||||
nsSMILKeySpline mTimingFunction;
|
||||
ComputedTimingFunction mTimingFunction;
|
||||
|
||||
// This is the start value to be used for a check for whether a
|
||||
// transition is being reversed. Normally the same as mStartValue,
|
||||
@ -134,7 +187,7 @@ ElementPropertyTransition::ValuePortionFor(TimeStamp aRefreshTime) const
|
||||
timePortion = 1.0; // we might be behind on flushing
|
||||
}
|
||||
|
||||
return mTimingFunction.GetSplineValue(timePortion);
|
||||
return mTimingFunction.GetValue(timePortion);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -704,7 +757,7 @@ nsTransitionManager::ConsiderStartingTransition(nsCSSProperty aProperty,
|
||||
pt.mProperty = aProperty;
|
||||
pt.mStartTime = mostRecentRefresh + TimeDuration::FromMilliseconds(delay);
|
||||
pt.mDuration = TimeDuration::FromMilliseconds(duration);
|
||||
pt.mTimingFunction.Init(tf.mX1, tf.mY1, tf.mX2, tf.mY2);
|
||||
pt.mTimingFunction.Init(tf);
|
||||
|
||||
if (!aElementTransitions) {
|
||||
aElementTransitions =
|
||||
|
@ -179,6 +179,7 @@ _TEST_FILES = test_acid3_test46.html \
|
||||
test_transitions_events.html \
|
||||
test_transitions.html \
|
||||
test_transitions_per_property.html \
|
||||
test_transitions_step_functions.html \
|
||||
test_transitions_dynamic_changes.html \
|
||||
test_transitions_bug537151.html \
|
||||
test_unclosed_parentheses.html \
|
||||
|
@ -2641,8 +2641,8 @@ var gCSSProperties = {
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "ease", "cubic-bezier(0.25, 0.1, 0.25, 1.0)" ],
|
||||
other_values: [ "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)" ],
|
||||
invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)" ]
|
||||
other_values: [ "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)", "step-start", "step-end", "steps(1)", "steps(2, start)", "steps(386)", "steps(3, end)" ],
|
||||
invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)", "steps(2, step-end)", "steps(0)", "steps(-2)", "steps(0, step-end, 1)" ]
|
||||
},
|
||||
"unicode-bidi": {
|
||||
domProp: "unicodeBidi",
|
||||
|
98
layout/style/test/test_transitions_step_functions.html
Normal file
98
layout/style/test/test_transitions_step_functions.html
Normal file
@ -0,0 +1,98 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=435441
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 435441</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style type="text/css">
|
||||
|
||||
p.transition {
|
||||
-moz-transition: margin-top 100s linear;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for transition step functions **/
|
||||
|
||||
function px_to_num(str)
|
||||
{
|
||||
return Number(String(str).match(/^([\d.]+)px$/)[1]);
|
||||
}
|
||||
|
||||
var display = document.getElementById("display");
|
||||
|
||||
function run_test(tf, percent, value)
|
||||
{
|
||||
var p = document.createElement("p");
|
||||
p.className = "transition";
|
||||
p.style.marginTop = "0px";
|
||||
// be this percent of the way through a 100s transition
|
||||
p.style.MozTransitionDelay = (percent * -100) + "s";
|
||||
p.style.MozTransitionTimingFunction = tf;
|
||||
display.appendChild(p);
|
||||
var cs = getComputedStyle(p, "");
|
||||
var flush1 = cs.marginTop;
|
||||
|
||||
p.style.marginTop = "1000px";
|
||||
var result = px_to_num(cs.marginTop) / 1000
|
||||
|
||||
is(result, value, 100 * percent + "% of the way through " + tf);
|
||||
|
||||
display.removeChild(p);
|
||||
}
|
||||
|
||||
run_test("step-start", 0, 0);
|
||||
run_test("step-start", 0.001, 1);
|
||||
run_test("step-start", 0.999, 1);
|
||||
run_test("step-start", 1, 1);
|
||||
run_test("step-end", 0, 0);
|
||||
run_test("step-end", 0.001, 0);
|
||||
run_test("step-end", 0.999, 0);
|
||||
run_test("step-end", 1, 1);
|
||||
|
||||
run_test("steps(2)", 0.00, 0.0);
|
||||
run_test("steps(2)", 0.49, 0.0);
|
||||
run_test("steps(2)", 0.50, 0.5);
|
||||
run_test("steps(2)", 0.99, 0.5);
|
||||
run_test("steps(2)", 1.00, 1.0);
|
||||
|
||||
run_test("steps(2, end)", 0.00, 0.0);
|
||||
run_test("steps(2, end)", 0.49, 0.0);
|
||||
run_test("steps(2, end)", 0.50, 0.5);
|
||||
run_test("steps(2, end)", 0.99, 0.5);
|
||||
run_test("steps(2, end)", 1.00, 1.0);
|
||||
|
||||
run_test("steps(2, start)", 0.00, 0.0);
|
||||
run_test("steps(2, start)", 0.01, 0.5);
|
||||
run_test("steps(2, start)", 0.50, 0.5);
|
||||
run_test("steps(2, start)", 0.51, 1.0);
|
||||
run_test("steps(2, start)", 1.00, 1.0);
|
||||
|
||||
run_test("steps(8,end)", 0.00, 0.0);
|
||||
run_test("steps(8,end)", 0.10, 0.0);
|
||||
run_test("steps(8,end)", 0.20, 0.125);
|
||||
run_test("steps(8,end)", 0.30, 0.25);
|
||||
run_test("steps(8,end)", 0.40, 0.375);
|
||||
run_test("steps(8,end)", 0.49, 0.375);
|
||||
run_test("steps(8,end)", 0.50, 0.5);
|
||||
run_test("steps(8,end)", 0.60, 0.5);
|
||||
run_test("steps(8,end)", 0.70, 0.625);
|
||||
run_test("steps(8,end)", 0.80, 0.75);
|
||||
run_test("steps(8,end)", 0.90, 0.875);
|
||||
run_test("steps(8,end)", 1.00, 1.0);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user