Title: [110148] trunk
Revision
110148
Author
mikelawt...@chromium.org
Date
2012-03-07 22:48:35 -0800 (Wed, 07 Mar 2012)

Log Message

CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
https://bugs.webkit.org/show_bug.cgi?id=79621

Reviewed by Andreas Kling.

Source/WebCore:

ApplyPropertyLength in CSSStyleApplyPropery now handles mixed absolute/percentage
length expressions. All property handlers using this template now work with
mixed expressions.

This patch adds a new _expression_ evaluator in CalculationValue.cpp. This is because
Length.[cpp|h] (in platform) cannot refer to CSSCalculationValue.[cpp|h] (in css)
due to layering restrictions.

Lengths can be copied, and so the expressions are stored in a hashmap, and only their
ids are copied along with Length. The expressions are RefCounted, and will get
cleaned up when the last referring Length is destructed.

* WebCore.exp.in:
* css/CSSCalculationValue.cpp:
(WebCore::CSSCalcPrimitiveValue::toCalcValue):
(CSSCalcPrimitiveValue):
(WebCore::CSSCalcBinaryOperation::toCalcValue):
(CSSCalcBinaryOperation):
* css/CSSCalculationValue.h:
(WebCore):
(CSSCalcExpressionNode):
(CSSCalcValue):
(WebCore::CSSCalcValue::toCalcValue):
* css/CSSPrimitiveValue.cpp:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
* css/CSSStyleApplyProperty.cpp:
(WebCore::ApplyPropertyLength::applyValue):
* css/CSSStyleSelector.cpp:
(WebCore::CSSStyleSelector::collectMatchingRulesForList):
* css/CSSStyleSelector.h:
(CSSStyleSelector):
* platform/CalculationValue.cpp:
(WebCore::CalcExpressionBinaryOperation::evaluate):
(WebCore):
(WebCore::CalculationValue::create):
(WebCore::CalculationValue::evaluate):
* platform/CalculationValue.h:
(CalcExpressionNode):
(WebCore::CalcExpressionNode::~CalcExpressionNode):
(WebCore):
(CalculationValue):
(WebCore::CalculationValue::CalculationValue):
(CalcExpressionNumber):
(WebCore::CalcExpressionNumber::CalcExpressionNumber):
(WebCore::CalcExpressionNumber::evaluate):
(CalcExpressionLength):
(WebCore::CalcExpressionLength::CalcExpressionLength):
(WebCore::CalcExpressionLength::evaluate):
(CalcExpressionBinaryOperation):
(WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation):
* platform/Length.cpp:
(WebCore):
(WebCore::Length::~Length):
(CalculationValueHandleMap):
(WebCore::CalculationValueHandleMap::CalculationValueHandleMap):
(WebCore::CalculationValueHandleMap::insert):
(WebCore::CalculationValueHandleMap::remove):
(WebCore::CalculationValueHandleMap::get):
(WebCore::calcHandles):
(WebCore::Length::Length):
(WebCore::Length::calculationValue):
(WebCore::Length::calculatedValue):
(WebCore::Length::calculatedMinValue):
(WebCore::Length::calculatedFloatValue):
(WebCore::Length::incrementCalculatedRef):
(WebCore::Length::decrementCalculatedRef):
(WebCore::Length::nonNanCalculatedValue):
* platform/Length.h:
(Length):
(WebCore::Length::Length):
(WebCore::Length::operator=):
(WebCore::Length::operator*=):
(WebCore::Length::value):
(WebCore::Length::setValue):
(WebCore::Length::calcValue):
(WebCore::Length::calcMinValue):
(WebCore::Length::calcFloatValue):
(WebCore::Length::isZero):
(WebCore::Length::isPositive):
(WebCore::Length::isNegative):
(WebCore::Length::isPercent):
(WebCore::Length::isSpecified):
(WebCore::Length::isCalculated):
(WebCore::Length::initFromLength):
(WebCore::Length::calculationHandle):

LayoutTests:

