From 7cdd855e3287492093749a833b8b56c67e8db800 Mon Sep 17 00:00:00 2001 From: "hmuller@adobe.com" Date: Fri, 27 Sep 2013 23:17:34 +0000 Subject: Crash on shape-outside when using calc() https://bugs.webkit.org/show_bug.cgi?id=121020 Reviewed by Dirk Schulze. Source/WebCore: This change prevents a crash caused by specifying a CSS Shape geometry Length attribute with a calc() expression. It adds support for converting Lengths to CSSPrimitive Values, in large part by migrating Blink changes made to the calc classes since the split. Doing so required a few supporting changes in some related classes, notably CSSPrimitiveValue. Tests: fast/shapes/shape-inside/shape-inside-calc-crash.html css3/calc/simplification.html * css/BasicShapeFunctions.cpp: (WebCore::convertToCSSPrimitiveValue): Effectively use the new CSSPrimtiveValue(length,style) constructor to convert Lengths to CSSValues. (WebCore::valueForBasicShape): Use the convertToCSSPrimitiveValue() function. (WebCore::convertToLength): Added the CalculatedConversion convertToLength() flag to enable support for calc() valued Length Shape attributes. * css/BasicShapeFunctions.h: * css/CSSCalculationValue.cpp: (WebCore::hasDoubleValue): (WebCore::buildCssText): (WebCore::CSSCalcValue::clampToPermittedRange): (WebCore::CSSCalcValue::doubleValue): (WebCore::CSSCalcExpressionNode::~CSSCalcExpressionNode): (WebCore::CSSCalcPrimitiveValue::create): (WebCore::CSSCalcPrimitiveValue::toCalcValue): (WebCore::CSSCalcPrimitiveValue::doubleValue): (WebCore::CSSCalcPrimitiveValue::computeLengthPx): (WebCore::CSSCalcPrimitiveValue::primitiveType): (WebCore::CSSCalcPrimitiveValue::CSSCalcPrimitiveValue): (WebCore::determineCategory): (WebCore::isIntegerResult): (WebCore::CSSCalcBinaryOperation::create): (WebCore::CSSCalcBinaryOperation::createSimplified): (WebCore::CSSCalcBinaryOperation::doubleValue): (WebCore::CSSCalcBinaryOperation::buildCssText): (WebCore::CSSCalcBinaryOperation::primitiveType): (WebCore::CSSCalcBinaryOperation::CSSCalcBinaryOperation): (WebCore::CSSCalcBinaryOperation::getNumberSide): (WebCore::CSSCalcBinaryOperation::evaluate): (WebCore::CSSCalcBinaryOperation::evaluateOperator): (WebCore::CSSCalcExpressionNodeParser::parseValue): (WebCore::CSSCalcExpressionNodeParser::parseValueTerm): (WebCore::CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression): (WebCore::CSSCalcExpressionNodeParser::parseAdditiveValueExpression): (WebCore::CSSCalcValue::createExpressionNode): (WebCore::CSSCalcValue::create): * css/CSSCalculationValue.h: (WebCore::CSSCalcExpressionNode::category): (WebCore::CSSCalcValue::create): (WebCore::CSSCalcValue::isInt): (WebCore::CSSCalcValue::permittedValueRange): (WebCore::CSSCalcValue::expressionNode): (WebCore::CSSCalcValue::CSSCalcValue): (WebCore::toCSSCalcValue): * css/CSSComputedStyleDeclaration.cpp: (WebCore::ComputedStyleExtractor::propertyValue): Pass the style along to the new valueForBasicShape() function. * css/CSSPrimitiveValue.cpp: (WebCore::CSSPrimitiveValue::unitCategory): Made this function public so that CSSCalculationValue could use it. (WebCore::CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor): Ditto. (WebCore::CSSPrimitiveValue::primitiveType): Cleared trailing whitespace. (WebCore::CSSPrimitiveValue::CSSPrimitiveValue): Construct a CSSPrimitiveValue from a Length and a RenderStyle*. (WebCore::CSSPrimitiveValue::init): The common part of the two Length CSSPrimitiveValue constructors. (WebCore::CSSPrimitiveValue::computeLengthDouble): Moved the case labels to the left per check-webkit-style. (WebCore::CSSPrimitiveValue::getStringValue): Ditto. (WebCore::CSSPrimitiveValue::getDoubleValue): Removed trailing whitespace. * css/CSSPrimitiveValue.h: (WebCore::CSSPrimitiveValue::create): Construct a CSSPrimitiveValue from a Length and a RenderStyle*. (WebCore::toCSSPrimitiveValue): Check the CSSValue*'s validity with ASSERT_WITH_SECURITY_IMPLICATION before casting to CSSPrimitiveValue*. * css/CSSValuePool.h: (WebCore::CSSValuePool::createValue): A new overload that delegates to the new CSSPrimitiveValue(length,style) constructor. * platform/CalculationValue.h: (WebCore::CalculationValue::operator==): (WebCore::CalculationValue::isNonNegative): (WebCore::CalculationValue::expression): (WebCore::CalcExpressionNumber::value): (WebCore::toCalcExpressionNumber): (WebCore::CalcExpressionLength::CalcExpressionLength): (WebCore::CalcExpressionLength::length): (WebCore::toCalcExpressionLength): (WebCore::CalcExpressionBinaryOperation::leftSide): (WebCore::CalcExpressionBinaryOperation::rightSide): (WebCore::CalcExpressionBinaryOperation::getOperator): (WebCore::toCalcExpressionBinaryOperation): (WebCore::CalcExpressionBlendLength::CalcExpressionBlendLength): (WebCore::CalcExpressionBlendLength::from): (WebCore::CalcExpressionBlendLength::to): (WebCore::CalcExpressionBlendLength::progress): (WebCore::toCalcExpressionBlendLength): LayoutTests: Specifying a CSS Shape geometry Length attribute with a calc() expression or looking up the value with getComputedStyle(), caused crashes. * fast/shapes/shape-inside/shape-inside-calc-crash-expected.txt: Added. * fast/shapes/shape-inside/shape-inside-calc-crash.html: Added. * css3/calc/simplification-expected.txt: Added * css3/calc/simplification.html: Added * LayoutTests/css3/calc/cssom-expected.txt: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@156586 268f45cc-cd09-0410-ab3c-d52691b4dbfc Change-Id: I38216be400bd7024999444d9c1c7e5ad79cce2de Reviewed-by: Allan Sandfeld Jensen --- Source/WebCore/css/BasicShapeFunctions.cpp | 44 +- Source/WebCore/css/BasicShapeFunctions.h | 2 +- Source/WebCore/css/CSSCalculationValue.cpp | 390 ++++++++++++++--- Source/WebCore/css/CSSCalculationValue.h | 58 ++- Source/WebCore/css/CSSComputedStyleDeclaration.cpp | 6 +- Source/WebCore/css/CSSPrimitiveValue.cpp | 467 +++++++++++---------- Source/WebCore/css/CSSPrimitiveValue.h | 27 +- Source/WebCore/css/CSSValuePool.h | 3 +- Source/WebCore/platform/CalculationValue.h | 98 +++-- 9 files changed, 741 insertions(+), 354 deletions(-) diff --git a/Source/WebCore/css/BasicShapeFunctions.cpp b/Source/WebCore/css/BasicShapeFunctions.cpp index c5885095e..a99739a78 100644 --- a/Source/WebCore/css/BasicShapeFunctions.cpp +++ b/Source/WebCore/css/BasicShapeFunctions.cpp @@ -38,7 +38,7 @@ namespace WebCore { -PassRefPtr valueForBasicShape(const BasicShape* basicShape) +PassRefPtr valueForBasicShape(const RenderStyle* style, const BasicShape* basicShape) { RefPtr basicShapeValue; switch (basicShape->type()) { @@ -46,12 +46,12 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) const BasicShapeRectangle* rectangle = static_cast(basicShape); RefPtr rectangleValue = CSSBasicShapeRectangle::create(); - rectangleValue->setX(cssValuePool().createValue(rectangle->x())); - rectangleValue->setY(cssValuePool().createValue(rectangle->y())); - rectangleValue->setWidth(cssValuePool().createValue(rectangle->width())); - rectangleValue->setHeight(cssValuePool().createValue(rectangle->height())); - rectangleValue->setRadiusX(cssValuePool().createValue(rectangle->cornerRadiusX())); - rectangleValue->setRadiusY(cssValuePool().createValue(rectangle->cornerRadiusY())); + rectangleValue->setX(cssValuePool().createValue(rectangle->x(), style)); + rectangleValue->setY(cssValuePool().createValue(rectangle->y(), style)); + rectangleValue->setWidth(cssValuePool().createValue(rectangle->width(), style)); + rectangleValue->setHeight(cssValuePool().createValue(rectangle->height(), style)); + rectangleValue->setRadiusX(cssValuePool().createValue(rectangle->cornerRadiusX(), style)); + rectangleValue->setRadiusY(cssValuePool().createValue(rectangle->cornerRadiusY(), style)); basicShapeValue = rectangleValue.release(); break; @@ -60,9 +60,9 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) const BasicShapeCircle* circle = static_cast(basicShape); RefPtr circleValue = CSSBasicShapeCircle::create(); - circleValue->setCenterX(cssValuePool().createValue(circle->centerX())); - circleValue->setCenterY(cssValuePool().createValue(circle->centerY())); - circleValue->setRadius(cssValuePool().createValue(circle->radius())); + circleValue->setCenterX(cssValuePool().createValue(circle->centerX(), style)); + circleValue->setCenterY(cssValuePool().createValue(circle->centerY(), style)); + circleValue->setRadius(cssValuePool().createValue(circle->radius(), style)); basicShapeValue = circleValue.release(); break; @@ -71,10 +71,10 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) const BasicShapeEllipse* ellipse = static_cast(basicShape); RefPtr ellipseValue = CSSBasicShapeEllipse::create(); - ellipseValue->setCenterX(cssValuePool().createValue(ellipse->centerX())); - ellipseValue->setCenterY(cssValuePool().createValue(ellipse->centerY())); - ellipseValue->setRadiusX(cssValuePool().createValue(ellipse->radiusX())); - ellipseValue->setRadiusY(cssValuePool().createValue(ellipse->radiusY())); + ellipseValue->setCenterX(cssValuePool().createValue(ellipse->centerX(), style)); + ellipseValue->setCenterY(cssValuePool().createValue(ellipse->centerY(), style)); + ellipseValue->setRadiusX(cssValuePool().createValue(ellipse->radiusX(), style)); + ellipseValue->setRadiusY(cssValuePool().createValue(ellipse->radiusY(), style)); basicShapeValue = ellipseValue.release(); break; @@ -86,7 +86,7 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) polygonValue->setWindRule(polygon->windRule()); const Vector& values = polygon->values(); for (unsigned i = 0; i < values.size(); i += 2) - polygonValue->appendPoint(cssValuePool().createValue(values.at(i)), cssValuePool().createValue(values.at(i + 1))); + polygonValue->appendPoint(cssValuePool().createValue(values.at(i), style), cssValuePool().createValue(values.at(i + 1), style)); basicShapeValue = polygonValue.release(); break; @@ -95,12 +95,12 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) const BasicShapeInsetRectangle* rectangle = static_cast(basicShape); RefPtr rectangleValue = CSSBasicShapeInsetRectangle::create(); - rectangleValue->setTop(cssValuePool().createValue(rectangle->top())); - rectangleValue->setRight(cssValuePool().createValue(rectangle->right())); - rectangleValue->setBottom(cssValuePool().createValue(rectangle->bottom())); - rectangleValue->setLeft(cssValuePool().createValue(rectangle->left())); - rectangleValue->setRadiusX(cssValuePool().createValue(rectangle->cornerRadiusX())); - rectangleValue->setRadiusY(cssValuePool().createValue(rectangle->cornerRadiusY())); + rectangleValue->setTop(cssValuePool().createValue(rectangle->top(), style)); + rectangleValue->setRight(cssValuePool().createValue(rectangle->right(), style)); + rectangleValue->setBottom(cssValuePool().createValue(rectangle->bottom(), style)); + rectangleValue->setLeft(cssValuePool().createValue(rectangle->left(), style)); + rectangleValue->setRadiusX(cssValuePool().createValue(rectangle->cornerRadiusX(), style)); + rectangleValue->setRadiusY(cssValuePool().createValue(rectangle->cornerRadiusY(), style)); basicShapeValue = rectangleValue.release(); break; @@ -113,7 +113,7 @@ PassRefPtr valueForBasicShape(const BasicShape* basicShape) static Length convertToLength(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value) { - return value->convertToLength(style, rootStyle, style->effectiveZoom()); + return value->convertToLength(style, rootStyle, style->effectiveZoom()); } PassRefPtr basicShapeForValue(const RenderStyle* style, const RenderStyle* rootStyle, const CSSBasicShape* basicShapeValue) diff --git a/Source/WebCore/css/BasicShapeFunctions.h b/Source/WebCore/css/BasicShapeFunctions.h index 9bbc7c762..ddf7659a2 100644 --- a/Source/WebCore/css/BasicShapeFunctions.h +++ b/Source/WebCore/css/BasicShapeFunctions.h @@ -39,7 +39,7 @@ class CSSBasicShape; class CSSValue; class RenderStyle; -PassRefPtr valueForBasicShape(const BasicShape*); +PassRefPtr valueForBasicShape(const RenderStyle*, const BasicShape*); PassRefPtr basicShapeForValue(const RenderStyle*, const RenderStyle* rootStyle, const CSSBasicShape*); } diff --git a/Source/WebCore/css/CSSCalculationValue.cpp b/Source/WebCore/css/CSSCalculationValue.cpp index dca177991..b42a520c2 100644 --- a/Source/WebCore/css/CSSCalculationValue.cpp +++ b/Source/WebCore/css/CSSCalculationValue.cpp @@ -31,10 +31,12 @@ #include "config.h" #include "CSSCalculationValue.h" +#include "CSSPrimitiveValueMappings.h" #include "CSSValueList.h" #include "Length.h" #include "StyleResolver.h" +#include #include #include #include @@ -77,6 +79,72 @@ static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) } } +static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) +{ + switch (type) { + case CSSPrimitiveValue::CSS_NUMBER: + case CSSPrimitiveValue::CSS_PARSER_INTEGER: + case CSSPrimitiveValue::CSS_PERCENTAGE: + case CSSPrimitiveValue::CSS_EMS: + case CSSPrimitiveValue::CSS_EXS: + case CSSPrimitiveValue::CSS_CHS: + case CSSPrimitiveValue::CSS_REMS: + case CSSPrimitiveValue::CSS_PX: + case CSSPrimitiveValue::CSS_CM: + case CSSPrimitiveValue::CSS_MM: + case CSSPrimitiveValue::CSS_IN: + case CSSPrimitiveValue::CSS_PT: + case CSSPrimitiveValue::CSS_PC: + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + case CSSPrimitiveValue::CSS_DIMENSION: + case CSSPrimitiveValue::CSS_VW: + case CSSPrimitiveValue::CSS_VH: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VMAX: + case CSSPrimitiveValue::CSS_DPPX: + case CSSPrimitiveValue::CSS_DPI: + case CSSPrimitiveValue::CSS_DPCM: + return true; + case CSSPrimitiveValue::CSS_UNKNOWN: + case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_URI: + case CSSPrimitiveValue::CSS_IDENT: + case CSSPrimitiveValue::CSS_ATTR: + case CSSPrimitiveValue::CSS_COUNTER: + case CSSPrimitiveValue::CSS_RECT: + case CSSPrimitiveValue::CSS_RGBCOLOR: + case CSSPrimitiveValue::CSS_PAIR: + case CSSPrimitiveValue::CSS_UNICODE_RANGE: + case CSSPrimitiveValue::CSS_PARSER_OPERATOR: + case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: + case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: + case CSSPrimitiveValue::CSS_TURN: + case CSSPrimitiveValue::CSS_COUNTER_NAME: + case CSSPrimitiveValue::CSS_SHAPE: + case CSSPrimitiveValue::CSS_QUAD: + case CSSPrimitiveValue::CSS_CALC: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: +#if ENABLE(CSS_VARIABLES) + case CSSPrimitiveValue::CSS_VARIABLE_NAME: +#endif + case CSSPrimitiveValue::CSS_PROPERTY_ID: + case CSSPrimitiveValue::CSS_VALUE_ID: +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPrimitiveValue::CSS_DASHBOARD_REGION: +#endif + return false; + }; + ASSERT_NOT_REACHED(); + return false; +} + static String buildCssText(const String& expression) { StringBuilder result; @@ -87,7 +155,7 @@ static String buildCssText(const String& expression) result.append(expression); if (expressionHasSingleTerm) result.append(')'); - return result.toString(); + return result.toString(); } String CSSCalcValue::customCssText() const @@ -115,10 +183,10 @@ bool CSSCalcValue::hasVariableReference() const double CSSCalcValue::clampToPermittedRange(double value) const { return m_nonNegative && value < 0 ? 0 : value; -} - -double CSSCalcValue::doubleValue() const -{ +} + +double CSSCalcValue::doubleValue() const +{ return clampToPermittedRange(m_expression->doubleValue()); } @@ -126,20 +194,27 @@ double CSSCalcValue::computeLengthPx(const RenderStyle* currentStyle, const Rend { return clampToPermittedRange(m_expression->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize)); } - -CSSCalcExpressionNode::~CSSCalcExpressionNode() + +CSSCalcExpressionNode::~CSSCalcExpressionNode() { } - + class CSSCalcPrimitiveValue : public CSSCalcExpressionNode { WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr create(CSSPrimitiveValue* value, bool isInteger) + static PassRefPtr create(PassRefPtr value, bool isInteger) { return adoptRef(new CSSCalcPrimitiveValue(value, isInteger)); } - + + static PassRefPtr create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger) + { + if (std::isnan(value) || std::isinf(value)) + return 0; + return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type).get(), isInteger)); + } + virtual bool isZero() const { return !m_value->getDoubleValue(); @@ -155,7 +230,7 @@ public: { return m_value->customSerializeResolvingVariables(variables); } - + virtual bool hasVariableReference() const { return m_value->isVariableName(); @@ -170,8 +245,12 @@ public: case CalcLength: return adoptPtr(new CalcExpressionNumber(m_value->computeLength(style, rootStyle, zoom))); case CalcPercent: - case CalcPercentLength: - return adoptPtr(new CalcExpressionLength(StyleResolver::convertToFloatLength(m_value.get(), style, rootStyle, zoom))); + case CalcPercentLength: { + CSSPrimitiveValue* primitiveValue = m_value.get(); + return adoptPtr(new CalcExpressionLength(primitiveValue + ? primitiveValue->convertToLength(style, rootStyle, zoom) + : Length(Undefined))); + } // Only types that could be part of a Length expression can be converted // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length. case CalcPercentNumber: @@ -186,23 +265,12 @@ public: virtual double doubleValue() const { - switch (m_category) { - case CalcNumber: - case CalcPercent: + if (hasDoubleValue(primitiveType())) return m_value->getDoubleValue(); - case CalcLength: - case CalcPercentLength: - case CalcPercentNumber: -#if ENABLE(CSS_VARIABLES) - case CalcVariable: -#endif - case CalcOther: - ASSERT_NOT_REACHED(); - break; - } + ASSERT_NOT_REACHED(); return 0; } - + virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const { switch (m_category) { @@ -220,7 +288,8 @@ public: ASSERT_NOT_REACHED(); break; } - return 0; + ASSERT_NOT_REACHED(); + return 0; } virtual bool equals(const CSSCalcExpressionNode& other) const @@ -232,9 +301,13 @@ public: } virtual Type type() const { return CssCalcPrimitiveValue; } - + virtual CSSPrimitiveValue::UnitTypes primitiveType() const + { + return CSSPrimitiveValue::UnitTypes(m_value->primitiveType()); + } + private: - explicit CSSCalcPrimitiveValue(CSSPrimitiveValue* value, bool isInteger) + explicit CSSCalcPrimitiveValue(PassRefPtr value, bool isInteger) : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger) , m_value(value) { @@ -244,12 +317,13 @@ private: }; static const CalculationCategory addSubtractResult[CalcOther][CalcOther] = { - { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, - { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, - { CalcPercentNumber, CalcPercentLength, CalcPercent, CalcPercentNumber, CalcPercentLength }, - { CalcPercentNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, - { CalcOther, CalcPercentLength, CalcPercentLength, CalcOther, CalcPercentLength }, -}; +// CalcNumber CalcLength CalcPercent CalcPercentNumber CalcPercentLength + { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcNumber + { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcLength + { CalcPercentNumber, CalcPercentLength, CalcPercent, CalcPercentNumber, CalcPercentLength }, // CalcPercent + { CalcPercentNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcPercentNumber + { CalcOther, CalcPercentLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcPercentLength +}; static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op) { @@ -266,10 +340,10 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi switch (op) { case CalcAdd: - case CalcSubtract: + case CalcSubtract: return addSubtractResult[leftCategory][rightCategory]; case CalcMultiply: - if (leftCategory != CalcNumber && rightCategory != CalcNumber) + if (leftCategory != CalcNumber && rightCategory != CalcNumber) return CalcOther; return leftCategory == CalcNumber ? rightCategory : leftCategory; case CalcDivide: @@ -277,18 +351,25 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi return CalcOther; return leftCategory; } - + ASSERT_NOT_REACHED(); return CalcOther; } +static bool isIntegerResult(const CSSCalcExpressionNode* leftSide, const CSSCalcExpressionNode* rightSide, CalcOperator op) +{ + // Performs W3C spec's type checking for calc integers. + // http://www.w3.org/TR/css3-values/#calc-type-checking + return op != CalcDivide && leftSide->isInteger() && rightSide->isInteger(); +} + class CSSCalcBinaryOperation : public CSSCalcExpressionNode { public: - static PassRefPtr create(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) + static PassRefPtr create(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) { ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther); - + CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op); if (newCategory == CalcOther) @@ -296,7 +377,64 @@ public: return adoptRef(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory)); } - + + static PassRefPtr createSimplified(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) + { + CalculationCategory leftCategory = leftSide->category(); + CalculationCategory rightCategory = rightSide->category(); + ASSERT(leftCategory != CalcOther && rightCategory != CalcOther); + + bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op); + + // Simplify numbers. + if (leftCategory == CalcNumber && rightCategory == CalcNumber) { + CSSPrimitiveValue::UnitTypes evaluationType = isInteger ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER; + return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), evaluationType, isInteger); + } + + // Simplify addition and subtraction between same types. + if (op == CalcAdd || op == CalcSubtract) { + if (leftCategory == rightSide->category()) { + CSSPrimitiveValue::UnitTypes leftType = leftSide->primitiveType(); + if (hasDoubleValue(leftType)) { + CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType(); + if (leftType == rightType) + return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger); + CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType); + if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) { + CSSPrimitiveValue::UnitTypes canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory); + if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) { + double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType); + double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType); + return CSSCalcPrimitiveValue::create(evaluateOperator(leftValue, rightValue, op), canonicalType, isInteger); + } + } + } + } + } else { + // Simplify multiplying or dividing by a number for simplifiable types. + ASSERT(op == CalcMultiply || op == CalcDivide); + CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get()); + if (!numberSide) + return create(leftSide, rightSide, op); + if (numberSide == leftSide && op == CalcDivide) + return 0; + CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get(); + + double number = numberSide->doubleValue(); + if (std::isnan(number) || std::isinf(number)) + return 0; + if (op == CalcDivide && !number) + return 0; + + CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType(); + if (hasDoubleValue(otherType)) + return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger); + } + + return create(leftSide, rightSide, op); + } + virtual bool isZero() const { return !doubleValue(); @@ -313,11 +451,11 @@ public: return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator)); } - virtual double doubleValue() const + virtual double doubleValue() const { return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue()); } - + virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const { const double leftValue = m_leftSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize); @@ -335,8 +473,8 @@ public: result.append(' '); result.append(rightExpression); result.append(')'); - - return result.toString(); + + return result.toString(); } virtual String customCssText() const @@ -369,18 +507,64 @@ public: virtual Type type() const { return CssCalcBinaryOperation; } + virtual CSSPrimitiveValue::UnitTypes primitiveType() const + { + switch (m_category) { + case CalcNumber: + ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber); + if (m_isInteger) + return CSSPrimitiveValue::CSS_PARSER_INTEGER; + return CSSPrimitiveValue::CSS_NUMBER; + case CalcLength: + case CalcPercent: { + if (m_leftSide->category() == CalcNumber) + return m_rightSide->primitiveType(); + if (m_rightSide->category() == CalcNumber) + return m_leftSide->primitiveType(); + CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType(); + if (leftType == m_rightSide->primitiveType()) + return leftType; + return CSSPrimitiveValue::CSS_UNKNOWN; + } +#if ENABLE(CSS_VARIABLES) + case CalcVariable: + return CSSPrimitiveValue::CSS_VARIABLE_NAME; +#endif + case CalcPercentLength: + case CalcPercentNumber: + case CalcOther: + return CSSPrimitiveValue::CSS_UNKNOWN; + } + ASSERT_NOT_REACHED(); + return CSSPrimitiveValue::CSS_UNKNOWN; + } + private: CSSCalcBinaryOperation(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op, CalculationCategory category) - : CSSCalcExpressionNode(category, leftSide->isInteger() && rightSide->isInteger()) + : CSSCalcExpressionNode(category, isIntegerResult(leftSide.get(), rightSide.get(), op)) , m_leftSide(leftSide) , m_rightSide(rightSide) , m_operator(op) { } - - double evaluate(double leftValue, double rightValue) const + + static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode* leftSide, CSSCalcExpressionNode* rightSide) + { + if (leftSide->category() == CalcNumber) + return leftSide; + if (rightSide->category() == CalcNumber) + return rightSide; + return 0; + } + + double evaluate(double leftSide, double rightSide) const + { + return evaluateOperator(leftSide, rightSide, m_operator); + } + + static double evaluateOperator(double leftValue, double rightValue, CalcOperator op) { - switch (m_operator) { + switch (op) { case CalcAdd: return leftValue + rightValue; case CalcSubtract: @@ -394,7 +578,7 @@ private: } return 0; } - + const RefPtr m_leftSide; const RefPtr m_rightSide; const CalcOperator m_operator; @@ -449,7 +633,7 @@ private: if (!value || !value->isPrimitiveValue()) return false; - CSSPrimitiveValue* primitiveValue = static_cast(value.get()); + CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get()); result->value = CSSCalcPrimitiveValue::create(primitiveValue, parserValue->isInt); ++*index; @@ -459,8 +643,8 @@ private: bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; - + return false; + if (operatorValue(tokens, *index) == '(') { unsigned currentIndex = *index + 1; if (!parseValueExpression(tokens, depth, ¤tIndex, result)) @@ -478,7 +662,7 @@ private: bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; + return false; if (!parseValueTerm(tokens, depth, index, result)) return false; @@ -493,7 +677,7 @@ private: if (!parseValueTerm(tokens, depth, index, &rhs)) return false; - result->value = CSSCalcBinaryOperation::create(result->value, rhs.value, static_cast(operatorCharacter)); + result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast(operatorCharacter)); if (!result->value) return false; } @@ -505,7 +689,7 @@ private: bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; + return false; if (!parseValueMultiplicativeExpression(tokens, depth, index, result)) return false; @@ -520,7 +704,7 @@ private: if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs)) return false; - result->value = CSSCalcBinaryOperation::create(result->value, rhs.value, static_cast(operatorCharacter)); + result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast(operatorCharacter)); if (!result->value) return false; } @@ -535,16 +719,96 @@ private: } }; +PassRefPtr CSSCalcValue::createExpressionNode(PassRefPtr value, bool isInteger) +{ + return CSSCalcPrimitiveValue::create(value, isInteger); +} + +PassRefPtr CSSCalcValue::createExpressionNode(PassRefPtr leftSide, PassRefPtr rightSide, CalcOperator op) +{ + return CSSCalcBinaryOperation::create(leftSide, rightSide, op); +} + +PassRefPtr CSSCalcValue::createExpressionNode(const CalcExpressionNode* node, const RenderStyle* style) +{ + switch (node->type()) { + case CalcExpressionNodeNumber: { + float value = toCalcExpressionNumber(node)->value(); + return createExpressionNode(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == trunc(value)); + } + case CalcExpressionNodeLength: + return createExpressionNode(toCalcExpressionLength(node)->length(), style); + case CalcExpressionNodeBinaryOperation: { + const CalcExpressionBinaryOperation* binaryNode = toCalcExpressionBinaryOperation(node); + return createExpressionNode(createExpressionNode(binaryNode->leftSide(), style), createExpressionNode(binaryNode->rightSide(), style), binaryNode->getOperator()); + } + case CalcExpressionNodeBlendLength: { + // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength. + const CalcExpressionBlendLength* blendNode = toCalcExpressionBlendLength(node); + const double progress = blendNode->progress(); + const bool isInteger = !progress || (progress == 1); + return createExpressionNode( + createExpressionNode( + createExpressionNode(blendNode->from(), style), + createExpressionNode(CSSPrimitiveValue::create(1 - progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), + CalcMultiply), + createExpressionNode( + createExpressionNode(blendNode->to(), style), + createExpressionNode(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), + CalcMultiply), + CalcAdd); + } + case CalcExpressionNodeUndefined: + ASSERT_NOT_REACHED(); + return 0; + } + ASSERT_NOT_REACHED(); + return 0; +} + +PassRefPtr CSSCalcValue::createExpressionNode(const Length& length, const RenderStyle* style) +{ + switch (length.type()) { + case Percent: + case ViewportPercentageWidth: + case ViewportPercentageHeight: + case ViewportPercentageMin: + case ViewportPercentageMax: + case Fixed: + return createExpressionNode(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); + case Calculated: + return createExpressionNode(length.calculationValue()->expression(), style); + case Auto: + case Intrinsic: + case MinIntrinsic: + case MinContent: + case MaxContent: + case FillAvailable: + case FitContent: + case Relative: + case Undefined: + ASSERT_NOT_REACHED(); + return 0; + } + ASSERT_NOT_REACHED(); + return 0; +} + PassRefPtr CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range) -{ - CSSCalcExpressionNodeParser parser; +{ + CSSCalcExpressionNodeParser parser; RefPtr expression; - + if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc(")) - expression = parser.parseCalc(parserValueList); - // FIXME calc (http://webkit.org/b/16662) Add parsing for min and max here + expression = parser.parseCalc(parserValueList); + // FIXME: calc (http://webkit.org/b/16662) Add parsing for min and max here return expression ? adoptRef(new CSSCalcValue(expression, range)) : 0; } +PassRefPtr CSSCalcValue::create(PassRefPtr expression, CalculationPermittedValueRange range) +{ + return adoptRef(new CSSCalcValue(expression, range)); +} + } // namespace WebCore diff --git a/Source/WebCore/css/CSSCalculationValue.h b/Source/WebCore/css/CSSCalculationValue.h index 266e8f76c..13a17a3b7 100644 --- a/Source/WebCore/css/CSSCalculationValue.h +++ b/Source/WebCore/css/CSSCalculationValue.h @@ -32,6 +32,7 @@ #define CSSCalculationValue_h #include "CSSParserValues.h" +#include "CSSPrimitiveValue.h" #include "CSSValue.h" #include "CalculationValue.h" #include @@ -42,9 +43,10 @@ namespace WebCore { class CSSParserValueList; class CSSValueList; -class RenderStyle; class CalculationValue; class CalcExpressionNode; +class RenderStyle; +struct Length; enum CalculationCategory { CalcNumber = 0, @@ -57,7 +59,7 @@ enum CalculationCategory { #endif CalcOther }; - + class CSSCalcExpressionNode : public RefCounted { public: enum Type { @@ -67,7 +69,7 @@ public: virtual ~CSSCalcExpressionNode() = 0; virtual bool isZero() const = 0; - virtual PassOwnPtr toCalcValue(const RenderStyle*, const RenderStyle* rootStyle, double zoom = 1.0) const = 0; + virtual PassOwnPtr toCalcValue(const RenderStyle*, const RenderStyle* rootStyle, double zoom = 1.0) const = 0; virtual double doubleValue() const = 0; virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const = 0; virtual String customCssText() const = 0; @@ -78,56 +80,84 @@ public: virtual bool equals(const CSSCalcExpressionNode& other) const { return m_category == other.m_category && m_isInteger == other.m_isInteger; } virtual Type type() const = 0; - CalculationCategory category() const { return m_category; } + CalculationCategory category() const { return m_category; } + virtual CSSPrimitiveValue::UnitTypes primitiveType() const = 0; bool isInteger() const { return m_isInteger; } - + protected: CSSCalcExpressionNode(CalculationCategory category, bool isInteger) : m_category(category) , m_isInteger(isInteger) { } - + CalculationCategory m_category; bool m_isInteger; }; - + class CSSCalcValue : public CSSValue { public: static PassRefPtr create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange); - static PassRefPtr create(CalculationValue*); + static PassRefPtr create(PassRefPtr, CalculationPermittedValueRange = CalculationRangeAll); + static PassRefPtr create(const CalculationValue* value, const RenderStyle* style) { return adoptRef(new CSSCalcValue(value, style)); } + + static PassRefPtr createExpressionNode(PassRefPtr, bool isInteger = false); + static PassRefPtr createExpressionNode(PassRefPtr, PassRefPtr, CalcOperator); + static PassRefPtr createExpressionNode(const CalcExpressionNode*, const RenderStyle*); + static PassRefPtr createExpressionNode(const Length&, const RenderStyle*); PassRefPtr toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom = 1.0) const { return CalculationValue::create(m_expression->toCalcValue(style, rootStyle, zoom), m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll); } CalculationCategory category() const { return m_expression->category(); } - bool isInt() const { return m_expression->isInteger(); } + bool isInt() const { return m_expression->isInteger(); } double doubleValue() const; bool isNegative() const { return m_expression->doubleValue() < 0; } + CalculationPermittedValueRange permittedValueRange() { return m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll; } double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const; - + + CSSCalcExpressionNode* expressionNode() const { return m_expression.get(); } + String customCssText() const; bool equals(const CSSCalcValue&) const; #if ENABLE(CSS_VARIABLES) String customSerializeResolvingVariables(const HashMap&) const; bool hasVariableReference() const; #endif - -private: + +private: CSSCalcValue(PassRefPtr expression, CalculationPermittedValueRange range) : CSSValue(CalculationClass) , m_expression(expression) , m_nonNegative(range == CalculationRangeNonNegative) { } - + CSSCalcValue(const CalculationValue* value, const RenderStyle* style) + : CSSValue(CalculationClass) + , m_expression(createExpressionNode(value->expression(), style)) + , m_nonNegative(value->isNonNegative()) + { + } + double clampToPermittedRange(double) const; const RefPtr m_expression; const bool m_nonNegative; }; - + +inline CSSCalcValue* toCSSCalcValue(CSSValue* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isCalculationValue()); + return static_cast(value); +} + +inline const CSSCalcValue* toCSSCalcValue(const CSSValue* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isCalculationValue()); + return static_cast(value); +} + } // namespace WebCore #endif // CSSCalculationValue_h diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp index f645ace2c..621cdf038 100644 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp @@ -2707,7 +2707,7 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert case CSSPropertyWebkitClipPath: if (ClipPathOperation* operation = style->clipPath()) { if (operation->getOperationType() == ClipPathOperation::SHAPE) - return valueForBasicShape(static_cast(operation)->basicShape()); + return valueForBasicShape(style.get(), static_cast(operation)->basicShape()); #if ENABLE(SVG) else if (operation->getOperationType() == ClipPathOperation::REFERENCE) { ReferenceClipPathOperation* referenceOperation = static_cast(operation); @@ -2750,7 +2750,7 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert return cssValuePool().createIdentifierValue(CSSValueNone); } ASSERT(style->shapeInside()->type() == ShapeValue::Shape); - return valueForBasicShape(style->shapeInside()->shape()); + return valueForBasicShape(style.get(), style->shapeInside()->shape()); case CSSPropertyWebkitShapeOutside: if (!style->shapeOutside()) return cssValuePool().createIdentifierValue(CSSValueAuto); @@ -2760,7 +2760,7 @@ PassRefPtr ComputedStyleExtractor::propertyValue(CSSPropertyID propert return cssValuePool().createIdentifierValue(CSSValueNone); } ASSERT(style->shapeOutside()->type() == ShapeValue::Shape); - return valueForBasicShape(style->shapeOutside()->shape()); + return valueForBasicShape(style.get(), style->shapeOutside()->shape()); #endif #if ENABLE(CSS_FILTERS) case CSSPropertyWebkitFilter: diff --git a/Source/WebCore/css/CSSPrimitiveValue.cpp b/Source/WebCore/css/CSSPrimitiveValue.cpp index d0c852465..bd544aab5 100644 --- a/Source/WebCore/css/CSSPrimitiveValue.cpp +++ b/Source/WebCore/css/CSSPrimitiveValue.cpp @@ -52,7 +52,7 @@ using namespace WTF; namespace WebCore { - + // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing. // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max. const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2; @@ -132,46 +132,46 @@ static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::Unit return false; } -static CSSPrimitiveValue::UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes type) +CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitTypes type) { // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment). switch (type) { - case CSSPrimitiveValue::CSS_NUMBER: - return CSSPrimitiveValue::UNumber; - case CSSPrimitiveValue::CSS_PERCENTAGE: - return CSSPrimitiveValue::UPercent; - case CSSPrimitiveValue::CSS_PX: - case CSSPrimitiveValue::CSS_CM: - case CSSPrimitiveValue::CSS_MM: - case CSSPrimitiveValue::CSS_IN: - case CSSPrimitiveValue::CSS_PT: - case CSSPrimitiveValue::CSS_PC: - return CSSPrimitiveValue::ULength; - case CSSPrimitiveValue::CSS_MS: - case CSSPrimitiveValue::CSS_S: - return CSSPrimitiveValue::UTime; - case CSSPrimitiveValue::CSS_DEG: - case CSSPrimitiveValue::CSS_RAD: - case CSSPrimitiveValue::CSS_GRAD: - case CSSPrimitiveValue::CSS_TURN: - return CSSPrimitiveValue::UAngle; - case CSSPrimitiveValue::CSS_HZ: - case CSSPrimitiveValue::CSS_KHZ: - return CSSPrimitiveValue::UFrequency; - case CSSPrimitiveValue::CSS_VW: - case CSSPrimitiveValue::CSS_VH: - case CSSPrimitiveValue::CSS_VMIN: - case CSSPrimitiveValue::CSS_VMAX: - return CSSPrimitiveValue::UViewportPercentageLength; + case CSS_NUMBER: + return UNumber; + case CSS_PERCENTAGE: + return UPercent; + case CSS_PX: + case CSS_CM: + case CSS_MM: + case CSS_IN: + case CSS_PT: + case CSS_PC: + return ULength; + case CSS_MS: + case CSS_S: + return UTime; + case CSS_DEG: + case CSS_RAD: + case CSS_GRAD: + case CSS_TURN: + return UAngle; + case CSS_HZ: + case CSS_KHZ: + return UFrequency; + case CSS_VW: + case CSS_VH: + case CSS_VMIN: + case CSS_VMAX: + return UViewportPercentageLength; #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY) - case CSSPrimitiveValue::CSS_DPPX: - case CSSPrimitiveValue::CSS_DPI: - case CSSPrimitiveValue::CSS_DPCM: - return CSSPrimitiveValue::UResolution; + case CSS_DPPX: + case CSS_DPI: + case CSS_DPCM: + return UResolution; #endif default: - return CSSPrimitiveValue::UOther; + return UOther; } } @@ -182,14 +182,14 @@ static CSSTextCache& cssTextCache() return cache; } -unsigned short CSSPrimitiveValue::primitiveType() const +unsigned short CSSPrimitiveValue::primitiveType() const { if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID) return CSS_IDENT; if (m_primitiveUnitType != CSSPrimitiveValue::CSS_CALC) - return m_primitiveUnitType; - + return m_primitiveUnitType; + switch (m_value.calc->category()) { case CalcNumber: return CSSPrimitiveValue::CSS_NUMBER; @@ -284,66 +284,103 @@ CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) : CSSValue(PrimitiveClass) +{ + init(length); +} + +CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle* style) + : CSSValue(PrimitiveClass) { switch (length.type()) { - case Auto: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueAuto; - break; - case WebCore::Fixed: - m_primitiveUnitType = CSS_PX; - m_value.num = length.value(); - break; - case Intrinsic: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueIntrinsic; - break; - case MinIntrinsic: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueMinIntrinsic; - break; - case MinContent: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueWebkitMinContent; - break; - case MaxContent: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueWebkitMaxContent; - break; - case FillAvailable: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueWebkitFillAvailable; - break; - case FitContent: - m_primitiveUnitType = CSS_VALUE_ID; - m_value.valueID = CSSValueWebkitFitContent; - break; - case Percent: - m_primitiveUnitType = CSS_PERCENTAGE; - ASSERT(std::isfinite(length.percent())); - m_value.num = length.percent(); - break; - case ViewportPercentageWidth: - m_primitiveUnitType = CSS_VW; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageHeight: - m_primitiveUnitType = CSS_VH; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageMin: - m_primitiveUnitType = CSS_VMIN; - m_value.num = length.viewportPercentageLength(); - break; - case ViewportPercentageMax: - m_primitiveUnitType = CSS_VMAX; - m_value.num = length.viewportPercentageLength(); - break; - case Calculated: - case Relative: - case Undefined: - ASSERT_NOT_REACHED(); - break; + case Auto: + case Intrinsic: + case MinIntrinsic: + case MinContent: + case MaxContent: + case FillAvailable: + case FitContent: + case Percent: + case ViewportPercentageWidth: + case ViewportPercentageHeight: + case ViewportPercentageMin: + case ViewportPercentageMax: + init(length); + return; + case Fixed: + m_primitiveUnitType = CSS_PX; + m_value.num = adjustFloatForAbsoluteZoom(length.value(), style); + return; + case Calculated: + init(CSSCalcValue::create(length.calculationValue().get(), style)); + return; + case Relative: + case Undefined: + ASSERT_NOT_REACHED(); + break; + } +} + +void CSSPrimitiveValue::init(const Length& length) +{ + switch (length.type()) { + case Auto: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueAuto; + break; + case WebCore::Fixed: + m_primitiveUnitType = CSS_PX; + m_value.num = length.value(); + break; + case Intrinsic: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueIntrinsic; + break; + case MinIntrinsic: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueMinIntrinsic; + break; + case MinContent: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueWebkitMinContent; + break; + case MaxContent: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueWebkitMaxContent; + break; + case FillAvailable: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueWebkitFillAvailable; + break; + case FitContent: + m_primitiveUnitType = CSS_VALUE_ID; + m_value.valueID = CSSValueWebkitFitContent; + break; + case Percent: + m_primitiveUnitType = CSS_PERCENTAGE; + ASSERT(std::isfinite(length.percent())); + m_value.num = length.percent(); + break; + case ViewportPercentageWidth: + m_primitiveUnitType = CSS_VW; + m_value.num = length.viewportPercentageLength(); + break; + case ViewportPercentageHeight: + m_primitiveUnitType = CSS_VH; + m_value.num = length.viewportPercentageLength(); + break; + case ViewportPercentageMin: + m_primitiveUnitType = CSS_VMIN; + m_value.num = length.viewportPercentageLength(); + break; + case ViewportPercentageMax: + m_primitiveUnitType = CSS_VMAX; + m_value.num = length.viewportPercentageLength(); + break; + case Calculated: + case Relative: + case Undefined: + ASSERT_NOT_REACHED(); + break; } } @@ -552,63 +589,63 @@ double CSSPrimitiveValue::computeLengthDouble(const RenderStyle* style, const Re if (m_primitiveUnitType == CSS_CALC) // The multiplier and factor is applied to each value in the calc expression individually return m_value.calc->computeLengthPx(style, rootStyle, multiplier, computingFontSize); - + double factor; switch (primitiveType()) { - case CSS_EMS: - factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); - break; - case CSS_EXS: - // FIXME: We have a bug right now where the zoom will be applied twice to EX units. - // We really need to compute EX using fontMetrics for the original specifiedSize and not use - // our actual constructed rendering font. - if (style->fontMetrics().hasXHeight()) - factor = style->fontMetrics().xHeight(); - else - factor = (computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize()) / 2.0; - break; - case CSS_REMS: - if (rootStyle) - factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); - else - factor = 1.0; - break; - case CSS_CHS: - factor = style->fontMetrics().zeroWidth(); - break; - case CSS_PX: - factor = 1.0; - break; - case CSS_CM: - factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) - break; - case CSS_MM: - factor = cssPixelsPerInch / 25.4; - break; - case CSS_IN: - factor = cssPixelsPerInch; - break; - case CSS_PT: - factor = cssPixelsPerInch / 72.0; - break; - case CSS_PC: - // 1 pc == 12 pt - factor = cssPixelsPerInch * 12.0 / 72.0; - break; - case CSS_CALC_PERCENTAGE_WITH_LENGTH: - case CSS_CALC_PERCENTAGE_WITH_NUMBER: - ASSERT_NOT_REACHED(); - return -1.0; - case CSS_VH: - case CSS_VW: - case CSS_VMAX: - case CSS_VMIN: + case CSS_EMS: + factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); + break; + case CSS_EXS: + // FIXME: We have a bug right now where the zoom will be applied twice to EX units. + // We really need to compute EX using fontMetrics for the original specifiedSize and not use + // our actual constructed rendering font. + if (style->fontMetrics().hasXHeight()) + factor = style->fontMetrics().xHeight(); + else + factor = (computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize()) / 2.0; + break; + case CSS_REMS: + if (rootStyle) + factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); + else factor = 1.0; - break; - default: - ASSERT_NOT_REACHED(); - return -1.0; + break; + case CSS_CHS: + factor = style->fontMetrics().zeroWidth(); + break; + case CSS_PX: + factor = 1.0; + break; + case CSS_CM: + factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) + break; + case CSS_MM: + factor = cssPixelsPerInch / 25.4; + break; + case CSS_IN: + factor = cssPixelsPerInch; + break; + case CSS_PT: + factor = cssPixelsPerInch / 72.0; + break; + case CSS_PC: + // 1 pc == 12 pt + factor = cssPixelsPerInch * 12.0 / 72.0; + break; + case CSS_CALC_PERCENTAGE_WITH_LENGTH: + case CSS_CALC_PERCENTAGE_WITH_NUMBER: + ASSERT_NOT_REACHED(); + return -1.0; + case CSS_VH: + case CSS_VW: + case CSS_VMAX: + case CSS_VMIN: + factor = 1.0; + break; + default: + ASSERT_NOT_REACHED(); + return -1.0; } // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming @@ -629,53 +666,53 @@ void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec) ec = NO_MODIFICATION_ALLOWED_ERR; } -static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType) +double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(unsigned short unitType) { double factor = 1.0; // FIXME: the switch can be replaced by an array of scale factors. switch (unitType) { - // These are "canonical" units in their respective categories. - case CSSPrimitiveValue::CSS_PX: - case CSSPrimitiveValue::CSS_DEG: - case CSSPrimitiveValue::CSS_MS: - case CSSPrimitiveValue::CSS_HZ: - break; - case CSSPrimitiveValue::CSS_CM: - factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) - break; - case CSSPrimitiveValue::CSS_DPCM: - factor = 2.54 / cssPixelsPerInch; // (2.54 cm/in) - break; - case CSSPrimitiveValue::CSS_MM: - factor = cssPixelsPerInch / 25.4; - break; - case CSSPrimitiveValue::CSS_IN: - factor = cssPixelsPerInch; - break; - case CSSPrimitiveValue::CSS_DPI: - factor = 1 / cssPixelsPerInch; - break; - case CSSPrimitiveValue::CSS_PT: - factor = cssPixelsPerInch / 72.0; - break; - case CSSPrimitiveValue::CSS_PC: - factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt - break; - case CSSPrimitiveValue::CSS_RAD: - factor = 180 / piDouble; - break; - case CSSPrimitiveValue::CSS_GRAD: - factor = 0.9; - break; - case CSSPrimitiveValue::CSS_TURN: - factor = 360; - break; - case CSSPrimitiveValue::CSS_S: - case CSSPrimitiveValue::CSS_KHZ: - factor = 1000; - break; - default: - break; + // These are "canonical" units in their respective categories. + case CSS_PX: + case CSS_DEG: + case CSS_MS: + case CSS_HZ: + break; + case CSS_CM: + factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) + break; + case CSS_DPCM: + factor = 2.54 / cssPixelsPerInch; // (2.54 cm/in) + break; + case CSS_MM: + factor = cssPixelsPerInch / 25.4; + break; + case CSS_IN: + factor = cssPixelsPerInch; + break; + case CSS_DPI: + factor = 1 / cssPixelsPerInch; + break; + case CSS_PT: + factor = cssPixelsPerInch / 72.0; + break; + case CSS_PC: + factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt + break; + case CSS_RAD: + factor = 180 / piDouble; + break; + case CSS_GRAD: + factor = 0.9; + break; + case CSS_TURN: + factor = 360; + break; + case CSS_S: + case CSS_KHZ: + factor = 1000; + break; + default: + break; } return factor; @@ -702,7 +739,7 @@ double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const } double CSSPrimitiveValue::getDoubleValue() const -{ +{ return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue(); } @@ -796,20 +833,20 @@ String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const { ec = 0; switch (m_primitiveUnitType) { - case CSS_STRING: - case CSS_ATTR: - case CSS_URI: + case CSS_STRING: + case CSS_ATTR: + case CSS_URI: #if ENABLE(CSS_VARIABLES) - case CSS_VARIABLE_NAME: + case CSS_VARIABLE_NAME: #endif - return m_value.string; - case CSS_VALUE_ID: - return valueName(m_value.valueID); - case CSS_PROPERTY_ID: - return propertyName(m_value.propertyID); - default: - ec = INVALID_ACCESS_ERR; - break; + return m_value.string; + case CSS_VALUE_ID: + return valueName(m_value.valueID); + case CSS_PROPERTY_ID: + return propertyName(m_value.propertyID); + default: + ec = INVALID_ACCESS_ERR; + break; } return String(); @@ -818,19 +855,19 @@ String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const String CSSPrimitiveValue::getStringValue() const { switch (m_primitiveUnitType) { - case CSS_STRING: - case CSS_ATTR: - case CSS_URI: + case CSS_STRING: + case CSS_ATTR: + case CSS_URI: #if ENABLE(CSS_VARIABLES) - case CSS_VARIABLE_NAME: + case CSS_VARIABLE_NAME: #endif - return m_value.string; - case CSS_VALUE_ID: - return valueName(m_value.valueID); - case CSS_PROPERTY_ID: - return propertyName(m_value.propertyID); - default: - break; + return m_value.string; + case CSS_VALUE_ID: + return valueName(m_value.valueID); + case CSS_PROPERTY_ID: + return propertyName(m_value.propertyID); + default: + break; } return String(); diff --git a/Source/WebCore/css/CSSPrimitiveValue.h b/Source/WebCore/css/CSSPrimitiveValue.h index 6bf437ac5..9ccb1eeb3 100644 --- a/Source/WebCore/css/CSSPrimitiveValue.h +++ b/Source/WebCore/css/CSSPrimitiveValue.h @@ -154,6 +154,7 @@ public: #endif UOther }; + static UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes); bool isAngle() const { @@ -207,7 +208,7 @@ public: bool isViewportPercentageMax() const { return m_primitiveUnitType == CSS_VMAX; } bool isViewportPercentageMin() const { return m_primitiveUnitType == CSS_VMIN; } bool isValueID() const { return m_primitiveUnitType == CSS_VALUE_ID; } - + static PassRefPtr createIdentifier(CSSValueID valueID) { return adoptRef(new CSSPrimitiveValue(valueID)); } static PassRefPtr createIdentifier(CSSPropertyID propertyID) { return adoptRef(new CSSPrimitiveValue(propertyID)); } static PassRefPtr createParserOperator(int parserOperator) { return adoptRef(new CSSPrimitiveValue(parserOperator)); } @@ -215,6 +216,7 @@ public: static PassRefPtr createColor(unsigned rgbValue) { return adoptRef(new CSSPrimitiveValue(rgbValue)); } static PassRefPtr create(double value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); } static PassRefPtr create(const String& value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); } + static PassRefPtr create(const Length& value, const RenderStyle* style) { return adoptRef(new CSSPrimitiveValue(value, style)); } template static PassRefPtr create(T value) { @@ -314,7 +316,7 @@ public: #endif CSSBasicShape* getShapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? 0 : m_value.shape; } - + CSSCalcValue* cssCalcValue() const { return m_primitiveUnitType != CSS_CALC ? 0 : m_value.calc; } CSSPropertyID getPropertyID() const { return m_primitiveUnitType == CSS_PROPERTY_ID ? m_value.propertyID : CSSPropertyInvalid; } @@ -333,12 +335,15 @@ public: void addSubresourceStyleURLs(ListHashSet&, const StyleSheetContents*) const; Length viewportPercentageLength() const; - + PassRefPtr cloneForCSSOM() const; void setCSSOMSafe() { m_isCSSOMSafe = true; } bool equals(const CSSPrimitiveValue&) const; + static UnitTypes canonicalUnitTypeForCategory(UnitCategory); + static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType); + private: CSSPrimitiveValue(CSSValueID); CSSPrimitiveValue(CSSPropertyID); @@ -346,6 +351,7 @@ private: CSSPrimitiveValue(int parserOperator); CSSPrimitiveValue(unsigned color); // RGB value CSSPrimitiveValue(const Length&); + CSSPrimitiveValue(const Length&, const RenderStyle*); CSSPrimitiveValue(const String&, UnitTypes); CSSPrimitiveValue(double, UnitTypes); @@ -366,8 +372,7 @@ private: static void create(unsigned); // compile-time guard template operator T*(); // compile-time guard - static UnitTypes canonicalUnitTypeForCategory(UnitCategory category); - + void init(const Length&); void init(PassRefPtr); void init(PassRefPtr); void init(PassRefPtr); @@ -396,6 +401,18 @@ private: } m_value; }; +inline CSSPrimitiveValue* toCSSPrimitiveValue(CSSValue* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isPrimitiveValue()); + return static_cast(value); +} + +inline const CSSPrimitiveValue* toCSSPrimitiveValue(const CSSValue* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isPrimitiveValue()); + return static_cast(value); +} + } // namespace WebCore #endif // CSSPrimitiveValue_h diff --git a/Source/WebCore/css/CSSValuePool.h b/Source/WebCore/css/CSSValuePool.h index 421d74d6e..e2ceb6e4c 100644 --- a/Source/WebCore/css/CSSValuePool.h +++ b/Source/WebCore/css/CSSValuePool.h @@ -31,9 +31,9 @@ #include "CSSPrimitiveValue.h" #include "CSSPropertyNames.h" #include "CSSValueKeywords.h" -#include #include #include +#include namespace WebCore { @@ -52,6 +52,7 @@ public: PassRefPtr createColorValue(unsigned rgbValue); PassRefPtr createValue(double value, CSSPrimitiveValue::UnitTypes); PassRefPtr createValue(const String& value, CSSPrimitiveValue::UnitTypes type) { return CSSPrimitiveValue::create(value, type); } + PassRefPtr createValue(const Length& value, const RenderStyle* style) { return CSSPrimitiveValue::create(value, style); } template static PassRefPtr createValue(T value) { return CSSPrimitiveValue::create(value); } void drain(); diff --git a/Source/WebCore/platform/CalculationValue.h b/Source/WebCore/platform/CalculationValue.h index 72543ff60..3dcbf1b78 100644 --- a/Source/WebCore/platform/CalculationValue.h +++ b/Source/WebCore/platform/CalculationValue.h @@ -59,7 +59,7 @@ enum CalcExpressionNodeType { CalcExpressionNodeBinaryOperation, CalcExpressionNodeBlendLength, }; - + class CalcExpressionNode { WTF_MAKE_FAST_ALLOCATED; public: @@ -67,37 +67,40 @@ public: : m_type(CalcExpressionNodeUndefined) { } - + virtual ~CalcExpressionNode() { } - + virtual float evaluate(float maxValue) const = 0; virtual bool operator==(const CalcExpressionNode&) const = 0; CalcExpressionNodeType type() const { return m_type; } - + protected: CalcExpressionNodeType m_type; }; - + class CalculationValue : public RefCounted { public: static PassRefPtr create(PassOwnPtr value, CalculationPermittedValueRange); float evaluate(float maxValue) const; - bool operator==(const CalculationValue& o) const - { + bool operator==(const CalculationValue& o) const + { return *(m_value.get()) == *(o.m_value.get()); } - + + bool isNonNegative() const { return m_isNonNegative; } + const CalcExpressionNode* expression() const { return m_value.get(); } + private: CalculationValue(PassOwnPtr value, CalculationPermittedValueRange range) : m_value(value) , m_isNonNegative(range == CalculationRangeNonNegative) { } - + OwnPtr m_value; bool m_isNonNegative; }; @@ -115,20 +118,28 @@ public: return m_value == o.m_value; } - virtual bool operator==(const CalcExpressionNode& o) const + virtual bool operator==(const CalcExpressionNode& o) const OVERRIDE { return type() == o.type() && *this == static_cast(o); } - - virtual float evaluate(float) const + + virtual float evaluate(float) const OVERRIDE { return m_value; } - + + float value() const { return m_value; } + private: float m_value; }; +inline const CalcExpressionNumber* toCalcExpressionNumber(const CalcExpressionNode* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeNumber); + return static_cast(value); +} + class CalcExpressionLength : public CalcExpressionNode { public: explicit CalcExpressionLength(Length length) @@ -141,21 +152,29 @@ public: { return m_length == o.m_length; } - - virtual bool operator==(const CalcExpressionNode& o) const + + virtual bool operator==(const CalcExpressionNode& o) const OVERRIDE { return type() == o.type() && *this == static_cast(o); } - - virtual float evaluate(float maxValue) const + + virtual float evaluate(float maxValue) const OVERRIDE { return floatValueForLength(m_length, maxValue); } - + + const Length& length() const { return m_length; } + private: Length m_length; }; +inline const CalcExpressionLength* toCalcExpressionLength(const CalcExpressionNode* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeLength); + return static_cast(value); +} + class CalcExpressionBinaryOperation : public CalcExpressionNode { public: CalcExpressionBinaryOperation(PassOwnPtr leftSide, PassOwnPtr rightSide, CalcOperator op) @@ -171,13 +190,16 @@ public: return m_operator == o.m_operator && *m_leftSide == *o.m_leftSide && *m_rightSide == *o.m_rightSide; } - virtual bool operator==(const CalcExpressionNode& o) const + virtual bool operator==(const CalcExpressionNode& o) const OVERRIDE { return type() == o.type() && *this == static_cast(o); } - - - virtual float evaluate(float) const; + + virtual float evaluate(float) const OVERRIDE; + + const CalcExpressionNode* leftSide() const { return m_leftSide.get(); } + const CalcExpressionNode* rightSide() const { return m_rightSide.get(); } + CalcOperator getOperator() const { return m_operator; } private: OwnPtr m_leftSide; @@ -185,6 +207,12 @@ private: CalcOperator m_operator; }; +inline const CalcExpressionBinaryOperation* toCalcExpressionBinaryOperation(const CalcExpressionNode* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeBinaryOperation); + return static_cast(value); +} + class CalcExpressionBlendLength : public CalcExpressionNode { public: CalcExpressionBlendLength(Length from, Length to, float progress) @@ -194,28 +222,38 @@ public: { m_type = CalcExpressionNodeBlendLength; } - + bool operator==(const CalcExpressionBlendLength& o) const { return m_progress == o.m_progress && m_from == o.m_from && m_to == o.m_to; } - - virtual bool operator==(const CalcExpressionNode& o) const + + virtual bool operator==(const CalcExpressionNode& o) const OVERRIDE { return type() == o.type() && *this == static_cast(o); } - - virtual float evaluate(float maxValue) const + + virtual float evaluate(float maxValue) const OVERRIDE { return (1.0f - m_progress) * floatValueForLength(m_from, maxValue) + m_progress * floatValueForLength(m_to, maxValue); } - -private: + + const Length& from() const { return m_from; } + const Length& to() const { return m_to; } + float progress() const { return m_progress; } + +private: Length m_from; Length m_to; float m_progress; }; - + +inline const CalcExpressionBlendLength* toCalcExpressionBlendLength(const CalcExpressionNode* value) +{ + ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeBlendLength); + return static_cast(value); +} + } // namespace WebCore #endif // CalculationValue_h -- cgit v1.2.3