Crash on shape-outside when using calc()
authorhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Sep 2013 23:17:34 +0000 (23:17 +0000)
committerhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 27 Sep 2013 23:17:34 +0000 (23:17 +0000)
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: https://svn.webkit.org/repository/webkit/trunk@156586 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
LayoutTests/ChangeLog
LayoutTests/css3/calc/cssom-expected.txt
LayoutTests/css3/calc/simplification-expected.txt [new file with mode: 0644]
LayoutTests/css3/calc/simplification.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash-expected.txt [new file with mode: 0644]
LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/BasicShapeFunctions.cpp
Source/WebCore/css/BasicShapeFunctions.h
Source/WebCore/css/CSSCalculationValue.cpp
Source/WebCore/css/CSSCalculationValue.h
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSPrimitiveValue.cpp
Source/WebCore/css/CSSPrimitiveValue.h
Source/WebCore/css/CSSValuePool.h
Source/WebCore/platform/CalculationValue.h

index 4390dba..2c8c33a 100644 (file)
@@ -1,3 +1,19 @@
+2013-09-27  Hans Muller  <hmuller@adobe.com>
+
+        Crash on shape-outside when using calc()
+        https://bugs.webkit.org/show_bug.cgi?id=121020
+
+        Reviewed by Dirk Schulze.
+
+        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:
+
 2013-09-27  Alexey Proskuryakov  <ap@apple.com>
 
         Layout Test animations/combo-transform-translate+scale.html is flaky
index d5f543c..e94d293 100644 (file)
@@ -1,15 +1,15 @@
 This tests calc() and the CSSOM
 
 10px => calc(10px)
-10px + 15px => calc(10px + 15px)
+10px + 15px => calc(25px)
 100% => calc(100%)
 100% - 10px => calc(100% - 10px)
-10px + 10px * 5 => calc(10px + (10px * 5))
+10px + 10px * 5 => calc(60px)
 5px + 2em + 6in => calc((5px + 2em) + 6in)
-100% - 10px / 2 => calc(100% - (10px / 2))
+100% - 10px / 2 => calc(100% - 5px)
 1px + 2em - 3rem + 4in => calc(((1px + 2em) - 3rem) + 4in)
-100px * (1 + 2 * 3 - 4 / 5) => calc(100px * ((1 + (2 * 3)) - (4 / 5)))
-(100px) + 200px => calc(100px + 200px)
+100px * (1 + 2 * 3 - 4 / 5) => calc(620px)
+(100px) + 200px => calc(300px)
 ((((((((((100px)))))))))) => calc(100px)
 flimstix => calc(100px)
 
