Bug 505115 - Part 9 - Implement the perspective() transform function and the perspective CSS property. r=dbaron

This commit is contained in:
Matt Woodrow 2011-08-03 15:04:22 +12:00
parent d9e573335e
commit b4bfd8dd6a
14 changed files with 135 additions and 19 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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),

View File

@ -347,6 +347,7 @@ private:
nsIDOMCSSValue* DoGetPageBreakBefore();
nsIDOMCSSValue* DoGetMozTransform();
nsIDOMCSSValue* DoGetMozTransformOrigin();
nsIDOMCSSValue* DoGetMozPerspective();
nsIDOMCSSValue* DoGetOrient();
/* User interface properties */

View File

@ -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,

View File

@ -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

View File

@ -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<nsTransition, 1> mTransitions; // [reset]
// The number of elements in mTransitions that are not from repeating

View File

@ -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!");
}

View File

@ -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

View File

@ -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,

View File

@ -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 ],