diff --git a/dom/interfaces/css/nsIDOMCSS2Properties.idl b/dom/interfaces/css/nsIDOMCSS2Properties.idl index 0c386bf3a32..76d39df320d 100644 --- a/dom/interfaces/css/nsIDOMCSS2Properties.idl +++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl @@ -51,7 +51,7 @@ * http://www.w3.org/TR/DOM-Level-2-Style */ -[scriptable, uuid(7cf11a5f-4be5-4e31-b427-58d82746b5f5)] +[scriptable, uuid(1ca298f0-4eaf-4483-8aa2-587f392f84bb)] interface nsIDOMCSS2Properties : nsISupports { attribute DOMString background; @@ -681,6 +681,9 @@ interface nsIDOMCSS2Properties : nsISupports attribute DOMString MozTransformOrigin; // raises(DOMException) on setting + attribute DOMString MozPerspective; + // raises(DOMException) on setting + attribute DOMString MozWindowShadow; // raises(DOMException) on setting diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 0eaa43cf372..3aebe7dbe03 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2376,24 +2376,39 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame, /* Get the matrix, then change its basis to factor in the origin. */ PRBool dummy; + gfx3DMatrix result = + nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform, + aFrame->GetStyleContext(), + aFrame->PresContext(), + dummy, bounds, aFactor); + + const nsStyleDisplay* parentDisp = nsnull; + if (aFrame->GetParent()) { + parentDisp = aFrame->GetParent()->GetStyleDisplay(); + } + if (nsLayoutUtils::Are3DTransformsEnabled() && + parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord && + parentDisp->mChildPerspective.GetCoordValue() > 0.0) { + gfx3DMatrix perspective; + perspective._34 = + -1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(), + aFactor); + result = result * perspective; + } return nsLayoutUtils::ChangeMatrixBasis - (newOrigin + toMozOrigin, - nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform, - aFrame->GetStyleContext(), - aFrame->PresContext(), - dummy, bounds, aFactor)); -} - -const gfx3DMatrix& -nsDisplayTransform::GetTransform(float aFactor) -{ - if (mTransform.IsIdentity() || mCachedFactor != aFactor) { - mTransform = - GetResultingTransformMatrix(mFrame, ToReferenceFrame(), - aFactor, - nsnull); - mCachedFactor = aFactor; - } + (newOrigin + toMozOrigin, result); +} + +const gfx3DMatrix& +nsDisplayTransform::GetTransform(float aFactor) +{ + if (mTransform.IsIdentity() || mCachedFactor != aFactor) { + mTransform = + GetResultingTransformMatrix(mFrame, ToReferenceFrame(), + aFactor, + nsnull); + mCachedFactor = aFactor; + } return mTransform; } diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 3cd639372bc..31267f1f7dd 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -367,6 +367,7 @@ CSS_KEY(padding-box, padding_box) CSS_KEY(painted, painted) CSS_KEY(paused, paused) CSS_KEY(pc, pc) +CSS_KEY(perspective, perspective) CSS_KEY(physical, physical) CSS_KEY(pointer, pointer) CSS_KEY(portrait, portrait) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 398f1843a0c..00b3896ec60 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -121,6 +121,7 @@ namespace css = mozilla::css; #define VARIANT_ZERO_ANGLE 0x02000000 // unitless zero for angles #define VARIANT_CALC 0x04000000 // eCSSUnit_Calc #define VARIANT_ELEMENT 0x08000000 // eCSSUnit_Element +#define VARIANT_POSITIVE_LENGTH 0x10000000 // Only lengths greater than 0.0 // Common combinations of variants #define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH) @@ -4545,6 +4546,12 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue, ((aVariantMask & (VARIANT_LENGTH | VARIANT_ZERO_ANGLE)) != 0 && eCSSToken_Number == tk->mType && tk->mNumber == 0.0f)) { + if ((aVariantMask & VARIANT_POSITIVE_LENGTH) != 0 && + eCSSToken_Number == tk->mType && + tk->mNumber <= 0.0) { + UngetToken(); + return PR_FALSE; + } if (TranslateDimension(aValue, aVariantMask, tk->mNumber, tk->mIdent)) { return PR_TRUE; } @@ -7278,6 +7285,7 @@ static PRBool GetFunctionParseInformation(nsCSSKeyword aToken, eAngle, eTwoAngles, eNumber, + ePositiveLength, eTwoNumbers, eThreeNumbers, eThreeNumbersOneAngle, @@ -7293,6 +7301,7 @@ static PRBool GetFunctionParseInformation(nsCSSKeyword aToken, {VARIANT_ANGLE_OR_ZERO}, {VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO}, {VARIANT_NUMBER}, + {VARIANT_LENGTH|VARIANT_POSITIVE_LENGTH}, {VARIANT_NUMBER, VARIANT_NUMBER}, {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER}, {VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO}, @@ -7305,7 +7314,7 @@ static PRBool GetFunctionParseInformation(nsCSSKeyword aToken, #ifdef DEBUG static const PRUint8 kVariantMaskLengths[eNumVariantMasks] = - {1, 1, 2, 3, 1, 2, 1, 2, 3, 4, 6, 16}; + {1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 16}; #endif PRInt32 variantIndex = eNumVariantMasks; @@ -7409,6 +7418,13 @@ static PRBool GetFunctionParseInformation(nsCSSKeyword aToken, aMaxElems = 16U; aIs3D = PR_TRUE; break; + case eCSSKeyword_perspective: + /* Exactly one scale number. */ + variantIndex = ePositiveLength; + aMinElems = 1U; + aMaxElems = 1U; + aIs3D = PR_TRUE; + break; default: /* Oh dear, we didn't match. Report an error. */ return PR_FALSE; diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index dc0f7cb387b..c6c71fe4c12 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -2258,6 +2258,15 @@ CSS_PROP_DISPLAY( kBackgroundPositionKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_Custom) +CSS_PROP_DISPLAY( + -moz-perspective, + perspective, + CSS_PROP_DOMPROP_PREFIXED(Perspective), + CSS_PROPERTY_PARSE_VALUE, + VARIANT_NONE | VARIANT_INHERIT | VARIANT_LENGTH, + nsnull, + offsetof(nsStyleDisplay, mChildPerspective), + eStyleAnimType_Coord) CSS_PROP_POSITION( top, top, diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 14ee1671d73..a7bc3bab4dc 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -941,6 +941,19 @@ nsComputedDOMStyle::DoGetMozTransformOrigin() return valueList; } +nsIDOMCSSValue* +nsComputedDOMStyle::DoGetMozPerspective() +{ + nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue(); + if (GetStyleDisplay()->mChildPerspective.GetUnit() == eStyleUnit_Coord && + GetStyleDisplay()->mChildPerspective.GetCoordValue() == 0.0) { + val->SetIdent(eCSSKeyword_none); + } else { + SetValueToCoord(val, GetStyleDisplay()->mChildPerspective, PR_FALSE); + } + return val; +} + /* If the property is "none", hand back "none" wrapped in a value. * Otherwise, compute the aggregate transform matrix and hands it back in a * "matrix" wrapper. @@ -4397,6 +4410,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength) COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight), COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_topLeft, OutlineRadiusTopLeft), COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_outline_radius_topRight, OutlineRadiusTopRight), + COMPUTED_STYLE_MAP_ENTRY(perspective, MozPerspective), COMPUTED_STYLE_MAP_ENTRY(stack_sizing, StackSizing), COMPUTED_STYLE_MAP_ENTRY(_moz_tab_size, MozTabSize), COMPUTED_STYLE_MAP_ENTRY(text_blink, MozTextBlink), diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 46354f556cb..e32d7e568f1 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -347,6 +347,7 @@ private: nsIDOMCSSValue* DoGetPageBreakBefore(); nsIDOMCSSValue* DoGetMozTransform(); nsIDOMCSSValue* DoGetMozTransformOrigin(); + nsIDOMCSSValue* DoGetMozPerspective(); nsIDOMCSSValue* DoGetOrient(); /* User interface properties */ diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 85fdb8b0f7b..6c6bdefc958 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -4484,6 +4484,11 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct, NS_ASSERTION(result, "Malformed -moz-transform-origin parse!"); } + SetCoord(*aRuleData->ValueForPerspective(), + display->mChildPerspective, parentDisplay->mChildPerspective, + SETCOORD_LAH | SETCOORD_INITIAL_ZERO | SETCOORD_NONE, + aContext, mPresContext, canStoreInRuleTree); + // orient: enum, inherit, initial SetDiscrete(*aRuleData->ValueForOrient(), display->mOrient, canStoreInRuleTree, diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 0b091504238..a481de8b988 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2033,6 +2033,7 @@ nsStyleDisplay::nsStyleDisplay() mSpecifiedTransform = nsnull; mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin mTransformOrigin[1].SetPercentValue(0.5f); + mChildPerspective.SetCoordValue(0); mOrient = NS_STYLE_ORIENT_HORIZONTAL; mTransitions.AppendElement(); @@ -2098,6 +2099,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource) /* Copy over transform origin. */ mTransformOrigin[0] = aSource.mTransformOrigin[0]; mTransformOrigin[1] = aSource.mTransformOrigin[1]; + mChildPerspective = aSource.mChildPerspective; } nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const @@ -2159,6 +2161,10 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const nsChangeHint_RepaintFrame)); break; } + + if (mChildPerspective != aOther.mChildPerspective) + NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, + nsChangeHint_RepaintFrame)); } // Note: Our current behavior for handling changes to the diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 6faa4960e3a..ea747caeca6 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1515,6 +1515,7 @@ struct nsStyleDisplay { // null, as appropriate.) (owned by the style rule) const nsCSSValueList *mSpecifiedTransform; // [reset] nsStyleCoord mTransformOrigin[2]; // [reset] percent, coord, calc + nsStyleCoord mChildPerspective; // [reset] coord nsAutoTArray mTransitions; // [reset] // The number of elements in mTransitions that are not from repeating diff --git a/layout/style/nsStyleTransformMatrix.cpp b/layout/style/nsStyleTransformMatrix.cpp index 9de7eb35137..1d1bea3cee7 100644 --- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -607,6 +607,34 @@ nsStyleTransformMatrix::ProcessRotate3D(const nsCSSValue::Array* aData) return temp; } +/* static */ gfx3DMatrix +nsStyleTransformMatrix::ProcessPerspective(const nsCSSValue::Array* aData, + nsStyleContext *aContext, + nsPresContext *aPresContext, + PRBool &aCanStoreInRuleTree, + float aAppUnitsPerMatrixUnit) +{ + NS_PRECONDITION(aData->Count() == 2, "Invalid array!"); + + /* We want our matrix to look like this: + * | 1 0 0 0 | + * | 0 1 0 0 | + * | 0 0 1 -1/depth | + * | 0 0 0 1 | + */ + + gfx3DMatrix temp; + + float depth; + ProcessTranslatePart(depth, aData->Item(1), aContext, + aPresContext, aCanStoreInRuleTree, + 0, aAppUnitsPerMatrixUnit); + NS_ASSERTION(depth > 0.0, "Perspective must be positive!"); + temp._34 = -1.0/depth; + + return temp; +} + /** * Return the transform function, as an nsCSSKeyword, for the given * nsCSSValue::Array from a transform list. @@ -687,6 +715,9 @@ nsStyleTransformMatrix::MatrixForTransformFunction(const nsCSSValue::Array * aDa case eCSSKeyword_interpolatematrix: return ProcessInterpolateMatrix(aData, aContext, aPresContext, aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit); + case eCSSKeyword_perspective: + return ProcessPerspective(aData, aContext, aPresContext, + aCanStoreInRuleTree, aAppUnitsPerMatrixUnit); default: NS_NOTREACHED("Unknown transform function!"); } diff --git a/layout/style/nsStyleTransformMatrix.h b/layout/style/nsStyleTransformMatrix.h index e5a5713561b..16f33443bcd 100644 --- a/layout/style/nsStyleTransformMatrix.h +++ b/layout/style/nsStyleTransformMatrix.h @@ -150,6 +150,11 @@ class nsStyleTransformMatrix static gfx3DMatrix ProcessRotateY(const nsCSSValue::Array *aData); static gfx3DMatrix ProcessRotateZ(const nsCSSValue::Array *aData); static gfx3DMatrix ProcessRotate3D(const nsCSSValue::Array *aData); + static gfx3DMatrix ProcessPerspective(const nsCSSValue::Array *aData, + nsStyleContext *aContext, + nsPresContext *aPresContext, + PRBool &aCanStoreInRuleTree, + float aAppUnitsPerMatrixUnit); }; #endif diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 0ac43cbead6..7e1bd95e453 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -967,6 +967,14 @@ var gCSSProperties = { "border", "center red", "right diagonal", "#00ffff bottom"] }, + "-moz-perspective": { + domProp: "MozPerspective", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "none", "0" ], + other_values: [ "1000px", "500.2px", "-100px", "-27.2em" ], + invalid_values: [ "pants", "200" ] + }, "-moz-user-focus": { domProp: "MozUserFocus", inherited: true, diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index 3b904c4a345..2df306b18c2 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -191,6 +191,7 @@ var supported_properties = { "padding-top": [ test_length_transition, test_percent_transition, test_length_percent_calc_transition, test_length_clamped, test_percent_clamped ], + "-moz-perspective": [ test_length_transition ], "right": [ test_length_transition, test_percent_transition, test_length_percent_calc_transition, test_length_unclamped, test_percent_unclamped ],