diff --git a/LayoutTests/css3/calc/simplification-expected.txt b/LayoutTests/css3/calc/simplification-expected.txt
new file mode 100644 (file)
index 0000000..16c44e2
--- /dev/null
@@ -0,0 +1,21 @@
+This tests parse time simplification in calc()
+
+100px * (25 + 5) => calc(3000px)
+100em * (25 - 5) => calc(2000em)
+100ex * (2 * 5 - 5) => calc(500ex)
+100cm * (5 - 4 / 5) => calc(420cm)
+100mm * (2.4 * 5 - 8 / 5) => calc(1040mm)
+100in * (6 * (5 - 4) / 8) => calc(75in)
+1px * (3 + 1/(7 + 1/(15 + 1/(1 + 1/(292 + 1/(1 + 1/(1 + 1/(1 + 1)))))))) => calc(3.1415926535583574px)
+100pc * 20 + 100rem * 10 - 100ch * 5 + 100pc => calc(((2000pc + 1000rem) - 500ch) + 100pc)
+((100px + 20 * 5px) * 10 - 5 * (10em * 5 + 10em)) * 2 => calc((2000px - 300em) * 2)
+100px + 1in => calc(196px)
+10 * 10px + 0.5 * 2in => calc(196px)
+100px + 1in + 10% => calc(196px + 10%)
+100px - 1in => calc(4px)
+50cm + 50cm => calc(100cm)
+50cm + 10in + 100mm => calc(3227.7165354330705px)
+100px + 1em => calc(100px + 1em)
+100px + 1em + 100px => calc((100px + 1em) + 100px)
+1em + 1rem => calc(1em + 1rem)
+
diff --git a/LayoutTests/css3/calc/simplification.html b/LayoutTests/css3/calc/simplification.html
new file mode 100644 (file)
index 0000000..c9de6db
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<div id="dummy"></div>
+<div id="results">This tests parse time simplification in calc()<br><br></div>
+<script>
+if (window.testRunner)
+    window.testRunner.dumpAsText();
+
+var tests = [
+    "100px * (25 + 5)",
+    "100em * (25 - 5)",
+    "100ex * (2 * 5 - 5)",
+    "100cm * (5 - 4 / 5)",
+    "100mm * (2.4 * 5 - 8 / 5)",
+    "100in * (6 * (5 - 4) / 8)",
+    "1px * (3 + 1/(7 + 1/(15 + 1/(1 + 1/(292 + 1/(1 + 1/(1 + 1/(1 + 1))))))))",
+    "100pc * 20 + 100rem * 10 - 100ch * 5 + 100pc",
+    "((100px + 20 * 5px) * 10 - 5 * (10em * 5 + 10em)) * 2",
+    "100px + 1in",
+    "10 * 10px + 0.5 * 2in",
+    "100px + 1in + 10%",
+    "100px - 1in",
+    "50cm + 50cm",
+    "50cm + 10in + 100mm",
+    "100px + 1em",
+    "100px + 1em + 100px",
+    "1em + 1rem",
+];
+
+var results = document.getElementById("results");
+var dummy = document.getElementById("dummy");
+for (var i = 0; i < tests.length; ++i) {
+    var expression = tests[i];
+    dummy.style.width = 'calc(' + expression + ')';
+    results.innerHTML += expression + " => " + dummy.style.width + "<br>";
+}
+</script>
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash-expected.txt b/LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash-expected.txt
new file mode 100644 (file)
index 0000000..09124fb
--- /dev/null
@@ -0,0 +1,3 @@
+PASS window.getComputedStyle(document.getElementById('shape-inside'))['-webkit-shape-inside'] is 'circle(30%, 50%, 50%)'
+This test should not crash
+Hello
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash.html b/LayoutTests/fast/shapes/shape-inside/shape-inside-calc-crash.html
new file mode 100644 (file)
index 0000000..440e378
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!--
+This is a regression test for https://bugs.webkit.org/show_bug.cgi?id=121020
+-->
+<script src="../../../resources/js-test-pre.js"></script>
+<script>
+window.onload = function() {
+    shouldBe("window.getComputedStyle(document.getElementById('shape-inside'))['-webkit-shape-inside']", "'circle(30%, 50%, 50%)'");
+};
+</script>
+<style>
+#shape-inside {
+    -webkit-shape-inside: circle(calc(50% - 20%), 50%, 50%);
+}
+</style>
+<body>
+  <div>This test should not crash</div>
+  <div id="shape-inside">Hello</div>
+</body>
+</html>
index 7e0792a..d544d42 100644 (file)
@@ -1,3 +1,96 @@
+2013-09-27  Hans Muller  <hmuller@adobe.com>
+
+        Crash on shape-outside when using calc()
+        https://bugs.webkit.org/show_bug.cgi?id=121020
+
+        Reviewed by Dirk Schulze.
+
+        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):
+
 2013-09-27  Andreas Kling  <akling@apple.com>
 
         REGRESSION(r154219): 30% more malloc memory used on html5-full-render.
index 135a963..7190745 100644 (file)
@@ -38,7 +38,7 @@
 
 namespace WebCore {
 
-PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
+PassRefPtr<CSSValue> valueForBasicShape(const RenderStyle* style, const BasicShape* basicShape)
 {
     CSSValuePool& pool = cssValuePool();
 
@@ -48,12 +48,12 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
         const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape);
         RefPtr<CSSBasicShapeRectangle> rectangleValue = CSSBasicShapeRectangle::create();
 
-        rectangleValue->setX(pool.createValue(rectangle->x()));
-        rectangleValue->setY(pool.createValue(rectangle->y()));
-        rectangleValue->setWidth(pool.createValue(rectangle->width()));
-        rectangleValue->setHeight(pool.createValue(rectangle->height()));
-        rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX()));
-        rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY()));
+        rectangleValue->setX(pool.createValue(rectangle->x(), style));
+        rectangleValue->setY(pool.createValue(rectangle->y(), style));
+        rectangleValue->setWidth(pool.createValue(rectangle->width(), style));
+        rectangleValue->setHeight(pool.createValue(rectangle->height(), style));
+        rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX(), style));
+        rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY(), style));
 
         basicShapeValue = rectangleValue.release();
         break;