* css3/calc/margin-expected.txt:
* css3/calc/padding-expected.txt:
* css3/calc/simple-calcs-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (110147 => 110148)


--- trunk/LayoutTests/ChangeLog	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/ChangeLog	2012-03-08 06:48:35 UTC (rev 110148)
@@ -1,3 +1,14 @@
+2012-03-07  Mike Lawther  <mikelawt...@chromium.org>
+
+        CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
+        https://bugs.webkit.org/show_bug.cgi?id=79621
+
+        Reviewed by Andreas Kling.
+
+        * css3/calc/margin-expected.txt:
+        * css3/calc/padding-expected.txt:
+        * css3/calc/simple-calcs-expected.txt:
+
 2012-03-07  Fumitoshi Ukai  <u...@chromium.org>
 
         Unreviewed. update chromium test expectations.

Modified: trunk/LayoutTests/css3/calc/margin-expected.txt (110147 => 110148)


--- trunk/LayoutTests/css3/calc/margin-expected.txt	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/margin-expected.txt	2012-03-08 06:48:35 UTC (rev 110148)
@@ -18,26 +18,26 @@
 PASS computedMarginTop("simple-bottom") is "0px"
 PASS computedMarginRight("simple-bottom") is "0px"
 PASS computedMarginBottom("simple-bottom") is "25px"
-FAIL computedMarginLeft("percent-all") should be 25px. Was 0px.
-FAIL computedMarginTop("percent-all") should be 25px. Was 0px.
-FAIL computedMarginRight("percent-all") should be 25px. Was 0px.
-FAIL computedMarginBottom("percent-all") should be 25px. Was 0px.
-FAIL computedMarginLeft("percent-left") should be 25px. Was 0px.
+PASS computedMarginLeft("percent-all") is "25px"
+PASS computedMarginTop("percent-all") is "25px"
+PASS computedMarginRight("percent-all") is "25px"
+PASS computedMarginBottom("percent-all") is "25px"
+PASS computedMarginLeft("percent-left") is "25px"
 PASS computedMarginTop("percent-left") is "0px"
 PASS computedMarginRight("percent-left") is "0px"
 PASS computedMarginBottom("percent-left") is "0px"
 PASS computedMarginLeft("percent-right") is "0px"
 PASS computedMarginTop("percent-right") is "0px"
-FAIL computedMarginRight("percent-right") should be 25px. Was 0px.
+PASS computedMarginRight("percent-right") is "25px"
 PASS computedMarginBottom("percent-right") is "0px"
 PASS computedMarginLeft("percent-top") is "0px"
-FAIL computedMarginTop("percent-top") should be 25px. Was 0px.
+PASS computedMarginTop("percent-top") is "25px"
 PASS computedMarginRight("percent-top") is "0px"
 PASS computedMarginBottom("percent-top") is "0px"
 PASS computedMarginLeft("percent-bottom") is "0px"
 PASS computedMarginTop("percent-bottom") is "0px"
 PASS computedMarginRight("percent-bottom") is "0px"
-FAIL computedMarginBottom("percent-bottom") should be 25px. Was 0px.
+PASS computedMarginBottom("percent-bottom") is "25px"
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/css3/calc/padding-expected.txt (110147 => 110148)


--- trunk/LayoutTests/css3/calc/padding-expected.txt	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/padding-expected.txt	2012-03-08 06:48:35 UTC (rev 110148)
@@ -8,12 +8,12 @@
 
 This element should have a bottom padding of 25 pixels. => PASS
 
-This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width, wrong height
+This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
 
-This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
+This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
 
-This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
+This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
 
-This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
+This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
 
-This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
+This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS

Modified: trunk/LayoutTests/css3/calc/simple-calcs-expected.txt (110147 => 110148)


--- trunk/LayoutTests/css3/calc/simple-calcs-expected.txt	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/simple-calcs-expected.txt	2012-03-08 06:48:35 UTC (rev 110148)
@@ -20,10 +20,10 @@
 10px* (5 * 2) => PASS
 50px + 10px * 5 (operation order) => PASS
 100%/2 (where 100% is 200px) => PASS
