mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 605231 - Move transform parsing code out of font property parsing code. r=dbaron
This commit is contained in:
parent
ab2798ea67
commit
9c000701a5
@ -8401,432 +8401,6 @@ CSSParserImpl::ParseOneFamily(nsAString& aFamily)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// transform Parsing Implementation
|
||||
|
||||
/* Reads a function list of arguments. Do not call this function
|
||||
* directly; it's mean to be caled from ParseFunction.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[],
|
||||
uint16_t aMinElems,
|
||||
uint16_t aMaxElems,
|
||||
InfallibleTArray<nsCSSValue> &aOutput)
|
||||
{
|
||||
for (uint16_t index = 0; index < aMaxElems; ++index) {
|
||||
nsCSSValue newValue;
|
||||
if (!ParseVariant(newValue, aVariantMask[index], nullptr))
|
||||
return false;
|
||||
|
||||
aOutput.AppendElement(newValue);
|
||||
|
||||
// See whether to continue or whether to look for end of function.
|
||||
if (!ExpectSymbol(',', true)) {
|
||||
// We need to read the closing parenthesis, and also must take care
|
||||
// that we haven't read too few symbols.
|
||||
return ExpectSymbol(')', true) && (index + 1) >= aMinElems;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're here, we finished looping without hitting the end, so we read too
|
||||
// many elements.
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Parses a function [ input of the form (a [, b]*) ] and stores it
|
||||
* as an nsCSSValue that holds a function of the form
|
||||
* function-name arg1 arg2 ... argN
|
||||
*
|
||||
* On error, the return value is false.
|
||||
*
|
||||
* @param aFunction The name of the function that we're reading.
|
||||
* @param aAllowedTypes An array of values corresponding to the legal
|
||||
* types for each element in the function. The zeroth element in the
|
||||
* array corresponds to the first function parameter, etc. The length
|
||||
* of this array _must_ be greater than or equal to aMaxElems or the
|
||||
* behavior is undefined.
|
||||
* @param aMinElems Minimum number of elements to read. Reading fewer than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aMaxElems Maximum number of elements to read. Reading more than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aValue (out) The value that was parsed.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseFunction(const nsString &aFunction,
|
||||
const int32_t aAllowedTypes[],
|
||||
uint16_t aMinElems, uint16_t aMaxElems,
|
||||
nsCSSValue &aValue)
|
||||
{
|
||||
typedef InfallibleTArray<nsCSSValue>::size_type arrlen_t;
|
||||
|
||||
/* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
|
||||
* elements stored in the the nsCSSValue::Array.
|
||||
*/
|
||||
static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE;
|
||||
|
||||
/* Make a copy of the function name, since the reference is _probably_ to
|
||||
* mToken.mIdent, which is going to get overwritten during the course of this
|
||||
* function.
|
||||
*/
|
||||
nsString functionName(aFunction);
|
||||
|
||||
/* Read in a list of values as an array, failing if we can't or if
|
||||
* it's out of bounds.
|
||||
*/
|
||||
InfallibleTArray<nsCSSValue> foundValues;
|
||||
if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems,
|
||||
foundValues))
|
||||
return false;
|
||||
|
||||
/* Now, convert this array into an nsCSSValue::Array object.
|
||||
* We'll need N + 1 spots, one for the function name and the rest for the
|
||||
* arguments. In case the user has given us more than 2^16 - 2 arguments,
|
||||
* we'll truncate them at 2^16 - 2 arguments.
|
||||
*/
|
||||
uint16_t numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ?
|
||||
foundValues.Length() + 1 : MAX_ALLOWED_ELEMS);
|
||||
nsRefPtr<nsCSSValue::Array> convertedArray =
|
||||
nsCSSValue::Array::Create(numElements);
|
||||
|
||||
/* Copy things over. */
|
||||
convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident);
|
||||
for (uint16_t index = 0; index + 1 < numElements; ++index)
|
||||
convertedArray->Item(index + 1) = foundValues[static_cast<arrlen_t>(index)];
|
||||
|
||||
/* Fill in the outparam value with the array. */
|
||||
aValue.SetArrayValue(convertedArray, eCSSUnit_Function);
|
||||
|
||||
/* Return it! */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a token, determines the minimum and maximum number of function
|
||||
* parameters to read, along with the mask that should be used to read
|
||||
* those function parameters. If the token isn't a transform function,
|
||||
* returns an error.
|
||||
*
|
||||
* @param aToken The token identifying the function.
|
||||
* @param aMinElems [out] The minimum number of elements to read.
|
||||
* @param aMaxElems [out] The maximum number of elements to read
|
||||
* @param aVariantMask [out] The variant mask to use during parsing
|
||||
* @return Whether the information was loaded successfully.
|
||||
*/
|
||||
static bool GetFunctionParseInformation(nsCSSKeyword aToken,
|
||||
bool aIsPrefixed,
|
||||
uint16_t &aMinElems,
|
||||
uint16_t &aMaxElems,
|
||||
const int32_t *& aVariantMask,
|
||||
bool &aIs3D)
|
||||
{
|
||||
/* These types represent the common variant masks that will be used to
|
||||
* parse out the individual functions. The order in the enumeration
|
||||
* must match the order in which the masks are declared.
|
||||
*/
|
||||
enum { eLengthPercentCalc,
|
||||
eLengthCalc,
|
||||
eTwoLengthPercentCalcs,
|
||||
eTwoLengthPercentCalcsOneLengthCalc,
|
||||
eAngle,
|
||||
eTwoAngles,
|
||||
eNumber,
|
||||
ePositiveLength,
|
||||
eTwoNumbers,
|
||||
eThreeNumbers,
|
||||
eThreeNumbersOneAngle,
|
||||
eMatrix,
|
||||
eMatrixPrefixed,
|
||||
eMatrix3d,
|
||||
eMatrix3dPrefixed,
|
||||
eNumVariantMasks };
|
||||
static const int32_t kMaxElemsPerFunction = 16;
|
||||
static const int32_t kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = {
|
||||
{VARIANT_LPCALC},
|
||||
{VARIANT_LENGTH|VARIANT_CALC},
|
||||
{VARIANT_LPCALC, VARIANT_LPCALC},
|
||||
{VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC},
|
||||
{VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_NUMBER},
|
||||
{VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_LPNCALC, VARIANT_LPNCALC},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}};
|
||||
|
||||
#ifdef DEBUG
|
||||
static const uint8_t kVariantMaskLengths[eNumVariantMasks] =
|
||||
{1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16};
|
||||
#endif
|
||||
|
||||
int32_t variantIndex = eNumVariantMasks;
|
||||
|
||||
aIs3D = false;
|
||||
|
||||
switch (aToken) {
|
||||
case eCSSKeyword_translatex:
|
||||
case eCSSKeyword_translatey:
|
||||
/* Exactly one length or percent. */
|
||||
variantIndex = eLengthPercentCalc;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_translatez:
|
||||
/* Exactly one length */
|
||||
variantIndex = eLengthCalc;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_translate3d:
|
||||
/* Exactly two lengthds or percents and a number */
|
||||
variantIndex = eTwoLengthPercentCalcsOneLengthCalc;
|
||||
aMinElems = 3U;
|
||||
aMaxElems = 3U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_scalez:
|
||||
aIs3D = true;
|
||||
case eCSSKeyword_scalex:
|
||||
case eCSSKeyword_scaley:
|
||||
/* Exactly one scale factor. */
|
||||
variantIndex = eNumber;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_scale3d:
|
||||
/* Exactly three scale factors. */
|
||||
variantIndex = eThreeNumbers;
|
||||
aMinElems = 3U;
|
||||
aMaxElems = 3U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_rotatex:
|
||||
case eCSSKeyword_rotatey:
|
||||
aIs3D = true;
|
||||
case eCSSKeyword_rotate:
|
||||
case eCSSKeyword_rotatez:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_rotate3d:
|
||||
variantIndex = eThreeNumbersOneAngle;
|
||||
aMinElems = 4U;
|
||||
aMaxElems = 4U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_translate:
|
||||
/* One or two lengths or percents. */
|
||||
variantIndex = eTwoLengthPercentCalcs;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skew:
|
||||
/* Exactly one or two angles. */
|
||||
variantIndex = eTwoAngles;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_scale:
|
||||
/* One or two scale factors. */
|
||||
variantIndex = eTwoNumbers;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skewx:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_skewy:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_matrix:
|
||||
/* Six values, all numbers. */
|
||||
variantIndex = aIsPrefixed ? eMatrixPrefixed : eMatrix;
|
||||
aMinElems = 6U;
|
||||
aMaxElems = 6U;
|
||||
break;
|
||||
case eCSSKeyword_matrix3d:
|
||||
/* 16 matrix values, all numbers */
|
||||
variantIndex = aIsPrefixed ? eMatrix3dPrefixed : eMatrix3d;
|
||||
aMinElems = 16U;
|
||||
aMaxElems = 16U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_perspective:
|
||||
/* Exactly one scale number. */
|
||||
variantIndex = ePositiveLength;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
default:
|
||||
/* Oh dear, we didn't match. Report an error. */
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!");
|
||||
NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!");
|
||||
NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!");
|
||||
NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!");
|
||||
NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex],
|
||||
"Invalid aMaxElems for this variant mask.");
|
||||
#endif
|
||||
|
||||
// Convert the index into a mask.
|
||||
aVariantMask = kVariantMasks[variantIndex];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Reads a single transform function from the tokenizer stream, reporting an
|
||||
* error if something goes wrong.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseSingleTransform(bool aIsPrefixed,
|
||||
nsCSSValue& aValue, bool& aIs3D)
|
||||
{
|
||||
if (!GetToken(true))
|
||||
return false;
|
||||
|
||||
if (mToken.mType != eCSSToken_Function) {
|
||||
UngetToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32_t* variantMask;
|
||||
uint16_t minElems, maxElems;
|
||||
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
|
||||
|
||||
if (!GetFunctionParseInformation(keyword, aIsPrefixed,
|
||||
minElems, maxElems, variantMask, aIs3D))
|
||||
return false;
|
||||
|
||||
// Bug 721136: Normalize the identifier to lowercase, except that things
|
||||
// like scaleX should have the last character capitalized. This matches
|
||||
// what other browsers do.
|
||||
nsContentUtils::ASCIIToLower(mToken.mIdent);
|
||||
switch (keyword) {
|
||||
case eCSSKeyword_rotatex:
|
||||
case eCSSKeyword_scalex:
|
||||
case eCSSKeyword_skewx:
|
||||
case eCSSKeyword_translatex:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X'));
|
||||
break;
|
||||
|
||||
case eCSSKeyword_rotatey:
|
||||
case eCSSKeyword_scaley:
|
||||
case eCSSKeyword_skewy:
|
||||
case eCSSKeyword_translatey:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y'));
|
||||
break;
|
||||
|
||||
case eCSSKeyword_rotatez:
|
||||
case eCSSKeyword_scalez:
|
||||
case eCSSKeyword_translatez:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z'));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue);
|
||||
}
|
||||
|
||||
/* Parses a transform property list by continuously reading in properties
|
||||
* and constructing a matrix from it.
|
||||
*/
|
||||
bool CSSParserImpl::ParseTransform(bool aIsPrefixed)
|
||||
{
|
||||
nsCSSValue value;
|
||||
if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
|
||||
// 'inherit', 'initial', and 'none' must be alone
|
||||
if (!ExpectEndProperty()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
nsCSSValueList* cur = value.SetListValue();
|
||||
for (;;) {
|
||||
bool is3D;
|
||||
if (!ParseSingleTransform(aIsPrefixed, cur->mValue, is3D)) {
|
||||
return false;
|
||||
}
|
||||
if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (CheckEndProperty()) {
|
||||
break;
|
||||
}
|
||||
cur->mNext = new nsCSSValueList;
|
||||
cur = cur->mNext;
|
||||
}
|
||||
}
|
||||
AppendValue(eCSSProperty_transform, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSSParserImpl::ParseTransformOrigin(bool aPerspective)
|
||||
{
|
||||
nsCSSValuePair position;
|
||||
if (!ParseBoxPositionValues(position, true))
|
||||
return false;
|
||||
|
||||
nsCSSProperty prop = eCSSProperty_transform_origin;
|
||||
if (aPerspective) {
|
||||
if (!ExpectEndProperty()) {
|
||||
return false;
|
||||
}
|
||||
prop = eCSSProperty_perspective_origin;
|
||||
}
|
||||
|
||||
// Unlike many other uses of pairs, this position should always be stored
|
||||
// as a pair, even if the values are the same, so it always serializes as
|
||||
// a pair, and to keep the computation code simple.
|
||||
if (position.mXValue.GetUnit() == eCSSUnit_Inherit ||
|
||||
position.mXValue.GetUnit() == eCSSUnit_Initial) {
|
||||
NS_ABORT_IF_FALSE(position.mXValue == position.mYValue,
|
||||
"inherit/initial only half?");
|
||||
AppendValue(prop, position.mXValue);
|
||||
} else {
|
||||
nsCSSValue value;
|
||||
if (aPerspective) {
|
||||
value.SetPairValue(position.mXValue, position.mYValue);
|
||||
} else {
|
||||
nsCSSValue depth;
|
||||
if (!nsLayoutUtils::Are3DTransformsEnabled() ||
|
||||
// only try parsing if 3-D transforms are enabled
|
||||
!ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) {
|
||||
depth.SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
}
|
||||
value.SetTripletValue(position.mXValue, position.mYValue, depth);
|
||||
}
|
||||
|
||||
AppendValue(prop, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSParserImpl::ParseFamily(nsCSSValue& aValue)
|
||||
{
|
||||
@ -9492,7 +9066,433 @@ CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// transform Parsing Implementation
|
||||
|
||||
/* Reads a function list of arguments. Do not call this function
|
||||
* directly; it's mean to be caled from ParseFunction.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseFunctionInternals(const int32_t aVariantMask[],
|
||||
uint16_t aMinElems,
|
||||
uint16_t aMaxElems,
|
||||
InfallibleTArray<nsCSSValue> &aOutput)
|
||||
{
|
||||
for (uint16_t index = 0; index < aMaxElems; ++index) {
|
||||
nsCSSValue newValue;
|
||||
if (!ParseVariant(newValue, aVariantMask[index], nullptr))
|
||||
return false;
|
||||
|
||||
aOutput.AppendElement(newValue);
|
||||
|
||||
// See whether to continue or whether to look for end of function.
|
||||
if (!ExpectSymbol(',', true)) {
|
||||
// We need to read the closing parenthesis, and also must take care
|
||||
// that we haven't read too few symbols.
|
||||
return ExpectSymbol(')', true) && (index + 1) >= aMinElems;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're here, we finished looping without hitting the end, so we read too
|
||||
// many elements.
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Parses a function [ input of the form (a [, b]*) ] and stores it
|
||||
* as an nsCSSValue that holds a function of the form
|
||||
* function-name arg1 arg2 ... argN
|
||||
*
|
||||
* On error, the return value is false.
|
||||
*
|
||||
* @param aFunction The name of the function that we're reading.
|
||||
* @param aAllowedTypes An array of values corresponding to the legal
|
||||
* types for each element in the function. The zeroth element in the
|
||||
* array corresponds to the first function parameter, etc. The length
|
||||
* of this array _must_ be greater than or equal to aMaxElems or the
|
||||
* behavior is undefined.
|
||||
* @param aMinElems Minimum number of elements to read. Reading fewer than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aMaxElems Maximum number of elements to read. Reading more than
|
||||
* this many elements will result in the function failing.
|
||||
* @param aValue (out) The value that was parsed.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseFunction(const nsString &aFunction,
|
||||
const int32_t aAllowedTypes[],
|
||||
uint16_t aMinElems, uint16_t aMaxElems,
|
||||
nsCSSValue &aValue)
|
||||
{
|
||||
typedef InfallibleTArray<nsCSSValue>::size_type arrlen_t;
|
||||
|
||||
/* 2^16 - 2, so that if we have 2^16 - 2 transforms, we have 2^16 - 1
|
||||
* elements stored in the the nsCSSValue::Array.
|
||||
*/
|
||||
static const arrlen_t MAX_ALLOWED_ELEMS = 0xFFFE;
|
||||
|
||||
/* Make a copy of the function name, since the reference is _probably_ to
|
||||
* mToken.mIdent, which is going to get overwritten during the course of this
|
||||
* function.
|
||||
*/
|
||||
nsString functionName(aFunction);
|
||||
|
||||
/* Read in a list of values as an array, failing if we can't or if
|
||||
* it's out of bounds.
|
||||
*/
|
||||
InfallibleTArray<nsCSSValue> foundValues;
|
||||
if (!ParseFunctionInternals(aAllowedTypes, aMinElems, aMaxElems,
|
||||
foundValues))
|
||||
return false;
|
||||
|
||||
/* Now, convert this array into an nsCSSValue::Array object.
|
||||
* We'll need N + 1 spots, one for the function name and the rest for the
|
||||
* arguments. In case the user has given us more than 2^16 - 2 arguments,
|
||||
* we'll truncate them at 2^16 - 2 arguments.
|
||||
*/
|
||||
uint16_t numElements = (foundValues.Length() <= MAX_ALLOWED_ELEMS ?
|
||||
foundValues.Length() + 1 : MAX_ALLOWED_ELEMS);
|
||||
nsRefPtr<nsCSSValue::Array> convertedArray =
|
||||
nsCSSValue::Array::Create(numElements);
|
||||
|
||||
/* Copy things over. */
|
||||
convertedArray->Item(0).SetStringValue(functionName, eCSSUnit_Ident);
|
||||
for (uint16_t index = 0; index + 1 < numElements; ++index)
|
||||
convertedArray->Item(index + 1) = foundValues[static_cast<arrlen_t>(index)];
|
||||
|
||||
/* Fill in the outparam value with the array. */
|
||||
aValue.SetArrayValue(convertedArray, eCSSUnit_Function);
|
||||
|
||||
/* Return it! */
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a token, determines the minimum and maximum number of function
|
||||
* parameters to read, along with the mask that should be used to read
|
||||
* those function parameters. If the token isn't a transform function,
|
||||
* returns an error.
|
||||
*
|
||||
* @param aToken The token identifying the function.
|
||||
* @param aMinElems [out] The minimum number of elements to read.
|
||||
* @param aMaxElems [out] The maximum number of elements to read
|
||||
* @param aVariantMask [out] The variant mask to use during parsing
|
||||
* @return Whether the information was loaded successfully.
|
||||
*/
|
||||
static bool GetFunctionParseInformation(nsCSSKeyword aToken,
|
||||
bool aIsPrefixed,
|
||||
uint16_t &aMinElems,
|
||||
uint16_t &aMaxElems,
|
||||
const int32_t *& aVariantMask,
|
||||
bool &aIs3D)
|
||||
{
|
||||
/* These types represent the common variant masks that will be used to
|
||||
* parse out the individual functions. The order in the enumeration
|
||||
* must match the order in which the masks are declared.
|
||||
*/
|
||||
enum { eLengthPercentCalc,
|
||||
eLengthCalc,
|
||||
eTwoLengthPercentCalcs,
|
||||
eTwoLengthPercentCalcsOneLengthCalc,
|
||||
eAngle,
|
||||
eTwoAngles,
|
||||
eNumber,
|
||||
ePositiveLength,
|
||||
eTwoNumbers,
|
||||
eThreeNumbers,
|
||||
eThreeNumbersOneAngle,
|
||||
eMatrix,
|
||||
eMatrixPrefixed,
|
||||
eMatrix3d,
|
||||
eMatrix3dPrefixed,
|
||||
eNumVariantMasks };
|
||||
static const int32_t kMaxElemsPerFunction = 16;
|
||||
static const int32_t kVariantMasks[eNumVariantMasks][kMaxElemsPerFunction] = {
|
||||
{VARIANT_LPCALC},
|
||||
{VARIANT_LENGTH|VARIANT_CALC},
|
||||
{VARIANT_LPCALC, VARIANT_LPCALC},
|
||||
{VARIANT_LPCALC, VARIANT_LPCALC, VARIANT_LENGTH|VARIANT_CALC},
|
||||
{VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_ANGLE_OR_ZERO, VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_NUMBER},
|
||||
{VARIANT_LENGTH|VARIANT_POSITIVE_DIMENSION},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_ANGLE_OR_ZERO},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_LPNCALC, VARIANT_LPNCALC},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER},
|
||||
{VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER, VARIANT_NUMBER,
|
||||
VARIANT_LPNCALC, VARIANT_LPNCALC, VARIANT_LNCALC, VARIANT_NUMBER}};
|
||||
|
||||
#ifdef DEBUG
|
||||
static const uint8_t kVariantMaskLengths[eNumVariantMasks] =
|
||||
{1, 1, 2, 3, 1, 2, 1, 1, 2, 3, 4, 6, 6, 16, 16};
|
||||
#endif
|
||||
|
||||
int32_t variantIndex = eNumVariantMasks;
|
||||
|
||||
aIs3D = false;
|
||||
|
||||
switch (aToken) {
|
||||
case eCSSKeyword_translatex:
|
||||
case eCSSKeyword_translatey:
|
||||
/* Exactly one length or percent. */
|
||||
variantIndex = eLengthPercentCalc;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_translatez:
|
||||
/* Exactly one length */
|
||||
variantIndex = eLengthCalc;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_translate3d:
|
||||
/* Exactly two lengthds or percents and a number */
|
||||
variantIndex = eTwoLengthPercentCalcsOneLengthCalc;
|
||||
aMinElems = 3U;
|
||||
aMaxElems = 3U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_scalez:
|
||||
aIs3D = true;
|
||||
case eCSSKeyword_scalex:
|
||||
case eCSSKeyword_scaley:
|
||||
/* Exactly one scale factor. */
|
||||
variantIndex = eNumber;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_scale3d:
|
||||
/* Exactly three scale factors. */
|
||||
variantIndex = eThreeNumbers;
|
||||
aMinElems = 3U;
|
||||
aMaxElems = 3U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_rotatex:
|
||||
case eCSSKeyword_rotatey:
|
||||
aIs3D = true;
|
||||
case eCSSKeyword_rotate:
|
||||
case eCSSKeyword_rotatez:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_rotate3d:
|
||||
variantIndex = eThreeNumbersOneAngle;
|
||||
aMinElems = 4U;
|
||||
aMaxElems = 4U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_translate:
|
||||
/* One or two lengths or percents. */
|
||||
variantIndex = eTwoLengthPercentCalcs;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skew:
|
||||
/* Exactly one or two angles. */
|
||||
variantIndex = eTwoAngles;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_scale:
|
||||
/* One or two scale factors. */
|
||||
variantIndex = eTwoNumbers;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 2U;
|
||||
break;
|
||||
case eCSSKeyword_skewx:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_skewy:
|
||||
/* Exactly one angle. */
|
||||
variantIndex = eAngle;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
break;
|
||||
case eCSSKeyword_matrix:
|
||||
/* Six values, all numbers. */
|
||||
variantIndex = aIsPrefixed ? eMatrixPrefixed : eMatrix;
|
||||
aMinElems = 6U;
|
||||
aMaxElems = 6U;
|
||||
break;
|
||||
case eCSSKeyword_matrix3d:
|
||||
/* 16 matrix values, all numbers */
|
||||
variantIndex = aIsPrefixed ? eMatrix3dPrefixed : eMatrix3d;
|
||||
aMinElems = 16U;
|
||||
aMaxElems = 16U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
case eCSSKeyword_perspective:
|
||||
/* Exactly one scale number. */
|
||||
variantIndex = ePositiveLength;
|
||||
aMinElems = 1U;
|
||||
aMaxElems = 1U;
|
||||
aIs3D = true;
|
||||
break;
|
||||
default:
|
||||
/* Oh dear, we didn't match. Report an error. */
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aMinElems > 0, "Didn't update minimum elements!");
|
||||
NS_ASSERTION(aMaxElems > 0, "Didn't update maximum elements!");
|
||||
NS_ASSERTION(aMinElems <= aMaxElems, "aMinElems > aMaxElems!");
|
||||
NS_ASSERTION(variantIndex >= 0, "Invalid variant mask!");
|
||||
NS_ASSERTION(variantIndex < eNumVariantMasks, "Invalid variant mask!");
|
||||
#ifdef DEBUG
|
||||
NS_ASSERTION(aMaxElems <= kVariantMaskLengths[variantIndex],
|
||||
"Invalid aMaxElems for this variant mask.");
|
||||
#endif
|
||||
|
||||
// Convert the index into a mask.
|
||||
aVariantMask = kVariantMasks[variantIndex];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Reads a single transform function from the tokenizer stream, reporting an
|
||||
* error if something goes wrong.
|
||||
*/
|
||||
bool
|
||||
CSSParserImpl::ParseSingleTransform(bool aIsPrefixed,
|
||||
nsCSSValue& aValue, bool& aIs3D)
|
||||
{
|
||||
if (!GetToken(true))
|
||||
return false;
|
||||
|
||||
if (mToken.mType != eCSSToken_Function) {
|
||||
UngetToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32_t* variantMask;
|
||||
uint16_t minElems, maxElems;
|
||||
nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
|
||||
|
||||
if (!GetFunctionParseInformation(keyword, aIsPrefixed,
|
||||
minElems, maxElems, variantMask, aIs3D))
|
||||
return false;
|
||||
|
||||
// Bug 721136: Normalize the identifier to lowercase, except that things
|
||||
// like scaleX should have the last character capitalized. This matches
|
||||
// what other browsers do.
|
||||
nsContentUtils::ASCIIToLower(mToken.mIdent);
|
||||
switch (keyword) {
|
||||
case eCSSKeyword_rotatex:
|
||||
case eCSSKeyword_scalex:
|
||||
case eCSSKeyword_skewx:
|
||||
case eCSSKeyword_translatex:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('X'));
|
||||
break;
|
||||
|
||||
case eCSSKeyword_rotatey:
|
||||
case eCSSKeyword_scaley:
|
||||
case eCSSKeyword_skewy:
|
||||
case eCSSKeyword_translatey:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Y'));
|
||||
break;
|
||||
|
||||
case eCSSKeyword_rotatez:
|
||||
case eCSSKeyword_scalez:
|
||||
case eCSSKeyword_translatez:
|
||||
mToken.mIdent.Replace(mToken.mIdent.Length() - 1, 1, PRUnichar('Z'));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ParseFunction(mToken.mIdent, variantMask, minElems, maxElems, aValue);
|
||||
}
|
||||
|
||||
/* Parses a transform property list by continuously reading in properties
|
||||
* and constructing a matrix from it.
|
||||
*/
|
||||
bool CSSParserImpl::ParseTransform(bool aIsPrefixed)
|
||||
{
|
||||
nsCSSValue value;
|
||||
if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE, nullptr)) {
|
||||
// 'inherit', 'initial', and 'none' must be alone
|
||||
if (!ExpectEndProperty()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
nsCSSValueList* cur = value.SetListValue();
|
||||
for (;;) {
|
||||
bool is3D;
|
||||
if (!ParseSingleTransform(aIsPrefixed, cur->mValue, is3D)) {
|
||||
return false;
|
||||
}
|
||||
if (is3D && !nsLayoutUtils::Are3DTransformsEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (CheckEndProperty()) {
|
||||
break;
|
||||
}
|
||||
cur->mNext = new nsCSSValueList;
|
||||
cur = cur->mNext;
|
||||
}
|
||||
}
|
||||
AppendValue(eCSSProperty_transform, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSSParserImpl::ParseTransformOrigin(bool aPerspective)
|
||||
{
|
||||
nsCSSValuePair position;
|
||||
if (!ParseBoxPositionValues(position, true))
|
||||
return false;
|
||||
|
||||
nsCSSProperty prop = eCSSProperty_transform_origin;
|
||||
if (aPerspective) {
|
||||
if (!ExpectEndProperty()) {
|
||||
return false;
|
||||
}
|
||||
prop = eCSSProperty_perspective_origin;
|
||||
}
|
||||
|
||||
// Unlike many other uses of pairs, this position should always be stored
|
||||
// as a pair, even if the values are the same, so it always serializes as
|
||||
// a pair, and to keep the computation code simple.
|
||||
if (position.mXValue.GetUnit() == eCSSUnit_Inherit ||
|
||||
position.mXValue.GetUnit() == eCSSUnit_Initial) {
|
||||
NS_ABORT_IF_FALSE(position.mXValue == position.mYValue,
|
||||
"inherit/initial only half?");
|
||||
AppendValue(prop, position.mXValue);
|
||||
} else {
|
||||
nsCSSValue value;
|
||||
if (aPerspective) {
|
||||
value.SetPairValue(position.mXValue, position.mYValue);
|
||||
} else {
|
||||
nsCSSValue depth;
|
||||
if (!nsLayoutUtils::Are3DTransformsEnabled() ||
|
||||
// only try parsing if 3-D transforms are enabled
|
||||
!ParseVariant(depth, VARIANT_LENGTH | VARIANT_CALC, nullptr)) {
|
||||
depth.SetFloatValue(0.0f, eCSSUnit_Pixel);
|
||||
}
|
||||
value.SetTripletValue(position.mXValue, position.mYValue, depth);
|
||||
}
|
||||
|
||||
AppendValue(prop, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSParserImpl::ParseTransitionProperty()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user