@@ -62,9 +62,9 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
         const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape);
         RefPtr<CSSBasicShapeCircle> circleValue = CSSBasicShapeCircle::create();
 
-        circleValue->setCenterX(pool.createValue(circle->centerX()));
-        circleValue->setCenterY(pool.createValue(circle->centerY()));
-        circleValue->setRadius(pool.createValue(circle->radius()));
+        circleValue->setCenterX(pool.createValue(circle->centerX(), style));
+        circleValue->setCenterY(pool.createValue(circle->centerY(), style));
+        circleValue->setRadius(pool.createValue(circle->radius(), style));
 
         basicShapeValue = circleValue.release();
         break;
@@ -73,10 +73,10 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
         const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape);
         RefPtr<CSSBasicShapeEllipse> ellipseValue = CSSBasicShapeEllipse::create();
 
-        ellipseValue->setCenterX(pool.createValue(ellipse->centerX()));
-        ellipseValue->setCenterY(pool.createValue(ellipse->centerY()));
-        ellipseValue->setRadiusX(pool.createValue(ellipse->radiusX()));
-        ellipseValue->setRadiusY(pool.createValue(ellipse->radiusY()));
+        ellipseValue->setCenterX(pool.createValue(ellipse->centerX(), style));
+        ellipseValue->setCenterY(pool.createValue(ellipse->centerY(), style));
+        ellipseValue->setRadiusX(pool.createValue(ellipse->radiusX(), style));
+        ellipseValue->setRadiusY(pool.createValue(ellipse->radiusY(), style));
 
         basicShapeValue = ellipseValue.release();
         break;
@@ -88,7 +88,7 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
         polygonValue->setWindRule(polygon->windRule());
         const Vector<Length>& values = polygon->values();
         for (unsigned i = 0; i < values.size(); i += 2)
-            polygonValue->appendPoint(pool.createValue(values.at(i)), pool.createValue(values.at(i + 1)));
+            polygonValue->appendPoint(pool.createValue(values.at(i), style), pool.createValue(values.at(i + 1), style));
 
         basicShapeValue = polygonValue.release();
         break;
@@ -97,12 +97,12 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
         const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape);
         RefPtr<CSSBasicShapeInsetRectangle> rectangleValue = CSSBasicShapeInsetRectangle::create();
 
-        rectangleValue->setTop(pool.createValue(rectangle->top()));
-        rectangleValue->setRight(pool.createValue(rectangle->right()));
-        rectangleValue->setBottom(pool.createValue(rectangle->bottom()));
-        rectangleValue->setLeft(pool.createValue(rectangle->left()));
-        rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX()));
-        rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY()));
+        rectangleValue->setTop(pool.createValue(rectangle->top(), style));
+        rectangleValue->setRight(pool.createValue(rectangle->right(), style));
+        rectangleValue->setBottom(pool.createValue(rectangle->bottom(), style));
+        rectangleValue->setLeft(pool.createValue(rectangle->left(), style));
+        rectangleValue->setRadiusX(pool.createValue(rectangle->cornerRadiusX(), style));
+        rectangleValue->setRadiusY(pool.createValue(rectangle->cornerRadiusY(), style));
 
         basicShapeValue = rectangleValue.release();
         break;
@@ -115,7 +115,7 @@ PassRefPtr<CSSValue> valueForBasicShape(const BasicShape* basicShape)
 
 static Length convertToLength(const RenderStyle* style, const RenderStyle* rootStyle, CSSPrimitiveValue* value)
 {
-    return value->convertToLength<FixedIntegerConversion | FixedFloatConversion | PercentConversion | ViewportPercentageConversion>(style, rootStyle, style->effectiveZoom());
+    return value->convertToLength<FixedIntegerConversion | FixedFloatConversion | PercentConversion | CalculatedConversion | ViewportPercentageConversion>(style, rootStyle, style->effectiveZoom());
 }
 
 PassRefPtr<BasicShape> basicShapeForValue(const RenderStyle* style, const RenderStyle* rootStyle, const CSSBasicShape* basicShapeValue)