-100% + -100px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
-80% - 60px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
-300px - 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
--100px + 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
+100% + -100px (where 100% is 200px) => PASS
+80% - 60px (where 100% is 200px) => PASS
+300px - 100% (where 100% is 200px) => PASS
+-100px + 100% (where 100% is 200px) => PASS
 20% + 30% (where 100% is 200px) => PASS
 80% - 30% (where 100% is 200px) => PASS
 10% * 5 (where 100% is 200px) => PASS

Modified: trunk/Source/WebCore/ChangeLog (110147 => 110148)


--- trunk/Source/WebCore/ChangeLog	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/ChangeLog	2012-03-08 06:48:35 UTC (rev 110148)
@@ -1,3 +1,96 @@
+2012-03-07  Mike Lawther  <mikelawt...@chromium.org>
+
+        CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
+        https://bugs.webkit.org/show_bug.cgi?id=79621
+
+        Reviewed by Andreas Kling.
+
+        ApplyPropertyLength in CSSStyleApplyPropery now handles mixed absolute/percentage
+        length expressions. All property handlers using this template now work with
+        mixed expressions.
+
+        This patch adds a new _expression_ evaluator in CalculationValue.cpp. This is because
+        Length.[cpp|h] (in platform) cannot refer to CSSCalculationValue.[cpp|h] (in css) 
+        due to layering restrictions.
+
+        Lengths can be copied, and so the expressions are stored in a hashmap, and only their
+        ids are copied along with Length. The expressions are RefCounted, and will get 
+        cleaned up when the last referring Length is destructed.
+
+        * WebCore.exp.in:
+        * css/CSSCalculationValue.cpp:
+        (WebCore::CSSCalcPrimitiveValue::toCalcValue):
+        (CSSCalcPrimitiveValue):
+        (WebCore::CSSCalcBinaryOperation::toCalcValue):
+        (CSSCalcBinaryOperation):
+        * css/CSSCalculationValue.h:
+        (WebCore):
+        (CSSCalcExpressionNode):
+        (CSSCalcValue):
+        (WebCore::CSSCalcValue::toCalcValue):
+        * css/CSSPrimitiveValue.cpp:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+        * css/CSSStyleApplyProperty.cpp:
+        (WebCore::ApplyPropertyLength::applyValue):
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::collectMatchingRulesForList):
+        * css/CSSStyleSelector.h:
+        (CSSStyleSelector):
+        * platform/CalculationValue.cpp:
+        (WebCore::CalcExpressionBinaryOperation::evaluate):
+        (WebCore):
+        (WebCore::CalculationValue::create):
+        (WebCore::CalculationValue::evaluate):
+        * platform/CalculationValue.h:
+        (CalcExpressionNode):
+        (WebCore::CalcExpressionNode::~CalcExpressionNode):
+        (WebCore):
+        (CalculationValue):
+        (WebCore::CalculationValue::CalculationValue):
+        (CalcExpressionNumber):
+        (WebCore::CalcExpressionNumber::CalcExpressionNumber):
+        (WebCore::CalcExpressionNumber::evaluate):
+        (CalcExpressionLength):
+        (WebCore::CalcExpressionLength::CalcExpressionLength):
+        (WebCore::CalcExpressionLength::evaluate):
+        (CalcExpressionBinaryOperation):
+        (WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation):
+        * platform/Length.cpp:
+        (WebCore):
+        (WebCore::Length::~Length):
+        (CalculationValueHandleMap):
+        (WebCore::CalculationValueHandleMap::CalculationValueHandleMap):
+        (WebCore::CalculationValueHandleMap::insert):
+        (WebCore::CalculationValueHandleMap::remove):
+        (WebCore::CalculationValueHandleMap::get):
+        (WebCore::calcHandles):
+        (WebCore::Length::Length):
+        (WebCore::Length::calculationValue):
+        (WebCore::Length::calculatedValue):
+        (WebCore::Length::calculatedMinValue):
+        (WebCore::Length::calculatedFloatValue):
+        (WebCore::Length::incrementCalculatedRef):
+        (WebCore::Length::decrementCalculatedRef):
+        (WebCore::Length::nonNanCalculatedValue):
+        * platform/Length.h:
+        (Length):
+        (WebCore::Length::Length):
+        (WebCore::Length::operator=):
+        (WebCore::Length::operator*=):
+        (WebCore::Length::value):
+        (WebCore::Length::setValue):
+        (WebCore::Length::calcValue):
+        (WebCore::Length::calcMinValue):
+        (WebCore::Length::calcFloatValue):
+        (WebCore::Length::isZero):
+        (WebCore::Length::isPositive):
+        (WebCore::Length::isNegative):
+        (WebCore::Length::isPercent):
+        (WebCore::Length::isSpecified):
+        (WebCore::Length::isCalculated):
+        (WebCore::Length::initFromLength):
+        (WebCore::Length::calculationHandle):
+
 2012-03-07  Kent Tamura  <tk...@chromium.org>
 
         Do not refer to resutlsButtonElement and cancelButtonElement to compute paddings of search popups

Modified: trunk/Source/WebCore/WebCore.exp.in (110147 => 110148)


--- trunk/Source/WebCore/WebCore.exp.in	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/WebCore.exp.in	2012-03-08 06:48:35 UTC (rev 110148)
@@ -1422,6 +1422,7 @@
 __ZNK7WebCore6Editor8canPasteEv
 __ZNK7WebCore6Editor9canDeleteEv
 __ZNK7WebCore6JSNode21pushEventHandlerScopeEPN3JSC9ExecStateEPNS1_14ScopeChainNodeE
+__ZNK7WebCore6Length22decrementCalculatedRefEv
 __ZNK7WebCore6Region5rectsEv
 __ZNK7WebCore6Widget14platformWidgetEv
 __ZNK7WebCore6Widget23convertToContainingViewERKNS_7IntRectE

Modified: trunk/Source/WebCore/css/CSSCalculationValue.cpp (110147 => 110148)


--- trunk/Source/WebCore/css/CSSCalculationValue.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSCalculationValue.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -114,6 +114,25 @@
         return m_value->cssText();
     }
 
+    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
+    {
+        switch (m_category) {
+        case CalcNumber:
+            return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue()));
+        case CalcLength:
+            return adoptPtr(new CalcExpressionNumber(m_value->computeLength<float>(style, rootStyle, zoom)));
+        case CalcPercent:
+        case CalcPercentLength:
+            return adoptPtr(new CalcExpressionLength(CSSStyleSelector::convertToFloatLength(m_value.get(), style, rootStyle, zoom)));
+        // 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:
+        case CalcOther:
+            ASSERT_NOT_REACHED();
+        }
+        return nullptr;
+    }
+
     virtual double doubleValue() const
     {
         switch (m_category) {
@@ -208,6 +227,17 @@
         return !doubleValue();
     }
 
+    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
+    {
+        OwnPtr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom));
+        if (!left)
+            return nullptr;
+        OwnPtr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom));
+        if (!right)
+            return nullptr;
+        return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator));
+    }
+
     virtual double doubleValue() const 
     {
         return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());

Modified: trunk/Source/WebCore/css/CSSCalculationValue.h (110147 => 110148)


--- trunk/Source/WebCore/css/CSSCalculationValue.h	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSCalculationValue.h	2012-03-08 06:48:35 UTC (rev 110148)
@@ -43,7 +43,7 @@
 class CSSParserValueList;
 class CSSValueList;
 class RenderStyle;