index 9bbc7c7..ddf7659 100644 (file)
@@ -39,7 +39,7 @@ class CSSBasicShape;
 class CSSValue;
 class RenderStyle;
 
-PassRefPtr<CSSValue> valueForBasicShape(const BasicShape*);
+PassRefPtr<CSSValue> valueForBasicShape(const RenderStyle*, const BasicShape*);
 PassRefPtr<BasicShape> basicShapeForValue(const RenderStyle*, const RenderStyle* rootStyle, const CSSBasicShape*);
 
 }
index 2d1a3fe..bdf049c 100644 (file)
 #include "config.h"
 #include "CSSCalculationValue.h"
 
+#include "CSSPrimitiveValueMappings.h"
 #include "CSSValueList.h"
 #include "Length.h"
 #include "StyleResolver.h"
 
+#include <wtf/MathExtras.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/text/StringBuilder.h>
@@ -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<CSSCalcPrimitiveValue> create(CSSPrimitiveValue* value, bool isInteger)
+    static PassRefPtr<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
     {
         return adoptRef(new CSSCalcPrimitiveValue(value, isInteger));
     }
-    
+
+    static PassRefPtr<CSSCalcPrimitiveValue> 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<float>(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<FixedFloatConversion | PercentConversion | FractionConversion>(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<CSSPrimitiveValue> 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<CSSCalcBinaryOperation> create(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
+    static PassRefPtr<CSSCalcExpressionNode> create(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> 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<CSSCalcExpressionNode> createSimplified(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> 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<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> 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<CSSCalcExpressionNode> m_leftSide;
     const RefPtr<CSSCalcExpressionNode> m_rightSide;
     const CalcOperator m_operator;
@@ -449,7 +633,7 @@ private:
         if (!value || !value->isPrimitiveValue())
             return false;
 
-        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(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, &currentIndex, 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<CalcOperator>(operatorCharacter));
+            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(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<CalcOperator>(operatorCharacter));
+            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
             if (!result->value)
                 return false;
         }
@@ -535,16 +719,96 @@ private:
     }
 };
 
+PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
+{
+    return CSSCalcPrimitiveValue::create(value, isInteger);
+}
+
+PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
+{
+    return CSSCalcBinaryOperation::create(leftSide, rightSide, op);
+}
+
+PassRefPtr<CSSCalcExpressionNode> 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<CSSCalcExpressionNode> 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> CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range)
-{    
-    CSSCalcExpressionNodeParser parser;    
+{
+    CSSCalcExpressionNodeParser parser;
     RefPtr<CSSCalcExpressionNode> 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> CSSCalcValue::create(PassRefPtr<CSSCalcExpressionNode> expression, CalculationPermittedValueRange range)
+{
+    return adoptRef(new CSSCalcValue(expression, range));
+}
+
 } // namespace WebCore
index befce16..e7db0ce 100644 (file)
@@ -32,6 +32,7 @@
 #define CSSCalculationValue_h
 
 #include "CSSParserValues.h"
+#include "CSSPrimitiveValue.h"
 #include "CSSValue.h"
 #include "CalculationValue.h"
 #include <wtf/PassOwnPtr.h>
@@ -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<CSSCalcExpressionNode> {
 public:
     enum Type {
@@ -67,7 +69,7 @@ public:
 
     virtual ~CSSCalcExpressionNode() = 0;
     virtual bool isZero() const = 0;
-    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(const RenderStyle*, const RenderStyle* rootStyle, double zoom = 1.0) const = 0;    
+    virtual PassOwnPtr<CalcExpressionNode> 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,83 @@ 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<CSSCalcValue> create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange);
-    static PassRefPtr<CSSCalcValue> create(CalculationValue*);
+    static PassRefPtr<CSSCalcValue> create(PassRefPtr<CSSCalcExpressionNode>, CalculationPermittedValueRange = CalculationRangeAll);
+    static PassRefPtr<CSSCalcValue> create(const CalculationValue* value, const RenderStyle* style) { return adoptRef(new CSSCalcValue(value, style)); }
+
+    static PassRefPtr<CSSCalcExpressionNode> createExpressionNode(PassRefPtr<CSSPrimitiveValue>, bool isInteger = false);
+    static PassRefPtr<CSSCalcExpressionNode> createExpressionNode(PassRefPtr<CSSCalcExpressionNode>, PassRefPtr<CSSCalcExpressionNode>, CalcOperator);
+    static PassRefPtr<CSSCalcExpressionNode> createExpressionNode(const CalcExpressionNode*, const RenderStyle*);
+    static PassRefPtr<CSSCalcExpressionNode> createExpressionNode(const Length&, const RenderStyle*);
 
     PassRefPtr<CalculationValue> 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<AtomicString, String>&) const;
     bool hasVariableReference() const;
 #endif
-    
-private:    
+
+private:
     CSSCalcValue(PassRefPtr<CSSCalcExpressionNode> 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<CSSCalcExpressionNode> m_expression;
     const bool m_nonNegative;
 };
-    
+
+inline CSSCalcValue* toCSSCalcValue(CSSValue* value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isCalculationValue());
+    return static_cast<CSSCalcValue*>(value);
+}
+
+inline const CSSCalcValue* toCSSCalcValue(const CSSValue* value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isCalculationValue());
+    return static_cast<const CSSCalcValue*>(value);
+}
+
 } // namespace WebCore
 
 #endif // CSSCalculationValue_h