-class CalcValue;
+class CalculationValue;
 class CalcExpressionNode;
 
 enum CalculationCategory {
@@ -58,8 +58,9 @@
 class CSSCalcExpressionNode : public RefCounted<CSSCalcExpressionNode> {
 public:
     
-    virtual ~CSSCalcExpressionNode() = 0;  
+    virtual ~CSSCalcExpressionNode() = 0;
     virtual bool isZero() const = 0;
+    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle*, RenderStyle* rootStyle, double zoom = 1.0) const = 0;    
     virtual double doubleValue() const = 0;
     virtual double computeLengthPx(RenderStyle* currentStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const = 0;
     
@@ -80,7 +81,12 @@
 class CSSCalcValue : public CSSValue {
 public:
     static PassRefPtr<CSSCalcValue> create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange);
+    static PassRefPtr<CSSCalcValue> create(CalculationValue*);
 
+    PassRefPtr<CalculationValue> toCalcValue(RenderStyle* style, 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(); }    
     double doubleValue() const;

Modified: trunk/Source/WebCore/css/CSSPrimitiveValue.cpp (110147 => 110148)


--- trunk/Source/WebCore/css/CSSPrimitiveValue.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSPrimitiveValue.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -266,6 +266,7 @@
             ASSERT(isfinite(length.percent()));
             m_value.num = length.percent();
             break;
+        case Calculated:
         case Relative:
         case Undefined:
             ASSERT_NOT_REACHED();

Modified: trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp (110147 => 110148)


--- trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -26,6 +26,7 @@
 #include "CSSStyleApplyProperty.h"
 
 #include "CSSAspectRatioValue.h"
+#include "CSSCalculationValue.h"
 #include "CSSCursorImageValue.h"
 #include "CSSFlexValue.h"
 #include "CSSPrimitiveValueMappings.h"
@@ -389,6 +390,8 @@
                 setValue(selector->style(), length);
             } else if (primitiveValue->isPercentage())
                 setValue(selector->style(), Length(primitiveValue->getDoubleValue(), Percent));
+            else if (primitiveValue->isCalculatedPercentageWithLength())
+                setValue(selector->style(), Length(primitiveValue->cssCalcValue()->toCalcValue(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom())));            
         }
     }
 

Modified: trunk/Source/WebCore/css/CSSStyleSelector.cpp (110147 => 110148)


--- trunk/Source/WebCore/css/CSSStyleSelector.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleSelector.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -30,10 +30,12 @@
 
 #include "Attribute.h"
 #include "CachedImage.h"
+#include "CalculationValue.h"
 #include "ContentData.h"
 #include "Counter.h"
 #include "CounterContent.h"
 #include "CSSBorderImage.h"
+#include "CSSCalculationValue.h"
 #include "CSSCursorImageValue.h"
 #include "CSSFontFaceRule.h"
 #include "CSSFontSelector.h"
@@ -2547,12 +2549,12 @@
     return l;
 }
 
-static Length convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
+Length CSSStyleSelector::convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
 {
     return convertToLength(primitiveValue, style, rootStyle, false, multiplier);
 }
 
-static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
+Length CSSStyleSelector::convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
 {
     return convertToLength(primitiveValue, style, rootStyle, true, multiplier);
 }

Modified: trunk/Source/WebCore/css/CSSStyleSelector.h (110147 => 110148)


--- trunk/Source/WebCore/css/CSSStyleSelector.h	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleSelector.h	2012-03-08 06:48:35 UTC (rev 110148)
@@ -362,6 +362,9 @@
     bool applyPropertyToRegularStyle() const { return m_applyPropertyToRegularStyle; }
     bool applyPropertyToVisitedLinkStyle() const { return m_applyPropertyToVisitedLinkStyle; }
 
+    static Length convertToIntLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
+    static Length convertToFloatLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
+
 private:
     static RenderStyle* s_styleNotYetAvailable;
 

Modified: trunk/Source/WebCore/platform/CalculationValue.cpp (110147 => 110148)


--- trunk/Source/WebCore/platform/CalculationValue.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/CalculationValue.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -31,6 +31,43 @@
 #include "config.h"
 #include "CalculationValue.h"
 
+#include <limits>
+
 namespace WebCore {
 
+float CalcExpressionBinaryOperation::evaluate(float maxValue) const
+{
+    float left = m_leftSide->evaluate(maxValue);
+    float right = m_rightSide->evaluate(maxValue);
+    switch (m_operator) {
+    case CalcAdd:
+        return left + right;
+    case CalcSubtract:
+        return left - right;
+    case CalcMultiply:
+        return left * right;
+    case CalcDivide:
+        if (!right)
+            return std::numeric_limits<float>::quiet_NaN();
+        return left / right;
+    }
+    ASSERT_NOT_REACHED();
+    return std::numeric_limits<float>::quiet_NaN();
+}
+
+PassRefPtr<CalculationValue> CalculationValue::create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+{
+    return adoptRef(new CalculationValue(value, range));
+}
+
+float CalculationValue::evaluate(float maxValue) const
+{
+    float result = m_value->evaluate(maxValue);
+    // FIXME calc https://webkit.org/b/80411 : result is NaN when there is a division 
+    // by zero which isn't found at parse time. 
+    if (isnan(result))
+        return 0;
+    return m_isNonNegative && result < 0 ? 0 : result;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/CalculationValue.h (110147 => 110148)


--- trunk/Source/WebCore/platform/CalculationValue.h	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/CalculationValue.h	2012-03-08 06:48:35 UTC (rev 110148)
@@ -50,7 +50,81 @@
     CalculationRangeAll,
     CalculationRangeNonNegative
 };
+        
+class CalcExpressionNode {
+public:
+    virtual ~CalcExpressionNode()
+    {
+    }
+    
+    virtual float evaluate(float maxValue) const = 0;
+};
+    
+class CalculationValue : public RefCounted<CalculationValue> {
+public:
+    static PassRefPtr<CalculationValue> create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange);
+    float evaluate(float maxValue) const;
+    
+private:
+    CalculationValue(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+        : m_value(value)
+        , m_isNonNegative(range == CalculationRangeNonNegative)
+    {
+    }
+    
+    OwnPtr<CalcExpressionNode> m_value;
+    bool m_isNonNegative;
+};
 
+class CalcExpressionNumber : public CalcExpressionNode {
+public:
+    explicit CalcExpressionNumber(float value)
+        : m_value(value)
+    {
+    }
+
+    virtual float evaluate(float) const 
+    {
+        return m_value;
+    }
+    
+private:
+    float m_value;
+};
+
+class CalcExpressionLength : public CalcExpressionNode {
+public:
+    explicit CalcExpressionLength(Length length)
+        : m_length(length)
+    {
+    }
+
+    virtual float evaluate(float maxValue) const
+    {
+        return m_length.calcFloatValue(maxValue);
+    }
+    
+private:
+    Length m_length;
+};
+
+class CalcExpressionBinaryOperation : public CalcExpressionNode {
+public:
+    CalcExpressionBinaryOperation(PassOwnPtr<CalcExpressionNode> leftSide, PassOwnPtr<CalcExpressionNode> rightSide, CalcOperator op)
+        : m_leftSide(leftSide)
+        , m_rightSide(rightSide)
+        , m_operator(op)
+    {
+    }
+
+    virtual float evaluate(float) const;
+
+private:
+    OwnPtr<CalcExpressionNode> m_leftSide;
+    OwnPtr<CalcExpressionNode> m_rightSide;
+    CalcOperator m_operator;
+};
+
 } // namespace WebCore
 
 #endif // CalculationValue_h

Modified: trunk/Source/WebCore/platform/Length.cpp (110147 => 110148)


--- trunk/Source/WebCore/platform/Length.cpp	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/Length.cpp	2012-03-08 06:48:35 UTC (rev 110148)
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "Length.h"
 
+#include "CalculationValue.h"
 #include "PlatformString.h"
 #include <wtf/ASCIICType.h>
 #include <wtf/Assertions.h>
@@ -148,7 +149,89 @@
 
     return r.release();
 }