index 287fbf6..4e6ee1a 100644 (file)
@@ -2811,7 +2811,7 @@ PassRefPtr<CSSValue> ComputedStyleExtractor::propertyValue(CSSPropertyID propert
         case CSSPropertyWebkitClipPath:
             if (ClipPathOperation* operation = style->clipPath()) {
                 if (operation->getOperationType() == ClipPathOperation::SHAPE)
-                    return valueForBasicShape(static_cast<ShapeClipPathOperation*>(operation)->basicShape());
+                    return valueForBasicShape(style.get(), static_cast<ShapeClipPathOperation*>(operation)->basicShape());
 #if ENABLE(SVG)
                 else if (operation->getOperationType() == ClipPathOperation::REFERENCE) {
                     ReferenceClipPathOperation* referenceOperation = static_cast<ReferenceClipPathOperation*>(operation);
@@ -2854,7 +2854,7 @@ PassRefPtr<CSSValue> 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);
@@ -2864,7 +2864,7 @@ PassRefPtr<CSSValue> 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:
index b59e808..62d03b7 100644 (file)
@@ -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;
@@ -285,65 +285,102 @@ 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();
index 649a74b..bfa3315 100644 (file)
@@ -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<CSSPrimitiveValue> createIdentifier(CSSValueID valueID) { return adoptRef(new CSSPrimitiveValue(valueID)); }
     static PassRefPtr<CSSPrimitiveValue> createIdentifier(CSSPropertyID propertyID) { return adoptRef(new CSSPrimitiveValue(propertyID)); }
     static PassRefPtr<CSSPrimitiveValue> createParserOperator(int parserOperator) { return adoptRef(new CSSPrimitiveValue(parserOperator)); }
@@ -215,6 +216,7 @@ public:
     static PassRefPtr<CSSPrimitiveValue> createColor(unsigned rgbValue) { return adoptRef(new CSSPrimitiveValue(rgbValue)); }
     static PassRefPtr<CSSPrimitiveValue> create(double value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); }
     static PassRefPtr<CSSPrimitiveValue> create(const String& value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); }
+    static PassRefPtr<CSSPrimitiveValue> create(const Length& value, const RenderStyle* style) { return adoptRef(new CSSPrimitiveValue(value, style)); }
 
     template<typename T> static PassRefPtr<CSSPrimitiveValue> 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<URL>&, const StyleSheetContents*) const;
 
     Length viewportPercentageLength() const;
-    
+
     PassRefPtr<CSSPrimitiveValue> 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<typename T> operator T*(); // compile-time guard
 