+        
+class CalculationValueHandleMap {
+public:
+    CalculationValueHandleMap() 
+        : m_index(1) 
+    {
+    }
+    
+    int insert(PassRefPtr<CalculationValue> calcValue)
+    {
+        ASSERT(m_index);
+        // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
+        // This monotonically increasing handle generation scheme is potentially wasteful
+        // of the handle space. Consider reusing empty handles.
+        while (m_map.contains(m_index))
+            m_index++;
+        
+        m_map.set(m_index, calcValue);       
+        
+        return m_index;
+    }
 
+    void remove(int index)
+    {
+        ASSERT(m_map.contains(index));
+        m_map.remove(index);
+    }
+    
+    PassRefPtr<CalculationValue> get(int index)
+    {
+        ASSERT(m_map.contains(index));
+        return m_map.get(index);
+    }
+    
+private:        
+    int m_index;
+    HashMap<int, RefPtr<CalculationValue> > m_map;
+};
+    
+static CalculationValueHandleMap& calcHandles()
+{
+    DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
+    return handleMap;
+}
+
+Length::Length(PassRefPtr<CalculationValue> calc)
+    : m_quirk(false)
+    , m_type(Calculated)
+    , m_isFloat(false)
+{
+    m_intValue = calcHandles().insert(calc);
+}
+    
+PassRefPtr<CalculationValue> Length::calculationValue() const
+{
+    ASSERT(isCalculated());
+    return calcHandles().get(calculationHandle());
+}
+    
+void Length::incrementCalculatedRef() const
+{
+    ASSERT(isCalculated());
+    calculationValue()->ref();
+}
+
+void Length::decrementCalculatedRef() const
+{
+    ASSERT(isCalculated());
+    RefPtr<CalculationValue> calcLength = calculationValue();
+    if (calcLength->hasOneRef())
+        calcHandles().remove(calculationHandle());
+    calcLength->deref();
+}    
+
+float Length::nonNanCalculatedValue(int maxValue) const
+{
+    ASSERT(isCalculated());
+    float result = calculationValue()->evaluate(maxValue);
+    if (isnan(result))
+        return 0;
+    return result;
+}
+
 class SameSizeAsLength {
     int32_t value;
     int32_t metaData;

Modified: trunk/Source/WebCore/platform/Length.h (110147 => 110148)


--- trunk/Source/WebCore/platform/Length.h	2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/Length.h	2012-03-08 06:48:35 UTC (rev 110148)
@@ -26,6 +26,7 @@
 #include <wtf/Assertions.h>
 #include <wtf/FastAllocBase.h>
 #include <wtf/Forward.h>
+#include <wtf/HashMap.h>
 #include <wtf/MathExtras.h>
 #include <wtf/PassOwnArrayPtr.h>
 
@@ -34,8 +35,10 @@
 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
 
-enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Undefined };
-
+enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Calculated, Undefined };
+ 
+class CalculationValue;    
+    
 struct Length {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -65,11 +68,35 @@
         m_floatValue = static_cast<float>(v);    
     }
 
+    explicit Length(PassRefPtr<CalculationValue>);
+
+    Length(const Length& length)
+    {
+        initFromLength(length);
+    }
+    
+    Length& operator=(const Length& length)
+    {
+        initFromLength(length);
+        return *this;
+    }
+    
+    ~Length()
+    {
+        if (isCalculated())
+            decrementCalculatedRef();
+    }  
+    
     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue())); }
     bool operator!=(const Length& o) const { return !(*this == o); }
 
     const Length& operator*=(float v)
-    {        
+    {       
+        if (isCalculated()) {
+            ASSERT_NOT_REACHED();
+            return *this;
+        }
+        
         if (m_isFloat)
             m_floatValue = static_cast<float>(m_floatValue * v);
         else        
@@ -80,6 +107,10 @@
     
     int value() const
     {
+        if (isCalculated()) {
+            ASSERT_NOT_REACHED();
+            return 0;
+        }
         return getIntValue();
     }
 
@@ -89,6 +120,8 @@
         return getFloatValue();
     }
 
+    PassRefPtr<CalculationValue> calculationValue() const;
+
     LengthType type() const { return static_cast<LengthType>(m_type); }
     bool quirk() const { return m_quirk; }
 
@@ -106,6 +139,10 @@
 
     void setValue(int value)
     {
+        if (isCalculated()) {
+            ASSERT_NOT_REACHED();
+            return;
+        }
         setValue(Fixed, value);
     }
 
@@ -121,13 +158,12 @@
         *this = Length(value, Fixed);
     }
 
-    // Note: May only be called for Fixed, Percent and Auto lengths.
-    // Other types will ASSERT in order to catch invalid length calculations.
     int calcValue(int maxValue, bool roundPercentages = false) const
     {
         switch (type()) {
             case Fixed:
             case Percent:
+            case Calculated:
                 return calcMinValue(maxValue, roundPercentages);
             case Auto:
                 return maxValue;
@@ -152,6 +188,8 @@
                     return static_cast<int>(round(maxValue * percent() / 100.0f));
                 // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
                 return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
+            case Calculated:
+                return nonNanCalculatedValue(maxValue);
             case Auto:
                 return 0;
             case Relative:
@@ -174,6 +212,8 @@
                 return static_cast<float>(maxValue * percent() / 100.0f);
             case Auto:
                 return static_cast<float>(maxValue);
+            case Calculated:
+                return nonNanCalculatedValue(maxValue);                
             case Relative:
             case Intrinsic:
             case MinIntrinsic:
@@ -186,21 +226,43 @@
     }
 
     bool isUndefined() const { return type() == Undefined; }
+
+    // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length 
+    // always contains a percentage, and without a maxValue passed to these functions
+    // it's impossible to determine the sign or zero-ness. We assume all calc values
+    // are positive and non-zero for now.    
     bool isZero() const 
     {
         ASSERT(!isUndefined());
+        if (isCalculated())
+            return false;
+            
         return m_isFloat ? !m_floatValue : !m_intValue;
     }
+    bool isPositive() const
+    {
+        if (isUndefined())
+            return false;
+        if (isCalculated())
+            return true;
+                
+        return getFloatValue() > 0;
+    }
+    bool isNegative() const
+    {
+        if (isUndefined() || isCalculated())
+            return false;
+            
+        return getFloatValue() < 0;
+    }
     
-    bool isPositive() const { return isUndefined() ? false : getFloatValue() > 0; }
-    bool isNegative() const { return isUndefined() ? false : getFloatValue() < 0; }
-
     bool isAuto() const { return type() == Auto; }
     bool isRelative() const { return type() == Relative; }
-    bool isPercent() const { return type() == Percent; }
+    bool isPercent() const { return type() == Percent || type() == Calculated; }
     bool isFixed() const { return type() == Fixed; }
     bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
-    bool isSpecified() const { return type() == Fixed || type() == Percent; }
+    bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
+    bool isCalculated() const { return type() == Calculated; }
 
     Length blend(const Length& from, double progress) const
     {
@@ -239,6 +301,30 @@
         return m_isFloat ? m_floatValue : m_intValue;
     }
 
+    void initFromLength(const Length &length) 
+    {
+        m_quirk = length.m_quirk;
+        m_type = length.m_type;
+        m_isFloat = length.m_isFloat;
+        
+        if (m_isFloat)
+            m_floatValue = length.m_floatValue;
+        else
+            m_intValue = length.m_intValue;
+        
+        if (isCalculated())
+            incrementCalculatedRef();
+    }
+    
+    float nonNanCalculatedValue(int maxValue) const;
+    int calculationHandle() const
+    {
+        ASSERT(isCalculated());
+        return getIntValue();
+    }
+    void incrementCalculatedRef() const;
+    void decrementCalculatedRef() const;    
+    
     union {
         int m_intValue;
         float m_floatValue;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to