-    static UnitTypes canonicalUnitTypeForCategory(UnitCategory category);
-
+    void init(const Length&);
     void init(PassRefPtr<Counter>);
     void init(PassRefPtr<Rect>);
     void init(PassRefPtr<Pair>);
@@ -396,6 +401,18 @@ private:
     } m_value;
 };
 
+inline CSSPrimitiveValue* toCSSPrimitiveValue(CSSValue* value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isPrimitiveValue());
+    return static_cast<CSSPrimitiveValue*>(value);
+}
+
+inline const CSSPrimitiveValue* toCSSPrimitiveValue(const CSSValue* value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->isPrimitiveValue());
+    return static_cast<const CSSPrimitiveValue*>(value);
+}
+
 } // namespace WebCore
 
 #endif // CSSPrimitiveValue_h
index b8ce1dc..bbcff77 100644 (file)
@@ -31,9 +31,9 @@
 #include "CSSPrimitiveValue.h"
 #include "CSSPropertyNames.h"
 #include "CSSValueKeywords.h"
-#include <wtf/text/AtomicStringHash.h>
 #include <wtf/HashMap.h>
 #include <wtf/RefPtr.h>
+#include <wtf/text/AtomicStringHash.h>
 
 namespace WebCore {
 
@@ -52,6 +52,7 @@ public:
     PassRefPtr<CSSPrimitiveValue> createColorValue(unsigned rgbValue);
     PassRefPtr<CSSPrimitiveValue> createValue(double value, CSSPrimitiveValue::UnitTypes);
     PassRefPtr<CSSPrimitiveValue> createValue(const String& value, CSSPrimitiveValue::UnitTypes type) { return CSSPrimitiveValue::create(value, type); }
+    PassRefPtr<CSSPrimitiveValue> createValue(const Length& value, const RenderStyle* style) { return CSSPrimitiveValue::create(value, style); }
     template<typename T> static PassRefPtr<CSSPrimitiveValue> createValue(T value) { return CSSPrimitiveValue::create(value); }
 
     void drain();
index 0aa7e20..3dcbf1b 100644 (file)
@@ -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<CalculationValue> {
 public:
     static PassRefPtr<CalculationValue> create(PassOwnPtr<CalcExpressionNode> 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<CalcExpressionNode> value, CalculationPermittedValueRange range)
         : m_value(value)
         , m_isNonNegative(range == CalculationRangeNonNegative)
     {
     }
-    
+
     OwnPtr<CalcExpressionNode> m_value;
     bool m_isNonNegative;
 };
@@ -115,24 +118,32 @@ 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<const CalcExpressionNumber&>(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<const CalcExpressionNumber*>(value);
+}
+
 class CalcExpressionLength : public CalcExpressionNode {
 public:
     explicit CalcExpressionLength(Length length)
-        : m_length(std::move(length))
+        : m_length(length)
     {
         m_type = CalcExpressionNodeLength;
     }
@@ -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<const CalcExpressionLength&>(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<const CalcExpressionLength*>(value);
+}
+
 class CalcExpressionBinaryOperation : public CalcExpressionNode {
 public:
     CalcExpressionBinaryOperation(PassOwnPtr<CalcExpressionNode> leftSide, PassOwnPtr<CalcExpressionNode> 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<const CalcExpressionBinaryOperation&>(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<CalcExpressionNode> m_leftSide;
@@ -185,37 +207,53 @@ private:
     CalcOperator m_operator;
 };
 
+inline const CalcExpressionBinaryOperation* toCalcExpressionBinaryOperation(const CalcExpressionNode* value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeBinaryOperation);
+    return static_cast<const CalcExpressionBinaryOperation*>(value);
+}
+
 class CalcExpressionBlendLength : public CalcExpressionNode {
 public:
     CalcExpressionBlendLength(Length from, Length to, float progress)
-        : m_from(std::move(from))
-        , m_to(std::move(to))
+        : m_from(from)
+        , m_to(to)
         , m_progress(progress)
     {
         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<const CalcExpressionBlendLength&>(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<const CalcExpressionBlendLength*>(value);
+}
+
 } // namespace WebCore
 
 #endif // CalculationValue_h