Source/WebCore: Rework CSS calc logic, fixing some reference count mistakes in Length
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Apr 2014 00:16:35 +0000 (00:16 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 7 Apr 2014 00:16:35 +0000 (00:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=131280
rdar://problem/16400823

Reviewed by Andreas Kling.

New unit test in TestWebKitAPI.

Changed the classes related to CSS "calc" to make the code a bit easier to read by
moving code out of class definitions. Also used final some more, made more things private,
used references instead of pointers, and other such changes. Biggest change, though, is to
Length, which had a broken system for managing reference counted calculated objects.
There were multiple bugs including a basic design mistake of not having a reference count
and trying to use the reference count in the object itself. Fixed and covered by the unit
test now; test found multiple problems in both the old and new implementations.

* WebCore.exp.in: Updated exports, including symbols to make the unit test practical.

* WebCore.xcodeproj/project.pbxproj: Made CalculationValue.h a Private file so it can
be used in a unit test. Also let Xcode update the file type for a gperf file.

* css/CSSCalculationValue.cpp:
(WebCore::CSSCalcValue::equals): Updated since m_expression is a Ref now.
(WebCore::CSSCalcValue::clampToPermittedRange): Marked inline and updated for data member
name change.
(WebCore::isIntegerResult): Changed argument order to put the operator first and use
references instead of pointers. Also marked inline.
(WebCore::createBlendHalf): Added. Helper to make the other functions more readable.
(WebCore::createExpressionNode): Made non-member function private to this file. Also made
many small improvements.
(WebCore::CSSCalcValue::create): Updated so both of these call the same constructor.

* css/CSSCalculationValue.h: Cut down CSSCalcValue class by making more things private
and deleting unneeded things. Also use Ref instead of RefPtr.

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::getPositionOffsetValue): Use isFixed function instead of type function.

* css/CSSGradientValue.cpp:
(WebCore::CSSGradientValue::addStops): Updated code since toCalcValue now returns PassRef
instead of PassRefPtr. Unfortunately the new code is a bit more verbose.
(WebCore::positionFromValue): Ditto.

* css/CSSParser.cpp:
(WebCore::CSSParser::parseCalculation):

* css/CSSPrimitiveValue.cpp:
(WebCore::CSSPrimitiveValue::CSSPrimitiveValue): Updated to pass reference rather than pointer.
(WebCore::CSSPrimitiveValue::init): Ditto.

* css/CSSToStyleMap.h: Removed unneeded include of LengthBox.h.

* css/DeprecatedStyleBuilder.cpp:
(WebCore::ApplyPropertyLength::applyValue): Updated for function name change.
(WebCore::ApplyPropertyBorderRadius::applyValue): Removed extra parentheses.
(WebCore::ApplyPropertyFontSize::applyValue): Ditto. Also updated since toCalcValue returns Ref.

* css/LengthFunctions.cpp:
(WebCore::floatValueForLength): Updated to call value instead of getFloatValue; both are the same.

* css/StyleResolver.cpp:
(WebCore::addIntrinsicMargins): Updated for function name change.
(WebCore::createGridTrackBreadth): Ditto.

* platform/CalculationValue.cpp:
(WebCore::CalculationValue::create): Changed to return PassRef.
(WebCore::CalcExpressionNumber::evaluate): Moved this function out of the header, since it's
virtual and not really going to be inlined.
(WebCore::CalcExpressionNumber::operator==): Ditto.
(WebCore::CalculationValue::evaluate): Ditto.
(WebCore::CalcExpressionBinaryOperation::operator==): Ditto.
(WebCore::CalcExpressionLength::evaluate): Ditto.
(WebCore::CalcExpressionLength::operator==): Ditto.
(WebCore::CalcExpressionBlendLength::evaluate): Ditto.
(WebCore::CalcExpressionBlendLength::operator==): Ditto.

* platform/CalculationValue.h: Moved most functions out of the class bodies so the classes are
easier to see. Made all the == operator functions non-member ones except for the polymorphic
one from the base class. Changed the casting functions to work on references instead of pointers.
Tweaked name of some members.

* platform/Length.cpp: Reworked the CalculationValueMap (formerly CalculationValueHandleMap) to
use unsigned instead of int, and store reference counts in the map rather than trying to share the
reference count of the underlying CalculationValue object, which can lead to storage leaks where
handles end up in the map permanently.
(WebCore::calculationValues): Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL.
(WebCore::Length::Length): Updated some data member names.
(WebCore::Length::calculationValue): Updated to return a reference instead of a PassRefPtr.
(WebCore::Length::ref): Renamed and updated for new interface to the map.
(WebCore::Length::deref): Ditto.
(WebCore::Length::nonNanCalculatedValue): Updated to use a reference instead of a pointer.
(WebCore::Length::isCalculatedEqual): Updated since this is now only called if both objects are
known to be calculated values.

* platform/Length.h: Moved most functions out of the class definition to make the class definition
easier to read. Reworked the constructors and assignment operators to handle the reference counting
correctly. Added various FIXMEs and assertions. Removed some unused functions, made others private.

* platform/LengthBox.h: Renamed some one-letter arguments to use words instead.

* rendering/AutoTableLayout.cpp:
(WebCore::AutoTableLayout::recalcColumn): Updated for change to Length::setValue.
* rendering/FixedTableLayout.cpp:
(WebCore::FixedTableLayout::calcWidthArray): Ditto.

* rendering/style/FillLayer.h:
(WebCore::FillLayer::initialFillXPosition): Updated to not convert a double to a float at runtime.
(WebCore::FillLayer::initialFillYPosition): Ditto.

* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::setWordSpacing): Removed a bogus FALLTHROUGH that was clearly wrong, but
harmless. Updated for changes to Length.

* rendering/style/RenderStyle.h: Updated for name changes and to avoid converting doubles to floats
at runtime.

Tools: Rework CSS calc logic, fixing some reference count mistakes in Length
https://bugs.webkit.org/show_bug.cgi?id=131280

Reviewed by Andreas Kling.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Added CalculationValue.cpp.
* TestWebKitAPI/Tests/WebCore/CalculationValue.cpp: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@166860 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSCalculationValue.cpp
Source/WebCore/css/CSSCalculationValue.h
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSGradientValue.cpp
Source/WebCore/css/CSSParser.cpp
Source/WebCore/css/CSSPrimitiveValue.cpp
Source/WebCore/css/CSSPrimitiveValueMappings.h
Source/WebCore/css/CSSToStyleMap.cpp
Source/WebCore/css/CSSToStyleMap.h
Source/WebCore/css/DeprecatedStyleBuilder.cpp
Source/WebCore/css/LengthFunctions.cpp
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/platform/CalculationValue.cpp
Source/WebCore/platform/CalculationValue.h
Source/WebCore/platform/Length.cpp
Source/WebCore/platform/Length.h
Source/WebCore/platform/LengthBox.h
Source/WebCore/rendering/AutoTableLayout.cpp
Source/WebCore/rendering/FixedTableLayout.cpp
Source/WebCore/rendering/style/FillLayer.h
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp [new file with mode: 0644]

index 1cf1592..5202e97 100644 (file)
@@ -1,3 +1,121 @@
+2014-04-06  Darin Adler  <darin@apple.com>
+
+        Rework CSS calc logic, fixing some reference count mistakes in Length
+        https://bugs.webkit.org/show_bug.cgi?id=131280
+        rdar://problem/16400823
+
+        Reviewed by Andreas Kling.
+
+        New unit test in TestWebKitAPI.
+
+        Changed the classes related to CSS "calc" to make the code a bit easier to read by
+        moving code out of class definitions. Also used final some more, made more things private,
+        used references instead of pointers, and other such changes. Biggest change, though, is to
+        Length, which had a broken system for managing reference counted calculated objects.
+        There were multiple bugs including a basic design mistake of not having a reference count
+        and trying to use the reference count in the object itself. Fixed and covered by the unit
+        test now; test found multiple problems in both the old and new implementations.
+
+        * WebCore.exp.in: Updated exports, including symbols to make the unit test practical.
+
+        * WebCore.xcodeproj/project.pbxproj: Made CalculationValue.h a Private file so it can
+        be used in a unit test. Also let Xcode update the file type for a gperf file.
+
+        * css/CSSCalculationValue.cpp:
+        (WebCore::CSSCalcValue::equals): Updated since m_expression is a Ref now.
+        (WebCore::CSSCalcValue::clampToPermittedRange): Marked inline and updated for data member
+        name change.
+        (WebCore::isIntegerResult): Changed argument order to put the operator first and use
+        references instead of pointers. Also marked inline.
+        (WebCore::createBlendHalf): Added. Helper to make the other functions more readable.
+        (WebCore::createExpressionNode): Made non-member function private to this file. Also made
+        many small improvements.
+        (WebCore::CSSCalcValue::create): Updated so both of these call the same constructor.
+
+        * css/CSSCalculationValue.h: Cut down CSSCalcValue class by making more things private
+        and deleting unneeded things. Also use Ref instead of RefPtr.
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::getPositionOffsetValue): Use isFixed function instead of type function.
+
+        * css/CSSGradientValue.cpp:
+        (WebCore::CSSGradientValue::addStops): Updated code since toCalcValue now returns PassRef
+        instead of PassRefPtr. Unfortunately the new code is a bit more verbose.
+        (WebCore::positionFromValue): Ditto.
+
+        * css/CSSParser.cpp:
+        (WebCore::CSSParser::parseCalculation):
+
+        * css/CSSPrimitiveValue.cpp:
+        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue): Updated to pass reference rather than pointer.
+        (WebCore::CSSPrimitiveValue::init): Ditto.
+
+        * css/CSSToStyleMap.h: Removed unneeded include of LengthBox.h.
+
+        * css/DeprecatedStyleBuilder.cpp:
+        (WebCore::ApplyPropertyLength::applyValue): Updated for function name change.
+        (WebCore::ApplyPropertyBorderRadius::applyValue): Removed extra parentheses.
+        (WebCore::ApplyPropertyFontSize::applyValue): Ditto. Also updated since toCalcValue returns Ref.
+
+        * css/LengthFunctions.cpp:
+        (WebCore::floatValueForLength): Updated to call value instead of getFloatValue; both are the same.
+
+        * css/StyleResolver.cpp:
+        (WebCore::addIntrinsicMargins): Updated for function name change.
+        (WebCore::createGridTrackBreadth): Ditto.
+
+        * platform/CalculationValue.cpp:
+        (WebCore::CalculationValue::create): Changed to return PassRef.
+        (WebCore::CalcExpressionNumber::evaluate): Moved this function out of the header, since it's
+        virtual and not really going to be inlined.
+        (WebCore::CalcExpressionNumber::operator==): Ditto.
+        (WebCore::CalculationValue::evaluate): Ditto.
+        (WebCore::CalcExpressionBinaryOperation::operator==): Ditto.
+        (WebCore::CalcExpressionLength::evaluate): Ditto.
+        (WebCore::CalcExpressionLength::operator==): Ditto.
+        (WebCore::CalcExpressionBlendLength::evaluate): Ditto.
+        (WebCore::CalcExpressionBlendLength::operator==): Ditto.
+
+        * platform/CalculationValue.h: Moved most functions out of the class bodies so the classes are
+        easier to see. Made all the == operator functions non-member ones except for the polymorphic
+        one from the base class. Changed the casting functions to work on references instead of pointers.
+        Tweaked name of some members.
+
+        * platform/Length.cpp: Reworked the CalculationValueMap (formerly CalculationValueHandleMap) to
+        use unsigned instead of int, and store reference counts in the map rather than trying to share the
+        reference count of the underlying CalculationValue object, which can lead to storage leaks where
+        handles end up in the map permanently.
+        (WebCore::calculationValues): Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL.
+        (WebCore::Length::Length): Updated some data member names.
+        (WebCore::Length::calculationValue): Updated to return a reference instead of a PassRefPtr.
+        (WebCore::Length::ref): Renamed and updated for new interface to the map.
+        (WebCore::Length::deref): Ditto.
+        (WebCore::Length::nonNanCalculatedValue): Updated to use a reference instead of a pointer.
+        (WebCore::Length::isCalculatedEqual): Updated since this is now only called if both objects are
+        known to be calculated values.
+
+        * platform/Length.h: Moved most functions out of the class definition to make the class definition
+        easier to read. Reworked the constructors and assignment operators to handle the reference counting
+        correctly. Added various FIXMEs and assertions. Removed some unused functions, made others private.
+
+        * platform/LengthBox.h: Renamed some one-letter arguments to use words instead.
+
+        * rendering/AutoTableLayout.cpp:
+        (WebCore::AutoTableLayout::recalcColumn): Updated for change to Length::setValue.
+        * rendering/FixedTableLayout.cpp:
+        (WebCore::FixedTableLayout::calcWidthArray): Ditto.
+
+        * rendering/style/FillLayer.h:
+        (WebCore::FillLayer::initialFillXPosition): Updated to not convert a double to a float at runtime.
+        (WebCore::FillLayer::initialFillYPosition): Ditto.
+
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::setWordSpacing): Removed a bogus FALLTHROUGH that was clearly wrong, but
+        harmless. Updated for changes to Length.
+
+        * rendering/style/RenderStyle.h: Updated for name changes and to avoid converting doubles to floats
+        at runtime.
+
 2014-04-06  Brent Fulgham  <bfulgham@apple.com>
 
         Honor System-Level User Preferences for Caption Display
index 5a74e85..27a4fb3 100644 (file)
@@ -649,6 +649,7 @@ __ZN7WebCore15visitedLinkHashERKN3WTF6StringE
 __ZN7WebCore16ApplicationCache18diskUsageForOriginEPNS_14SecurityOriginE
 __ZN7WebCore16ApplicationCache20deleteCacheForOriginEPNS_14SecurityOriginE
 __ZN7WebCore16CSSParserContextC1ERNS_8DocumentERKNS_3URLERKN3WTF6StringE
+__ZN7WebCore16CalculationValue6createENSt3__110unique_ptrINS_18CalcExpressionNodeENS1_14default_deleteIS3_EEEENS_30CalculationPermittedValueRangeE
 __ZN7WebCore16DatabaseStrategy17getDatabaseServerEv
 __ZN7WebCore16DatabaseStrategy23createIDBFactoryBackendERKN3WTF6StringE
 __ZN7WebCore16DeviceMotionData12Acceleration6createEbdbdbd
@@ -1172,6 +1173,7 @@ __ZN7WebCore6Editor7commandERKN3WTF6StringE
 __ZN7WebCore6Editor7copyURLERKNS_3URLERKN3WTF6StringE
 __ZN7WebCore6Editor7outdentEv
 __ZN7WebCore6JSNode6s_infoE
+__ZN7WebCore6LengthC1EN3WTF7PassRefINS_16CalculationValueEEE
 __ZN7WebCore6Region21updateBoundsFromShapeEv
 __ZN7WebCore6Region5uniteERKS0_
 __ZN7WebCore6Region8subtractERKS0_
@@ -1855,8 +1857,8 @@ __ZNK7WebCore6Editor7canCopyEv
 __ZNK7WebCore6Editor7canEditEv
 __ZNK7WebCore6Editor8canPasteEv
 __ZNK7WebCore6Editor9canDeleteEv
-__ZNK7WebCore6Length22decrementCalculatedRefEv
-__ZNK7WebCore6Length22incrementCalculatedRefEv
+__ZNK7WebCore6Length3refEv
+__ZNK7WebCore6Length5derefEv
 __ZNK7WebCore6Region5Shape7isValidEv
 __ZNK7WebCore6Region5rectsEv
 __ZNK7WebCore6Region8containsERKS0_
index 60559ed..9df6ab3 100644 (file)
                49AE2D8E134EE50C0072920A /* CSSCalculationValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49AE2D8C134EE50C0072920A /* CSSCalculationValue.cpp */; };
                49AE2D8F134EE50C0072920A /* CSSCalculationValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 49AE2D8D134EE50C0072920A /* CSSCalculationValue.h */; };
                49AE2D96134EE5F90072920A /* CalculationValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49AE2D94134EE5F90072920A /* CalculationValue.cpp */; };
-               49AE2D97134EE5F90072920A /* CalculationValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 49AE2D95134EE5F90072920A /* CalculationValue.h */; };
+               49AE2D97134EE5F90072920A /* CalculationValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 49AE2D95134EE5F90072920A /* CalculationValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                49AF2D6914435D050016A784 /* DisplayRefreshMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 49AF2D6814435D050016A784 /* DisplayRefreshMonitor.h */; settings = {ATTRIBUTES = (Private, ); }; };
                49AF2D6C14435D210016A784 /* DisplayRefreshMonitorMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49AF2D6B14435D210016A784 /* DisplayRefreshMonitorMac.cpp */; };
                49B3760C15C6C6840059131D /* ArrayValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49B3760A15C6C6840059131D /* ArrayValue.cpp */; };
                43A6266613B3D11000AC94B8 /* SVGAnimatedString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimatedString.cpp; sourceTree = "<group>"; };
                43B85ED018CBEACE00E31AF4 /* makeSelectorPseudoClassAndCompatibilityElementMap.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = makeSelectorPseudoClassAndCompatibilityElementMap.py; sourceTree = "<group>"; };
                43B85ED218CBEC5200E31AF4 /* SelectorPseudoClassAndCompatibilityElementMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SelectorPseudoClassAndCompatibilityElementMap.cpp; sourceTree = "<group>"; };
-               43B85ED318CBEC5200E31AF4 /* SelectorPseudoClassAndCompatibilityElementMap.gperf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file; path = SelectorPseudoClassAndCompatibilityElementMap.gperf; sourceTree = "<group>"; };
+               43B85ED318CBEC5200E31AF4 /* SelectorPseudoClassAndCompatibilityElementMap.gperf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SelectorPseudoClassAndCompatibilityElementMap.gperf; sourceTree = "<group>"; };
                43B85ED618CBEC9700E31AF4 /* SelectorPseudoClassAndCompatibilityElementMap.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SelectorPseudoClassAndCompatibilityElementMap.in; sourceTree = "<group>"; };
                43B9336713B261B1004584BF /* SVGAnimatedPointList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGAnimatedPointList.h; sourceTree = "<group>"; };
                43B9336813B261B1004584BF /* SVGAnimatedPointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGAnimatedPointList.cpp; sourceTree = "<group>"; };
index 50e530d..96f8c44 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
 #include "CSSCalculationValue.h"
 
 #include "CSSPrimitiveValueMappings.h"
-#include "CSSValueList.h"
-#include "Length.h"
 #include "StyleResolver.h"
-
 #include <wtf/MathExtras.h>
 #include <wtf/text/StringBuilder.h>
 
@@ -49,6 +47,9 @@ enum ParseState {
 
 namespace WebCore {
 
+static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&);
+static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&);
+
 static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
 {
     switch (type) {
@@ -157,12 +158,12 @@ String CSSCalcValue::customCSSText() const
 
 bool CSSCalcValue::equals(const CSSCalcValue& other) const
 {
-    return compareCSSValuePtr(m_expression, other.m_expression);
+    return compareCSSValue(m_expression, other.m_expression);
 }
 
-double CSSCalcValue::clampToPermittedRange(double value) const
+inline double CSSCalcValue::clampToPermittedRange(double value) const
 {
-    return m_nonNegative && value < 0 ? 0 : value;
+    return m_shouldClampToNonNegative && value < 0 ? 0 : value;
 }
 
 double CSSCalcValue::doubleValue() const
@@ -175,39 +176,35 @@ double CSSCalcValue::computeLengthPx(const RenderStyle* currentStyle, const Rend
     return clampToPermittedRange(m_expression->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize));
 }
 
-CSSCalcExpressionNode::~CSSCalcExpressionNode()
-{
-}
-
-class CSSCalcPrimitiveValue : public CSSCalcExpressionNode {
+class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-
-    static PassRefPtr<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
+    static PassRef<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
     {
-        return adoptRef(new CSSCalcPrimitiveValue(value, 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 nullptr;
         return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger));
     }
 
-    virtual bool isZero() const
+private:
+    virtual bool isZero() const override
     {
         return !m_value->getDoubleValue();
     }
 
-    virtual String customCSSText() const
+    virtual String customCSSText() const override
     {
         return m_value->cssText();
     }
 
-    virtual std::unique_ptr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const
+    virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const override
     {
-        switch (m_category) {
+        switch (category()) {
         case CalcNumber:
             return std::make_unique<CalcExpressionNumber>(m_value->getFloatValue());
         case CalcLength:
@@ -227,7 +224,7 @@ public:
         return nullptr;
     }
 
-    virtual double doubleValue() const
+    virtual double doubleValue() const override
     {
         if (hasDoubleValue(primitiveType()))
             return m_value->getDoubleValue();
@@ -235,9 +232,9 @@ public:
         return 0;
     }
 
-    virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const
+    virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const override
     {
-        switch (m_category) {
+        switch (category()) {
         case CalcLength:
             return m_value->computeLength<double>(currentStyle, rootStyle, multiplier, computingFontSize);
         case CalcPercent:
@@ -253,7 +250,7 @@ public:
         return 0;
     }
 
-    virtual bool equals(const CSSCalcExpressionNode& other) const
+    virtual bool equals(const CSSCalcExpressionNode& other) const override
     {
         if (type() != other.type())
             return false;
@@ -261,8 +258,8 @@ public:
         return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
     }
 
-    virtual Type type() const { return CssCalcPrimitiveValue; }
-    virtual CSSPrimitiveValue::UnitTypes primitiveType() const
+    virtual Type type() const override { return CssCalcPrimitiveValue; }
+    virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
     {
         return CSSPrimitiveValue::UnitTypes(m_value->primitiveType());
     }
@@ -312,40 +309,40 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi
     return CalcOther;
 }
 
-static bool isIntegerResult(const CSSCalcExpressionNode* leftSide, const CSSCalcExpressionNode* rightSide, CalcOperator op)
+static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
 {
     // 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();
+    return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger();
 }
 
-class CSSCalcBinaryOperation : public CSSCalcExpressionNode {
-
+class CSSCalcBinaryOperation final : public CSSCalcExpressionNode {
+    WTF_MAKE_FAST_ALLOCATED;
 public:
-    static PassRefPtr<CSSCalcExpressionNode> create(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
+    static PassRefPtr<CSSCalcBinaryOperation> create(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
     {
         ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther);
 
         CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op);
 
         if (newCategory == CalcOther)
-            return 0;
+            return nullptr;
 
-        return adoptRef(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory));
+        return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide, rightSide));
     }
 
-    static PassRefPtr<CSSCalcExpressionNode> createSimplified(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
+    static PassRefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
     {
         CalculationCategory leftCategory = leftSide->category();
         CalculationCategory rightCategory = rightSide->category();
         ASSERT(leftCategory != CalcOther && rightCategory != CalcOther);
 
-        bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op);
+        bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
 
         // 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);
+            return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), evaluationType, isInteger);
         }
 
         // Simplify addition and subtraction between same types.
@@ -355,14 +352,14 @@ public:
                 if (hasDoubleValue(leftType)) {
                     CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType();
                     if (leftType == rightType)
-                        return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger);
+                        return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), 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);
+                            return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger);
                         }
                     }
                 }
@@ -370,49 +367,50 @@ public:
         } else {
             // Simplify multiplying or dividing by a number for simplifiable types.
             ASSERT(op == CalcMultiply || op == CalcDivide);
-            CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get());
+            CSSCalcExpressionNode* numberSide = getNumberSide(*leftSide, *rightSide);
             if (!numberSide)
-                return create(leftSide, rightSide, op);
+                return create(op, leftSide, rightSide);
             if (numberSide == leftSide && op == CalcDivide)
-                return 0;
+                return nullptr;
             CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get();
 
             double number = numberSide->doubleValue();
             if (std::isnan(number) || std::isinf(number))
-                return 0;
+                return nullptr;
             if (op == CalcDivide && !number)
-                return 0;
+                return nullptr;
 
             CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType();
             if (hasDoubleValue(otherType))
-                return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger);
+                return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide->doubleValue(), number), otherType, isInteger);
         }
 
-        return create(leftSide, rightSide, op);
+        return create(op, leftSide, rightSide);
     }
 
-    virtual bool isZero() const
+private:
+    virtual bool isZero() const override
     {
         return !doubleValue();
     }
 
-    virtual std::unique_ptr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const
+    virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const override
     {
-        std::unique_ptr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom));
+        std::unique_ptr<CalcExpressionNode> left(m_leftSide->createCalcExpression(style, rootStyle, zoom));
         if (!left)
             return nullptr;
-        std::unique_ptr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom));
+        std::unique_ptr<CalcExpressionNode> right(m_rightSide->createCalcExpression(style, rootStyle, zoom));
         if (!right)
             return nullptr;
         return std::make_unique<CalcExpressionBinaryOperation>(std::move(left), std::move(right), m_operator);
     }
 
-    virtual double doubleValue() const
+    virtual double doubleValue() const override
     {
         return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
     }
 
-    virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const
+    virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const override
     {
         const double leftValue = m_leftSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize);
         const double rightValue = m_rightSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize);
@@ -433,13 +431,12 @@ public:
         return result.toString();
     }
 
-    virtual String customCSSText() const
+    virtual String customCSSText() const override
     {
         return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
     }
 
-
-    virtual bool equals(const CSSCalcExpressionNode& exp) const
+    virtual bool equals(const CSSCalcExpressionNode& exp) const override
     {
         if (type() != exp.type())
             return false;
@@ -450,14 +447,14 @@ public:
             && m_operator == other.m_operator;
     }
 
-    virtual Type type() const { return CssCalcBinaryOperation; }
+    virtual Type type() const override { return CssCalcBinaryOperation; }
 
-    virtual CSSPrimitiveValue::UnitTypes primitiveType() const
+    virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
     {
-        switch (m_category) {
+        switch (category()) {
         case CalcNumber:
             ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
-            if (m_isInteger)
+            if (isInteger())
                 return CSSPrimitiveValue::CSS_PARSER_INTEGER;
             return CSSPrimitiveValue::CSS_NUMBER;
         case CalcLength:
@@ -480,30 +477,29 @@ public:
         return CSSPrimitiveValue::CSS_UNKNOWN;
     }
 
-private:
-    CSSCalcBinaryOperation(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op, CalculationCategory category)
-        : CSSCalcExpressionNode(category, isIntegerResult(leftSide.get(), rightSide.get(), op))
+    CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
+        : CSSCalcExpressionNode(category, isIntegerResult(op, *leftSide, *rightSide))
         , m_leftSide(leftSide)
         , m_rightSide(rightSide)
         , m_operator(op)
     {
     }
 
-    static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode* leftSide, CSSCalcExpressionNode* rightSide)
+    static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
     {
-        if (leftSide->category() == CalcNumber)
-            return leftSide;
-        if (rightSide->category() == CalcNumber)
-            return rightSide;
-        return 0;
+        if (leftSide.category() == CalcNumber)
+            return &leftSide;
+        if (rightSide.category() == CalcNumber)
+            return &rightSide;
+        return nullptr;
     }
 
     double evaluate(double leftSide, double rightSide) const
     {
-        return evaluateOperator(leftSide, rightSide, m_operator);
+        return evaluateOperator(m_operator, leftSide, rightSide);
     }
 
-    static double evaluateOperator(double leftValue, double rightValue, CalcOperator op)
+    static double evaluateOperator(CalcOperator op, double leftValue, double rightValue)
     {
         switch (op) {
         case CalcAdd:
@@ -517,6 +513,7 @@ private:
                 return leftValue / rightValue;
             return std::numeric_limits<double>::quiet_NaN();
         }
+        ASSERT_NOT_REACHED();
         return 0;
     }
 
@@ -544,7 +541,7 @@ public:
         bool ok = parseValueExpression(tokens, 0, &index, &result);
         ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size());
         if (!ok || index != tokens->size())
-            return 0;
+            return nullptr;
         return result.value;
     }
 
@@ -618,7 +615,7 @@ private:
             if (!parseValueTerm(tokens, depth, index, &rhs))
                 return false;
 
-            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
+            result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
             if (!result->value)
                 return false;
         }
@@ -645,7 +642,7 @@ private:
             if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs))
                 return false;
 
-            result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
+            result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
             if (!result->value)
                 return false;
         }
@@ -660,54 +657,40 @@ 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)
+static inline PassRefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
 {
-    return CSSCalcBinaryOperation::create(leftSide, rightSide, op);
+    return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style),
+        CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
 }
 
-PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const CalcExpressionNode* node, const RenderStyle* style)
+static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style)
 {
-    switch (node->type()) {
+    switch (node.type()) {
     case CalcExpressionNodeNumber: {
-        float value = toCalcExpressionNumber(node)->value();
-        return createExpressionNode(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == trunc(value));
+        float value = toCalcExpressionNumber(node).value();
+        return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == truncf(value));
     }
     case CalcExpressionNodeLength:
-        return createExpressionNode(toCalcExpressionLength(node)->length(), style);
+        return createCSS(toCalcExpressionLength(node).length(), style);
     case CalcExpressionNodeBinaryOperation: {
-        const CalcExpressionBinaryOperation* binaryNode = toCalcExpressionBinaryOperation(node);
-        return createExpressionNode(createExpressionNode(binaryNode->leftSide(), style), createExpressionNode(binaryNode->rightSide(), style), binaryNode->getOperator());
+        auto& binaryNode = toCalcExpressionBinaryOperation(node);
+        return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style));
     }
     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);
+        auto& blend = toCalcExpressionBlendLength(node);
+        float progress = blend.progress();
+        return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
     }
     case CalcExpressionNodeUndefined:
         ASSERT_NOT_REACHED();
-        return 0;
+        return nullptr;
     }
     ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const Length& length, const RenderStyle* style)
+static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style)
 {
     switch (length.type()) {
     case Percent:
@@ -716,9 +699,9 @@ PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const Lengt
     case ViewportPercentageMin:
     case ViewportPercentageMax:
     case Fixed:
-        return createExpressionNode(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value()));
+        return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, &style), length.value() == trunc(length.value()));
     case Calculated:
-        return createExpressionNode(length.calculationValue()->expression(), style);
+        return createCSS(length.calculationValue().expression(), style);
     case Auto:
     case Intrinsic:
     case MinIntrinsic:
@@ -729,27 +712,30 @@ PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const Lengt
     case Relative:
     case Undefined:
         ASSERT_NOT_REACHED();
-        return 0;
+        return nullptr;
     }
     ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
-PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range)
+PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList& parserValueList, CalculationPermittedValueRange range)
 {
     CSSCalcExpressionNodeParser parser;
     RefPtr<CSSCalcExpressionNode> expression;
 
     if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc("))
-        expression = parser.parseCalc(parserValueList);
+        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;
+    return expression ? adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != CalculationRangeAll)) : nullptr;
 }
 
-PassRef<CSSCalcValue> CSSCalcValue::create(PassRefPtr<CSSCalcExpressionNode> expression, CalculationPermittedValueRange range)
+PassRefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style)
 {
-    return adoptRef(*new CSSCalcValue(expression, range));
+    RefPtr<CSSCalcExpressionNode> expression = createCSS(value.expression(), style);
+    if (!expression)
+        return nullptr;
+    return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative()));
 }
 
 } // namespace WebCore
index 041c7b3..07e4208 100644 (file)
 
 #include "CSSParserValues.h"
 #include "CSSPrimitiveValue.h"
-#include "CSSValue.h"
 #include "CalculationValue.h"
-#include <memory>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
 
 namespace WebCore {
 
-class CSSParserValueList;
-class CSSValueList;
-class CalculationValue;
-class CalcExpressionNode;
 class RenderStyle;
-struct Length;
 
 enum CalculationCategory {
     CalcNumber = 0,
@@ -64,17 +55,17 @@ public:
         CssCalcBinaryOperation
     };
 
-    virtual ~CSSCalcExpressionNode() = 0;
+    virtual ~CSSCalcExpressionNode() { }
     virtual bool isZero() const = 0;
-    virtual std::unique_ptr<CalcExpressionNode> toCalcValue(const RenderStyle*, const RenderStyle* rootStyle, double zoom = 1.0) const = 0;
+    virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(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;
     virtual bool equals(const CSSCalcExpressionNode& other) const { return m_category == other.m_category && m_isInteger == other.m_isInteger; }
     virtual Type type() const = 0;
+    virtual CSSPrimitiveValue::UnitTypes primitiveType() const = 0;
 
     CalculationCategory category() const { return m_category; }
-    virtual CSSPrimitiveValue::UnitTypes primitiveType() const = 0;
     bool isInteger() const { return m_isInteger; }
 
 protected:
@@ -84,56 +75,49 @@ protected:
     {
     }
 
+private:
     CalculationCategory m_category;
     bool m_isInteger;
 };
 
 class CSSCalcValue : public CSSValue {
 public:
-    static PassRefPtr<CSSCalcValue> create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange);
-    static PassRef<CSSCalcValue> create(PassRefPtr<CSSCalcExpressionNode>, CalculationPermittedValueRange = CalculationRangeAll);
-    static PassRef<CSSCalcValue> create(const CalculationValue* value, const RenderStyle* style) { return adoptRef(*new CSSCalcValue(value, style)); }
+    static PassRefPtr<CSSCalcValue> create(CSSParserString name, CSSParserValueList& arguments, CalculationPermittedValueRange);
+    static PassRefPtr<CSSCalcValue> create(const CalculationValue&, const RenderStyle&);
 
-    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(); }
     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(); }
+
+    PassRef<CalculationValue> createCalculationValue(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double zoom = 1.0) const;
 
     String customCSSText() const;
     bool equals(const CSSCalcValue&) const;
 
 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())
-    {
-    }
+    CSSCalcValue(PassRef<CSSCalcExpressionNode>, bool shouldClampToNonNegative);
 
     double clampToPermittedRange(double) const;
 
-    const RefPtr<CSSCalcExpressionNode> m_expression;
-    const bool m_nonNegative;
+    const Ref<CSSCalcExpressionNode> m_expression;
+    const bool m_shouldClampToNonNegative;
 };
 
+inline CSSCalcValue::CSSCalcValue(PassRef<CSSCalcExpressionNode> expression, bool shouldClampToNonNegative)
+    : CSSValue(CalculationClass)
+    , m_expression(std::move(expression))
+    , m_shouldClampToNonNegative(shouldClampToNonNegative)
+{
+}
+
+inline PassRef<CalculationValue> CSSCalcValue::createCalculationValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const
+{
+    return CalculationValue::create(m_expression->createCalcExpression(style, rootStyle, zoom),
+        m_shouldClampToNonNegative ? CalculationRangeNonNegative : CalculationRangeAll);
+}
+
 CSS_VALUE_TYPE_CASTS(CSSCalcValue, isCalcValue())
 
 } // namespace WebCore
index 484c3d9..c29983a 100644 (file)
@@ -677,9 +677,9 @@ static PassRefPtr<CSSValue> getPositionOffsetValue(RenderStyle* style, CSSProper
     }
 
     if (style->hasOutOfFlowPosition()) {
-        if (l.type() == WebCore::Fixed)
+        if (l.isFixed())
             return zoomAdjustedPixelValue(l.value(), style);
-        else if (l.isViewportPercentage())
+        if (l.isViewportPercentage())
             return zoomAdjustedPixelValue(valueForLength(l, 0, renderView), style);
         return cssValuePool().createValue(l);
     }
index d179ded..69c0066 100644 (file)
@@ -182,8 +182,10 @@ void CSSGradientValue::addStops(Gradient* gradient, RenderElement* renderer, con
                 float length;
                 if (stop.m_position->isLength())
                     length = stop.m_position->computeLength<float>(&style, &rootStyle, style.effectiveZoom());
-                else 
-                    length = stop.m_position->cssCalcValue()->toCalcValue(&style, &rootStyle, style.effectiveZoom())->evaluate(gradientLength);
+                else {
+                    Ref<CalculationValue> calculationValue { stop.m_position->cssCalcValue()->createCalculationValue(&style, &rootStyle, style.effectiveZoom()) };
+                    length = calculationValue->evaluate(gradientLength);
+                }
                 stops[i].offset = (gradientLength > 0) ? length / gradientLength : 0;
             } else {
                 ASSERT_NOT_REACHED();
@@ -401,8 +403,10 @@ static float positionFromValue(CSSPrimitiveValue* value, const RenderStyle& styl
     if (value->isPercentage())
         return value->getFloatValue() / 100.f * edgeDistance;
 
-    if (value->isCalculatedPercentageWithLength())
-        return value->cssCalcValue()->toCalcValue(&style, &rootStyle, style.effectiveZoom())->evaluate(edgeDistance);
+    if (value->isCalculatedPercentageWithLength()) {
+        Ref<CalculationValue> calculationValue { value->cssCalcValue()->createCalculationValue(&style, &rootStyle, style.effectiveZoom()) };
+        return calculationValue->evaluate(edgeDistance);
+    }
 
     switch (value->getValueID()) {
     case CSSValueTop:
index bd74bf6..e88fb39 100644 (file)
@@ -9569,7 +9569,7 @@ bool CSSParser::parseCalculation(CSSParserValue* value, CalculationPermittedValu
         return false;
 
     ASSERT(!m_parsedCalculation);
-    m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
+    m_parsedCalculation = CSSCalcValue::create(value->function->name, *args, range);
     
     if (!m_parsedCalculation)
         return false;
index 864ec63..f2280cd 100644 (file)
@@ -305,15 +305,16 @@ CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle* st
         m_value.num = adjustFloatForAbsoluteZoom(length.value(), style);
         return;
     case Calculated: {
-        RefPtr<CSSCalcValue> calcValue = CSSCalcValue::create(length.calculationValue().get(), style);
+        RefPtr<CSSCalcValue> calcValue = CSSCalcValue::create(length.calculationValue(), *style);
         init(calcValue.release());
         return;
     }
     case Relative:
     case Undefined:
         ASSERT_NOT_REACHED();
-        break;
+        return;
     }
+    ASSERT_NOT_REACHED();
 }
 
 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize)
@@ -328,62 +329,63 @@ void CSSPrimitiveValue::init(const Length& length)
     case Auto:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueAuto;
-        break;
+        return;
     case WebCore::Fixed:
         m_primitiveUnitType = CSS_PX;
         m_value.num = length.value();
-        break;
+        return;
     case Intrinsic:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueIntrinsic;
-        break;
+        return;
     case MinIntrinsic:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueMinIntrinsic;
-        break;
+        return;
     case MinContent:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueWebkitMinContent;
-        break;
+        return;
     case MaxContent:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueWebkitMaxContent;
-        break;
+        return;
     case FillAvailable:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueWebkitFillAvailable;
-        break;
+        return;
     case FitContent:
         m_primitiveUnitType = CSS_VALUE_ID;
         m_value.valueID = CSSValueWebkitFitContent;
-        break;
+        return;
     case Percent:
         m_primitiveUnitType = CSS_PERCENTAGE;
         ASSERT(std::isfinite(length.percent()));
         m_value.num = length.percent();
-        break;
+        return;
     case ViewportPercentageWidth:
         m_primitiveUnitType = CSS_VW;
         m_value.num = length.viewportPercentageLength();
-        break;
+        return;
     case ViewportPercentageHeight:
         m_primitiveUnitType = CSS_VH;
         m_value.num = length.viewportPercentageLength();
-        break;
+        return;
     case ViewportPercentageMin:
         m_primitiveUnitType = CSS_VMIN;
         m_value.num = length.viewportPercentageLength();
-        break;
+        return;
     case ViewportPercentageMax:
         m_primitiveUnitType = CSS_VMAX;
         m_value.num = length.viewportPercentageLength();
-        break;
+        return;
     case Calculated:
     case Relative:
     case Undefined:
         ASSERT_NOT_REACHED();
-        break;
+        return;
     }
+    ASSERT_NOT_REACHED();
 }
 
 void CSSPrimitiveValue::init(const LengthSize& lengthSize)
index f4ce031..b5b7c31 100644 (file)
@@ -4646,7 +4646,7 @@ template<int supported> Length CSSPrimitiveValue::convertToLength(const RenderSt
     if ((supported & AutoConversion) && getValueID() == CSSValueAuto)
         return Length(Auto);
     if ((supported & CalculatedConversion) && isCalculated())
-        return Length(cssCalcValue()->toCalcValue(style, rootStyle, multiplier));
+        return Length(cssCalcValue()->createCalculationValue(style, rootStyle, multiplier));
     if ((supported & ViewportPercentageConversion) && isViewportPercentageLength())
         return viewportPercentageLength();
     return Length(Undefined);
index 988cd83..46931e5 100644 (file)
@@ -251,7 +251,7 @@ void CSSToStyleMap::mapFillXPosition(CSSPropertyID propertyID, FillLayer* layer,
     else if (primitiveValue->isPercentage())
         length = Length(primitiveValue->getDoubleValue(), Percent);
     else if (primitiveValue->isCalculatedPercentageWithLength())
-        length = Length(primitiveValue->cssCalcValue()->toCalcValue(style(), rootElementStyle(), zoomFactor));
+        length = Length(primitiveValue->cssCalcValue()->createCalculationValue(style(), rootElementStyle(), zoomFactor));
     else if (primitiveValue->isViewportPercentageLength())
         length = primitiveValue->viewportPercentageLength();
     else
@@ -287,7 +287,7 @@ void CSSToStyleMap::mapFillYPosition(CSSPropertyID propertyID, FillLayer* layer,
     else if (primitiveValue->isPercentage())
         length = Length(primitiveValue->getDoubleValue(), Percent);
     else if (primitiveValue->isCalculatedPercentageWithLength())
-        length = Length(primitiveValue->cssCalcValue()->toCalcValue(style(), rootElementStyle(), zoomFactor));
+        length = Length(primitiveValue->cssCalcValue()->createCalculationValue(style(), rootElementStyle(), zoomFactor));
     else if (primitiveValue->isViewportPercentageLength())
         length = primitiveValue->viewportPercentageLength();
     else
index 1a13d83..617dfad 100644 (file)
 #define CSSToStyleMap_h
 
 #include "CSSPropertyNames.h"
-#include "LengthBox.h"
 #include <wtf/FastMalloc.h>
 #include <wtf/Noncopyable.h>
 
 namespace WebCore {
 
-class FillLayer;
-class CSSValue;
 class Animation;
+class CSSValue;
+class FillLayer;
 class RenderStyle;
 class StyleImage;
 class StyleResolver;
 class NinePieceImage;
 
+struct LengthBox;
+
 class CSSToStyleMap {
     WTF_MAKE_NONCOPYABLE(CSSToStyleMap);
     WTF_MAKE_FAST_ALLOCATED;
index 2007598..a2cdd7a 100644 (file)
@@ -388,12 +388,12 @@ public:
             setValue(styleResolver->style(), Length());
         else if (primitiveValue->isLength()) {
             Length length = primitiveValue->computeLength<Length>(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom());
-            length.setQuirk(primitiveValue->isQuirkValue());
+            length.setHasQuirk(primitiveValue->isQuirkValue());
             setValue(styleResolver->style(), length);
         } else if (primitiveValue->isPercentage())
             setValue(styleResolver->style(), Length(primitiveValue->getDoubleValue(), Percent));
         else if (primitiveValue->isCalculatedPercentageWithLength())
-            setValue(styleResolver->style(), Length(primitiveValue->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())));
+            setValue(styleResolver->style(), Length(primitiveValue->cssCalcValue()->createCalculationValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())));
         else if (primitiveValue->isViewportPercentageLength())
             setValue(styleResolver->style(), primitiveValue->viewportPercentageLength());
     }
@@ -449,7 +449,7 @@ public:
         else if (pair->first()->isViewportPercentageLength())
             radiusWidth = Length(styleResolver->viewportPercentageValue(*pair->first(), pair->first()->getIntValue()), Fixed);
         else if (pair->first()->isCalculatedPercentageWithLength())
-            radiusWidth = Length((pair->first()->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())));
+            radiusWidth = Length(pair->first()->cssCalcValue()->createCalculationValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()));
         else
             radiusWidth = pair->first()->computeLength<Length>(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom());
         if (pair->second()->isPercentage())
@@ -457,7 +457,7 @@ public:
         else if (pair->second()->isViewportPercentageLength())
             radiusHeight = Length(styleResolver->viewportPercentageValue(*pair->second(), pair->second()->getIntValue()), Fixed);
         else if (pair->second()->isCalculatedPercentageWithLength())
-            radiusHeight = Length((pair->second()->cssCalcValue()->toCalcValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom())));
+            radiusHeight = Length(pair->second()->cssCalcValue()->createCalculationValue(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom()));
         else
             radiusHeight = pair->second()->computeLength<Length>(styleResolver->style(), styleResolver->rootElementStyle(), styleResolver->style()->effectiveZoom());
         int width = radiusWidth.value();
@@ -883,9 +883,10 @@ public:
                 size = primitiveValue->computeLength<float>(styleResolver->parentStyle(), styleResolver->rootElementStyle(), 1.0, true);
             else if (primitiveValue->isPercentage())
                 size = (primitiveValue->getFloatValue() * parentSize) / 100.0f;
-            else if (primitiveValue->isCalculatedPercentageWithLength())
-                size = primitiveValue->cssCalcValue()->toCalcValue(styleResolver->parentStyle(), styleResolver->rootElementStyle())->evaluate(parentSize);
-            else if (primitiveValue->isViewportPercentageLength())
+            else if (primitiveValue->isCalculatedPercentageWithLength()) {
+                Ref<CalculationValue> calculationValue { primitiveValue->cssCalcValue()->createCalculationValue(styleResolver->parentStyle(), styleResolver->rootElementStyle()) };
+                size = calculationValue->evaluate(parentSize);
+            } else if (primitiveValue->isViewportPercentageLength())
                 size = valueForLength(primitiveValue->viewportPercentageLength(), 0, styleResolver->document().renderView());
             else
                 return;
index 5749c89..bd67b10 100644 (file)
@@ -122,7 +122,7 @@ float floatValueForLength(const Length& length, LayoutUnit maximumValue, RenderV
 {
     switch (length.type()) {
     case Fixed:
-        return length.getFloatValue();
+        return length.value();
     case Percent:
         return static_cast<float>(maximumValue * length.percent() / 100.0f);
     case FillAvailable:
@@ -168,7 +168,7 @@ float floatValueForLength(const Length& length, float maximumValue, RenderView*
 {
     switch (length.type()) {
     case Fixed:
-        return length.getFloatValue();
+        return length.value();
     case Percent:
         return static_cast<float>(maximumValue * length.percent() / 100.0f);
     case FillAvailable:
index fe90de4..1da838b 100644 (file)
@@ -1041,18 +1041,18 @@ static void addIntrinsicMargins(RenderStyle& style)
     const int intrinsicMargin = 2 * style.effectiveZoom();
 
     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
-    // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
+    // FIXME: Using "hasQuirk" to decide the margin wasn't set is kind of lame.
     if (style.width().isIntrinsicOrAuto()) {
-        if (style.marginLeft().quirk())
+        if (style.marginLeft().hasQuirk())
             style.setMarginLeft(Length(intrinsicMargin, Fixed));
-        if (style.marginRight().quirk())
+        if (style.marginRight().hasQuirk())
             style.setMarginRight(Length(intrinsicMargin, Fixed));
     }
 
     if (style.height().isAuto()) {
-        if (style.marginTop().quirk())
+        if (style.marginTop().hasQuirk())
             style.setMarginTop(Length(intrinsicMargin, Fixed));
-        if (style.marginBottom().quirk())
+        if (style.marginBottom().hasQuirk())
             style.setMarginBottom(Length(intrinsicMargin, Fixed));
     }
 }
@@ -1860,7 +1860,7 @@ static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const Styl
         return false;
 
     if (primitiveValue->isLength())
-        workingLength.length().setQuirk(primitiveValue->isQuirkValue());
+        workingLength.length().setHasQuirk(primitiveValue->isQuirkValue());
 
     return true;
 }
index d80aabc..8d965b0 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011 Google Inc. All rights reserved.
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
 
 namespace WebCore {
 
+PassRef<CalculationValue> CalculationValue::create(std::unique_ptr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+{
+    return adoptRef(*new CalculationValue(std::move(value), range));
+}
+
+float CalcExpressionNumber::evaluate(float) const
+{
+    return m_value;
+}
+
+bool CalcExpressionNumber::operator==(const CalcExpressionNode& other) const
+{
+    return other.type() == CalcExpressionNodeNumber && *this == toCalcExpressionNumber(other);
+}
+
+float CalculationValue::evaluate(float maxValue) const
+{
+    float result = m_expression->evaluate(maxValue);
+    // FIXME: This test was originally needed when we did not detect division by zero at parse time.
+    // It's possible that this is now unneeded code and can be removed.
+    if (std::isnan(result))
+        return 0;
+    return m_shouldClampToNonNegative && result < 0 ? 0 : result;
+}
+
 float CalcExpressionBinaryOperation::evaluate(float maxValue) const
 {
     float left = m_leftSide->evaluate(maxValue);
@@ -55,19 +81,29 @@ float CalcExpressionBinaryOperation::evaluate(float maxValue) const
     return std::numeric_limits<float>::quiet_NaN();
 }
 
-PassRefPtr<CalculationValue> CalculationValue::create(std::unique_ptr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+bool CalcExpressionBinaryOperation::operator==(const CalcExpressionNode& other) const
 {
-    return adoptRef(new CalculationValue(std::move(value), range));
+    return other.type() == CalcExpressionNodeBinaryOperation && *this == toCalcExpressionBinaryOperation(other);
 }
 
-float CalculationValue::evaluate(float maxValue) const
+float CalcExpressionLength::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 (std::isnan(result))
-        return 0;
-    return m_isNonNegative && result < 0 ? 0 : result;
+    return floatValueForLength(m_length, maxValue);
+}
+
+bool CalcExpressionLength::operator==(const CalcExpressionNode& other) const
+{
+    return other.type() == CalcExpressionNodeLength && *this == toCalcExpressionLength(other);
+}
+
+float CalcExpressionBlendLength::evaluate(float maxValue) const
+{
+    return (1.0f - m_progress) * floatValueForLength(m_from, maxValue) + m_progress * floatValueForLength(m_to, maxValue);
+}
+
+bool CalcExpressionBlendLength::operator==(const CalcExpressionNode& other) const
+{
+    return other.type() == CalcExpressionNodeBlendLength && *this == toCalcExpressionBlendLength(other);
 }
 
 } // namespace WebCore
index f6ae676..4417320 100644 (file)
@@ -62,195 +62,179 @@ enum CalcExpressionNodeType {
 class CalcExpressionNode {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    CalcExpressionNode()
-        : m_type(CalcExpressionNodeUndefined)
-    {
-    }
+    explicit CalcExpressionNode(CalcExpressionNodeType = CalcExpressionNodeUndefined);
+    virtual ~CalcExpressionNode() { }
 
-    virtual ~CalcExpressionNode()
-    {
-    }
+    CalcExpressionNodeType type() const { return m_type; }
 
     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(std::unique_ptr<CalcExpressionNode> value, CalculationPermittedValueRange);
-    float evaluate(float maxValue) 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(std::unique_ptr<CalcExpressionNode> value, CalculationPermittedValueRange range)
-        : m_value(std::move(value))
-        , m_isNonNegative(range == CalculationRangeNonNegative)
-    {
-    }
-
-    std::unique_ptr<CalcExpressionNode> m_value;
-    bool m_isNonNegative;
+    CalcExpressionNodeType m_type;
 };
 
-class CalcExpressionNumber : public CalcExpressionNode {
+class CalcExpressionNumber final : public CalcExpressionNode {
 public:
-    explicit CalcExpressionNumber(float value)
-        : m_value(value)
-    {
-        m_type = CalcExpressionNodeNumber;
-    }
-
-    bool operator==(const CalcExpressionNumber& o) const
-    {
-        return m_value == o.m_value;
-    }
-
-    virtual bool operator==(const CalcExpressionNode& o) const override
-    {
-        return type() == o.type() && *this == static_cast<const CalcExpressionNumber&>(o);
-    }
-
-    virtual float evaluate(float) const override
-    {
-        return m_value;
-    }
+    explicit CalcExpressionNumber(float);
 
     float value() const { return m_value; }
 
 private:
+    virtual float evaluate(float) const override;
+    virtual bool operator==(const CalcExpressionNode&) const override;
+
     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 {
+class CalcExpressionLength final : public CalcExpressionNode {
 public:
-    explicit CalcExpressionLength(Length length)
-        : m_length(length)
-    {
-        m_type = CalcExpressionNodeLength;
-    }
-
-    bool operator==(const CalcExpressionLength& o) const
-    {
-        return m_length == o.m_length;
-    }
-
-    virtual bool operator==(const CalcExpressionNode& o) const override
-    {
-        return type() == o.type() && *this == static_cast<const CalcExpressionLength&>(o);
-    }
-
-    virtual float evaluate(float maxValue) const override
-    {
-        return floatValueForLength(m_length, maxValue);
-    }
+    explicit CalcExpressionLength(Length);
 
     const Length& length() const { return m_length; }
 
 private:
+    virtual float evaluate(float maxValue) const override;
+    virtual bool operator==(const CalcExpressionNode&) const override;
+
     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 {
+class CalcExpressionBinaryOperation final : public CalcExpressionNode {
 public:
-    CalcExpressionBinaryOperation(std::unique_ptr<CalcExpressionNode> leftSide, std::unique_ptr<CalcExpressionNode> rightSide, CalcOperator op)
-        : m_leftSide(std::move(leftSide))
-        , m_rightSide(std::move(rightSide))
-        , m_operator(op)
-    {
-        m_type = CalcExpressionNodeBinaryOperation;
-    }
-
-    bool operator==(const CalcExpressionBinaryOperation& o) const
-    {
-        return m_operator == o.m_operator && *m_leftSide == *o.m_leftSide && *m_rightSide == *o.m_rightSide;
-    }
-
-    virtual bool operator==(const CalcExpressionNode& o) const override
-    {
-        return type() == o.type() && *this == static_cast<const CalcExpressionBinaryOperation&>(o);
-    }
+    CalcExpressionBinaryOperation(std::unique_ptr<CalcExpressionNode> leftSide, std::unique_ptr<CalcExpressionNode> rightSide, CalcOperator);
 
-    virtual float evaluate(float) const override;
-
-    const CalcExpressionNode* leftSide() const { return m_leftSide.get(); }
-    const CalcExpressionNode* rightSide() const { return m_rightSide.get(); }
+    const CalcExpressionNode& leftSide() const { return *m_leftSide; }
+    const CalcExpressionNode& rightSide() const { return *m_rightSide; }
     CalcOperator getOperator() const { return m_operator; }
 
 private:
+    virtual float evaluate(float maxValue) const override;
+    virtual bool operator==(const CalcExpressionNode&) const override;
+
     std::unique_ptr<CalcExpressionNode> m_leftSide;
     std::unique_ptr<CalcExpressionNode> m_rightSide;
     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 {
+class CalcExpressionBlendLength final : public CalcExpressionNode {
 public:
-    CalcExpressionBlendLength(Length from, Length to, float progress)
-        : 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 override
-    {
-        return type() == o.type() && *this == static_cast<const CalcExpressionBlendLength&>(o);
-    }
-
-    virtual float evaluate(float maxValue) const override
-    {
-        return (1.0f - m_progress) * floatValueForLength(m_from, maxValue) + m_progress * floatValueForLength(m_to, maxValue);
-    }
+    CalcExpressionBlendLength(Length from, Length to, float progress);
 
     const Length& from() const { return m_from; }
     const Length& to() const { return m_to; }
     float progress() const { return m_progress; }
 
 private:
+    virtual float evaluate(float maxValue) const override;
+    virtual bool operator==(const CalcExpressionNode&) const override;
+
     Length m_from;
     Length m_to;
     float m_progress;
 };
 
-inline const CalcExpressionBlendLength* toCalcExpressionBlendLength(const CalcExpressionNode* value)
+class CalculationValue : public RefCounted<CalculationValue> {
+public:
+    static PassRef<CalculationValue> create(std::unique_ptr<CalcExpressionNode>, CalculationPermittedValueRange);
+    float evaluate(float maxValue) const;
+
+    bool shouldClampToNonNegative() const { return m_shouldClampToNonNegative; }
+    const CalcExpressionNode& expression() const { return *m_expression; }
+
+private:
+    CalculationValue(std::unique_ptr<CalcExpressionNode>, CalculationPermittedValueRange);
+
+    std::unique_ptr<CalcExpressionNode> m_expression;
+    bool m_shouldClampToNonNegative;
+};
+
+inline CalcExpressionNode::CalcExpressionNode(CalcExpressionNodeType type)
+    : m_type(type)
+{
+}
+
+inline CalculationValue::CalculationValue(std::unique_ptr<CalcExpressionNode> expression, CalculationPermittedValueRange range)
+    : m_expression(std::move(expression))
+    , m_shouldClampToNonNegative(range == CalculationRangeNonNegative)
+{
+}
+
+inline bool operator==(const CalculationValue& a, const CalculationValue& b)
+{
+    return a.expression() == b.expression();
+}
+
+inline CalcExpressionNumber::CalcExpressionNumber(float value)
+    : CalcExpressionNode(CalcExpressionNodeNumber)
+    , m_value(value)
+{
+}
+
+inline bool operator==(const CalcExpressionNumber& a, const CalcExpressionNumber& b)
+{
+    return a.value() == b.value();
+}
+
+inline const CalcExpressionNumber& toCalcExpressionNumber(const CalcExpressionNode& value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeNumber);
+    return static_cast<const CalcExpressionNumber&>(value);
+}
+
+inline CalcExpressionLength::CalcExpressionLength(Length length)
+    : CalcExpressionNode(CalcExpressionNodeLength)
+    , m_length(length)
+{
+}
+
+inline bool operator==(const CalcExpressionLength& a, const CalcExpressionLength& b)
+{
+    return a.length() == b.length();
+}
+
+inline const CalcExpressionLength& toCalcExpressionLength(const CalcExpressionNode& value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeLength);
+    return static_cast<const CalcExpressionLength&>(value);
+}
+
+inline CalcExpressionBinaryOperation::CalcExpressionBinaryOperation(std::unique_ptr<CalcExpressionNode> leftSide, std::unique_ptr<CalcExpressionNode> rightSide, CalcOperator op)
+    : CalcExpressionNode(CalcExpressionNodeBinaryOperation)
+    , m_leftSide(std::move(leftSide))
+    , m_rightSide(std::move(rightSide))
+    , m_operator(op)
+{
+}
+
+inline bool operator==(const CalcExpressionBinaryOperation& a, const CalcExpressionBinaryOperation& b)
+{
+    return a.getOperator() == b.getOperator() && a.leftSide() == b.leftSide() && a.rightSide() == b.rightSide();
+}
+
+inline const CalcExpressionBinaryOperation& toCalcExpressionBinaryOperation(const CalcExpressionNode& value)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeBinaryOperation);
+    return static_cast<const CalcExpressionBinaryOperation&>(value);
+}
+
+inline CalcExpressionBlendLength::CalcExpressionBlendLength(Length from, Length to, float progress)
+    : CalcExpressionNode(CalcExpressionNodeBlendLength)
+    , m_from(from)
+    , m_to(to)
+    , m_progress(progress)
+{
+}
+
+inline bool operator==(const CalcExpressionBlendLength& a, const CalcExpressionBlendLength& b)
+{
+    return a.progress() == b.progress() && a.from() == b.from() && a.to() == b.to();
+}
+
+inline const CalcExpressionBlendLength& toCalcExpressionBlendLength(const CalcExpressionNode& value)
 {
-    ASSERT_WITH_SECURITY_IMPLICATION(!value || value->type() == CalcExpressionNodeBlendLength);
-    return static_cast<const CalcExpressionBlendLength*>(value);
+    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeBlendLength);
+    return static_cast<const CalcExpressionBlendLength&>(value);
 }
 
 } // namespace WebCore
index f8404b0..8212f7b 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller ( mueller@kde.org )
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
  *
  * This library is free software; you can redistribute it and/or
@@ -27,7 +27,8 @@
 
 #include "CalculationValue.h"
 #include <wtf/ASCIICType.h>
-#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/text/StringBuffer.h>
 #include <wtf/text/StringView.h>
@@ -151,70 +152,102 @@ std::unique_ptr<Length[]> newLengthArray(const String& string, int& len)
 
     return r;
 }
-        
-class CalculationValueHandleMap {
-    WTF_MAKE_FAST_ALLOCATED;
+
+class CalculationValueMap {
 public:
-    CalculationValueHandleMap() 
-        : m_index(1) 
-    {
-    }
+    CalculationValueMap();
+
+    unsigned insert(PassRef<CalculationValue>);
+    void ref(unsigned handle);
+    void deref(unsigned handle);
+
+    CalculationValue& get(unsigned handle) const;
+
+private:
+    struct Entry {
+        uint64_t referenceCountMinusOne;
+        CalculationValue* value;
+        Entry();
+        Entry(CalculationValue&);
+    };
+
+    unsigned m_nextAvailableHandle;
+    HashMap<unsigned, Entry> m_map;
+};
+
+inline CalculationValueMap::Entry::Entry()
+    : referenceCountMinusOne(0)
+    , value(nullptr)
+{
+}
+
+inline CalculationValueMap::Entry::Entry(CalculationValue& value)
+    : referenceCountMinusOne(0)
+    , value(&value)
+{
+}
+
+inline CalculationValueMap::CalculationValueMap()
+    : m_nextAvailableHandle(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;
-    }
+inline unsigned CalculationValueMap::insert(PassRef<CalculationValue> value)
+{
+    ASSERT(m_nextAvailableHandle);
 
-    void remove(int index)
-    {
-        ASSERT(m_map.contains(index));
-        m_map.remove(index);
-    }
+    // The leakRef below is balanced by the deref in the deref member function.
+    Entry leakedValue = value.leakRef();
 
-    void remove(HashMap<int, RefPtr<CalculationValue>>::iterator it)
-    {
-        ASSERT(it != m_map.end());
-        m_map.remove(it);
-    }
+    // FIXME: This monotonically increasing handle generation scheme is potentially wasteful
+    // of the handle space. Consider reusing empty handles. https://bugs.webkit.org/show_bug.cgi?id=80489
+    while (!m_map.isValidKey(m_nextAvailableHandle) || !m_map.add(m_nextAvailableHandle, leakedValue).isNewEntry)
+        ++m_nextAvailableHandle;
 
-    PassRefPtr<CalculationValue> get(int index)
-    {
-        ASSERT(m_map.contains(index));
-        return m_map.get(index);
-    }
+    return m_nextAvailableHandle++;
+}
+
+inline CalculationValue& CalculationValueMap::get(unsigned handle) const
+{
+    ASSERT(m_map.contains(handle));
+
+    return *m_map.find(handle)->value.value;
+}
+
+inline void CalculationValueMap::ref(unsigned handle)
+{
+    ASSERT(m_map.contains(handle));
+
+    ++m_map.find(handle)->value.referenceCountMinusOne;
+}
+
+inline void CalculationValueMap::deref(unsigned handle)
+{
+    ASSERT(m_map.contains(handle));
 
-    HashMap<int, RefPtr<CalculationValue>>::iterator find(int index)
-    {
-        ASSERT(m_map.contains(index));
-        return m_map.find(index);
+    auto it = m_map.find(handle);
+    if (it->value.referenceCountMinusOne) {
+        --it->value.referenceCountMinusOne;
+        return;
     }
 
-private:        
-    int m_index;
-    HashMap<int, RefPtr<CalculationValue>> m_map;
-};
-    
-static CalculationValueHandleMap& calcHandles()
+    // The deref below is balanced by the leakRef in the insert member function.
+    it->value.value->deref();
+    m_map.remove(it);
+}
+
+static CalculationValueMap& calculationValues()
 {
-    DEPRECATED_DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
-    return handleMap;
+    static NeverDestroyed<CalculationValueMap> map;
+    return map;
 }
 
-Length::Length(PassRefPtr<CalculationValue> calc)
-    : m_quirk(false)
+Length::Length(PassRef<CalculationValue> value)
+    : m_hasQuirk(false)
     , m_type(Calculated)
     , m_isFloat(false)
 {
-    m_intValue = calcHandles().insert(calc);
+    m_calculationValueHandle = calculationValues().insert(std::move(value));
 }
         
 Length Length::blendMixedTypes(const Length& from, double progress) const
@@ -228,39 +261,37 @@ Length Length::blendMixedTypes(const Length& from, double progress) const
     auto blend = std::make_unique<CalcExpressionBlendLength>(from, *this, progress);
     return Length(CalculationValue::create(std::move(blend), CalculationRangeAll));
 }
-          
-PassRefPtr<CalculationValue> Length::calculationValue() const
+
+CalculationValue& Length::calculationValue() const
 {
     ASSERT(isCalculated());
-    return calcHandles().get(calculationHandle());
+    return calculationValues().get(m_calculationValueHandle);
 }
     
-void Length::incrementCalculatedRef() const
+void Length::ref() const
 {
     ASSERT(isCalculated());
-    calculationValue()->ref();
+    calculationValues().ref(m_calculationValueHandle);
 }
 
-void Length::decrementCalculatedRef() const
+void Length::deref() const
 {
     ASSERT(isCalculated());
-    auto it = calcHandles().find(calculationHandle());
-    if (it->value->hasOneRef())
-        calcHandles().remove(it);
+    calculationValues().deref(m_calculationValueHandle);
 }
 
 float Length::nonNanCalculatedValue(int maxValue) const
 {
     ASSERT(isCalculated());
-    float result = calculationValue()->evaluate(maxValue);
+    float result = calculationValue().evaluate(maxValue);
     if (std::isnan(result))
         return 0;
     return result;
 }
 
-bool Length::isCalculatedEqual(const Length& o) const
+bool Length::isCalculatedEqual(const Length& other) const
 {
-    return isCalculated() && (calculationValue() == o.calculationValue() || *calculationValue() == *o.calculationValue());
+    return calculationValue() == other.calculationValue();
 }
 
 struct SameSizeAsLength {
index 71e79f0..ff3c992 100644 (file)
@@ -1,6 +1,6 @@
 /*
     Copyright (C) 1999 Lars Knoll (knoll@kde.org)
-    Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+    Copyright (C) 2006, 2008, 2014 Apple Inc. All rights reserved.
     Copyright (C) 2011 Rik Cabanier (cabanier@adobe.com)
     Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
 
@@ -29,8 +29,6 @@
 #include <wtf/Assertions.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/Forward.h>
-#include <wtf/HashMap.h>
-#include <wtf/MathExtras.h>
 
 namespace WebCore {
 
@@ -48,285 +46,394 @@ class CalculationValue;
 struct Length {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    Length()
-        :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
-    {
-    }
-
-    Length(LengthType t)
-        : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
-    {
-        ASSERT(t != Calculated);
-    }
-
-    Length(int v, LengthType t, bool q = false)
-        : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
-    {
-        ASSERT(t != Calculated);
-    }
-    
-    Length(LayoutUnit v, LengthType t, bool q = false)
-        : m_floatValue(v.toFloat()), m_quirk(q), m_type(t), m_isFloat(true)
-    {
-        ASSERT(t != Calculated);
-    }
-    
-    Length(float v, LengthType t, bool q = false)
-        : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
-    {
-        ASSERT(t != Calculated);
-    }
-
-    Length(double v, LengthType t, bool q = false)
-        : m_quirk(q), m_type(t), m_isFloat(true)
-    {
-        m_floatValue = static_cast<float>(v);    
-    }
-
-    explicit Length(PassRefPtr<CalculationValue>);
-
-    Length(const Length& length)
-    {
-        initFromLength(length);
-    }
-
-    Length(Length&& other)
-    {
-        moveFromLength(std::move(other));
-    }
-
-    Length& operator=(const Length& length)
-    {
-        initFromLength(length);
-        return *this;
-    }
+    Length(LengthType = Auto);
 
-    Length& operator=(Length&& other)
-    {
-        if (this != &other)
-            moveFromLength(std::move(other));
-        return *this;
-    }
+    Length(int value, LengthType, bool hasQuirk = false);
+    Length(LayoutUnit value, LengthType, bool hasQuirk = false);
+    Length(float value, LengthType, bool hasQuirk = false);
+    Length(double value, LengthType, bool hasQuirk = false);
 
-    ~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()) || isCalculatedEqual(o)); }
-    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        
-            m_intValue = static_cast<int>(m_intValue * v);
-        
-        return *this;
-    }
-    
-    inline float value() const
-    {
-        return getFloatValue();
-    }
-
-     int intValue() const
-     {
-        if (isCalculated()) {
-            ASSERT_NOT_REACHED();
-            return 0;
-        }
-        return getIntValue();
-    }
-
-    float percent() const
-    {
-        ASSERT(isPercent());
-        return getFloatValue();
-    }
+    explicit Length(PassRef<CalculationValue>);
 
-    PassRefPtr<CalculationValue> calculationValue() const;
+    Length(const Length&);
+    Length(Length&&);
+    Length& operator=(const Length&);
+    Length& operator=(Length&&);
 
-    LengthType type() const { return static_cast<LengthType>(m_type); }
-    bool quirk() const { return m_quirk; }
+    ~Length();
 
-    void setQuirk(bool quirk)
-    {
-        m_quirk = quirk;
-    }
+    void setValue(LengthType, int value);
+    void setValue(LengthType, float value);
+    void setValue(LengthType, LayoutUnit value);
+    Length& operator*=(float);
 
-    void setValue(LengthType t, int value)
-    {
-        m_type = t;
-        m_intValue = value;
-        m_isFloat = false;
-    }
+    void setHasQuirk(bool);
 
-    void setValue(int value)
-    {
-        if (isCalculated()) {
-            ASSERT_NOT_REACHED();
-            return;
-        }
-        setValue(Fixed, value);
-    }
+    bool operator==(const Length&) const;
+    bool operator!=(const Length&) const;
 
-    void setValue(LengthType t, float value)
-    {
-        m_type = t;
-        m_floatValue = value;
-        m_isFloat = true;    
-    }
+    float value() const;
+    int intValue() const;
+    float percent() const;
+    float viewportPercentageLength() const;
+    CalculationValue& calculationValue() const;
 
-    void setValue(LengthType t, LayoutUnit value)
-    {
-        m_type = t;
-        m_floatValue = value;
-        m_isFloat = true;    
-    }
+    LengthType type() const;
 
-    void setValue(float value)
-    {
-        *this = Length(value, Fixed);
-    }
+    bool isAuto() const;
+    bool isFixed() const;
+    bool isMaxContent() const;
+    bool isMinContent() const;
+    bool isRelative() const;
+    bool isUndefined() const;
 
-    bool isUndefined() const { return type() == Undefined; }
+    bool hasQuirk() const;
 
-    // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length 
+    // 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 isAuto() const { return type() == Auto; }
-    bool isRelative() const { return type() == Relative; }
-    bool isPercent() const { return type() == Percent || type() == Calculated; }
-    bool isFixed() const { return type() == Fixed; }
-    bool isIntrinsicOrAuto() const { return type() == Auto || isLegacyIntrinsic() || isIntrinsic(); }
-    bool isLegacyIntrinsic() const { return type() == Intrinsic || type() == MinIntrinsic; }
-    bool isIntrinsic() const { return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent; }
-    bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated || isViewportPercentage(); }
-    bool isSpecifiedOrIntrinsic() const { return isSpecified() || isIntrinsic(); }
-    bool isCalculated() const { return type() == Calculated; }
-    bool isCalculatedEqual(const Length&) const;
-    bool isMinContent() const { return type() == MinContent; }
-    bool isMaxContent() const { return type() == MaxContent; }
-
-    Length blend(const Length& from, double progress) const
-    {
-        // Blend two lengths to produce a new length that is in between them.  Used for animation.
-        if (from.type() == Calculated || type() == Calculated)
-            return blendMixedTypes(from, progress);
-        
-        if (!from.isZero() && !isZero() && from.type() != type())
-            return blendMixedTypes(from, progress);
-
-        if (from.isZero() && isZero())
-            return *this;
-        
-        LengthType resultType = type();
-        if (isZero())
-            resultType = from.type();
-        
-        if (resultType == Percent) {
-            float fromPercent = from.isZero() ? 0 : from.percent();
-            float toPercent = isZero() ? 0 : percent();
-            return Length(WebCore::blend(fromPercent, toPercent, progress), Percent);
-        } 
-
-        float fromValue = from.isZero() ? 0 : from.value();
-        float toValue = isZero() ? 0 : value();
-        return Length(WebCore::blend(fromValue, toValue, progress), resultType);
-    }
+    // it's impossible to determine the sign or zero-ness. The following three functions
+    // act as if all calculated values are positive.
+    bool isZero() const;
+    bool isPositive() const;
+    bool isNegative() const;
+
+    // Returns true for both Percent and Calculated.
+    // FIXME: Doesn't really seem OK to return true for Calculated given this function's name,
+    // even though all calculated values are treated as percentages. Callers can tell Percent
+    // from a Calculated already by looking at type, so this function only half-hides the distinction.
+    bool isPercent() const;
+
+    bool isIntrinsic() const;
+    bool isIntrinsicOrAuto() const;
+    bool isSpecified() const;
+    bool isSpecifiedOrIntrinsic() const;
+    bool isViewportPercentage() const;
+
+    // Blend two lengths to produce a new length that is in between them. Used for animation.
+    // FIXME: Why is this a member function?
+    Length blend(const Length& from, double progress) const;
 
-    float getFloatValue() const
-    {
-        ASSERT(!isUndefined());
-        return m_isFloat ? m_floatValue : m_intValue;
-    }
     float nonNanCalculatedValue(int maxValue) const;
 
-    bool isViewportPercentage() const
-    {
-        LengthType lengthType = type();
-        return lengthType >= ViewportPercentageWidth && lengthType <= ViewportPercentageMax;
-    }
-    float viewportPercentageLength() const
-    {
-        ASSERT(isViewportPercentage());
-        return getFloatValue();
-    }
 private:
-    int getIntValue() const
-    {
-        ASSERT(!isUndefined());
-        return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
-    }
-    void initFromLength(const Length& length)
-    {
-        memcpy(this, &length, sizeof(Length));
-        if (isCalculated())
-            incrementCalculatedRef();
-    }
-
-    void moveFromLength(Length&& length)
-    {
-        ASSERT(this != &length);
-        memcpy(this, &length, sizeof(Length));
-        length.m_type = Auto;
-    }
+    bool isCalculated() const;
+    bool isLegacyIntrinsic() const;
 
+    bool isCalculatedEqual(const Length&) const;
     Length blendMixedTypes(const Length& from, double progress) const;
 
-    int calculationHandle() const
-    {
-        ASSERT(isCalculated());
-        return getIntValue();
-    }
-    void incrementCalculatedRef() const;
-    void decrementCalculatedRef() const;    
+    void ref() const;
+    void deref() const;
     
     union {
         int m_intValue;
         float m_floatValue;
+        unsigned m_calculationValueHandle;
     };
-    bool m_quirk;
+    bool m_hasQuirk;
     unsigned char m_type;
     bool m_isFloat;
 };
 
-std::unique_ptr<Length[]> newCoordsArray(const String&, int& len);
-std::unique_ptr<Length[]> newLengthArray(const String&, int& len);
+std::unique_ptr<Length[]> newCoordsArray(const String&, int& length);
+std::unique_ptr<Length[]> newLengthArray(const String&, int& length);
+
+inline Length::Length(LengthType type)
+    : m_intValue(0), m_hasQuirk(false), m_type(type), m_isFloat(false)
+{
+    ASSERT(type != Calculated);
+}
+
+inline Length::Length(int value, LengthType type, bool hasQuirk)
+    : m_intValue(value), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(false)
+{
+    ASSERT(type != Calculated);
+}
+
+inline Length::Length(LayoutUnit value, LengthType type, bool hasQuirk)
+    : m_floatValue(value.toFloat()), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
+{
+    ASSERT(type != Calculated);
+}
+
+inline Length::Length(float value, LengthType type, bool hasQuirk)
+    : m_floatValue(value), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
+{
+    ASSERT(type != Calculated);
+}
+
+inline Length::Length(double value, LengthType type, bool hasQuirk)
+    : m_floatValue(static_cast<float>(value)), m_hasQuirk(hasQuirk), m_type(type), m_isFloat(true)
+{
+    ASSERT(type != Calculated);
+}
+
+inline Length::Length(const Length& other)
+{
+    if (other.isCalculated())
+        other.ref();
+
+    memcpy(this, &other, sizeof(Length));
+}
+
+inline Length::Length(Length&& other)
+{
+    memcpy(this, &other, sizeof(Length));
+    other.m_type = Auto;
+}
+
+inline Length& Length::operator=(const Length& other)
+{
+    if (other.isCalculated())
+        other.ref();
+    if (isCalculated())
+        deref();
+
+    memcpy(this, &other, sizeof(Length));
+    return *this;
+}
+
+inline Length& Length::operator=(Length&& other)
+{
+    if (this == &other)
+        return *this;
+
+    if (isCalculated())
+        deref();
+
+    memcpy(this, &other, sizeof(Length));
+    other.m_type = Auto;
+    return *this;
+}
+
+inline Length::~Length()
+{
+    if (isCalculated())
+        deref();
+}
+
+inline bool Length::operator==(const Length& other) const
+{
+    // FIXME: This might be too long to be inline.
+    if (type() != other.type() || hasQuirk() != other.hasQuirk())
+        return false;
+    if (isUndefined())
+        return true;
+    if (isCalculated())
+        return isCalculatedEqual(other);
+    return value() == other.value();
+}
+
+inline bool Length::operator!=(const Length& other) const
+{
+    return !(*this == other);
+}
+
+inline Length& Length::operator*=(float value)
+{
+    ASSERT(!isCalculated());
+    if (isCalculated())
+        return *this;
+
+    if (m_isFloat)
+        m_floatValue *= value;
+    else
+        m_intValue *= value;
+
+    return *this;
+}
+
+inline float Length::value() const
+{
+    ASSERT(!isUndefined());
+    ASSERT(!isCalculated());
+    return m_isFloat ? m_floatValue : m_intValue;
+}
+
+inline int Length::intValue() const
+{
+    ASSERT(!isUndefined());
+    ASSERT(!isCalculated());
+    // FIXME: Makes no sense to return 0 here but not in the value() function above.
+    if (isCalculated())
+        return 0;
+    return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
+}
+
+inline float Length::percent() const
+{
+    ASSERT(isPercent());
+    return value();
+}
+
+inline float Length::viewportPercentageLength() const
+{
+    ASSERT(isViewportPercentage());
+    return value();
+}
+
+inline LengthType Length::type() const
+{
+    return static_cast<LengthType>(m_type);
+}
+
+inline bool Length::hasQuirk() const
+{
+    return m_hasQuirk;
+}
+
+inline void Length::setHasQuirk(bool hasQuirk)
+{
+    m_hasQuirk = hasQuirk;
+}
+
+inline void Length::setValue(LengthType type, int value)
+{
+    ASSERT(m_type != Calculated);
+    ASSERT(type != Calculated);
+    m_type = type;
+    m_intValue = value;
+    m_isFloat = false;
+}
+
+inline void Length::setValue(LengthType type, float value)
+{
+    ASSERT(m_type != Calculated);
+    ASSERT(type != Calculated);
+    m_type = type;
+    m_floatValue = value;
+    m_isFloat = true;
+}
+
+inline void Length::setValue(LengthType type, LayoutUnit value)
+{
+    ASSERT(m_type != Calculated);
+    ASSERT(type != Calculated);
+    m_type = type;
+    m_floatValue = value;
+    m_isFloat = true;
+}
+
+inline bool Length::isAuto() const
+{
+    return type() == Auto;
+}
+
+inline bool Length::isFixed() const
+{
+    return type() == Fixed;
+}
+
+inline bool Length::isMaxContent() const
+{
+    return type() == MaxContent;
+}
+
+inline bool Length::isMinContent() const
+{
+    return type() == MinContent;
+}
+
+inline bool Length::isNegative() const
+{
+    if (isUndefined() || isCalculated())
+        return false;
+    return m_isFloat ? (m_floatValue < 0) : (m_intValue < 0);
+}
+
+inline bool Length::isRelative() const
+{
+    return type() == Relative;
+}
+
+inline bool Length::isUndefined() const
+{
+    return type() == Undefined;
+}
+
+inline bool Length::isPercent() const
+{
+    return type() == Percent || isCalculated();
+}
+
+inline bool Length::isPositive() const
+{
+    if (isUndefined())
+        return false;
+    if (isCalculated())
+        return true;
+    return m_isFloat ? (m_floatValue > 0) : (m_intValue > 0);
+}
+
+inline bool Length::isZero() const
+{
+    ASSERT(!isUndefined());
+    if (isCalculated())
+        return false;
+    return m_isFloat ? !m_floatValue : !m_intValue;
+}
+
+inline bool Length::isCalculated() const
+{
+    return type() == Calculated;
+}
+
+inline bool Length::isLegacyIntrinsic() const
+{
+    return type() == Intrinsic || type() == MinIntrinsic;
+}
+
+inline bool Length::isIntrinsic() const
+{
+    return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent;
+}
+
+inline bool Length::isIntrinsicOrAuto() const
+{
+    return isAuto() || isIntrinsic() || isLegacyIntrinsic();
+}
+
+inline bool Length::isSpecified() const
+{
+    return isFixed() || type() == Percent || isCalculated() || isViewportPercentage();
+}
+
+inline bool Length::isSpecifiedOrIntrinsic() const
+{
+    return isSpecified() || isIntrinsic();
+}
+
+inline bool Length::isViewportPercentage() const
+{
+    return type() >= ViewportPercentageWidth && type() <= ViewportPercentageMax;
+}
+
+// FIXME: Does this need to be in the header? Is it valuable to inline? Does it get inlined?
+inline Length Length::blend(const Length& from, double progress) const
+{
+    if (from.type() == Calculated || type() == Calculated)
+        return blendMixedTypes(from, progress);
+
+    if (!from.isZero() && !isZero() && from.type() != type())
+        return blendMixedTypes(from, progress);
+
+    if (from.isZero() && isZero())
+        return *this;
+
+    LengthType resultType = type();
+    if (isZero())
+        resultType = from.type();
+
+    if (resultType == Percent) {
+        float fromPercent = from.isZero() ? 0 : from.percent();
+        float toPercent = isZero() ? 0 : percent();
+        return Length(WebCore::blend(fromPercent, toPercent, progress), Percent);
+    }
+
+    float fromValue = from.isZero() ? 0 : from.value();
+    float toValue = isZero() ? 0 : value();
+    return Length(WebCore::blend(fromValue, toValue, progress), resultType);
+}
 
 } // namespace WebCore
 
index 9addabd..2655f6d 100644 (file)
 
 namespace WebCore {
 
-class RenderStyle;
-
 struct LengthBox {
     LengthBox()
     {
     }
 
-    LengthBox(LengthType t)
-        : m_left(t)
-        , m_right(t)
-        , m_top(t)
-        , m_bottom(t)
+    explicit LengthBox(LengthType type)
+        : m_left(type)
+        , m_right(type)
+        , m_top(type)
+        , m_bottom(type)
     {
     }
 
-    LengthBox(int v)
+    explicit LengthBox(int v)
         : m_left(Length(v, Fixed))
         , m_right(Length(v, Fixed))
         , m_top(Length(v, Fixed))
@@ -51,19 +49,19 @@ struct LengthBox {
     {
     }
 
-    LengthBox(Length t, Length r, Length b, Length l)
-        : m_left(std::move(l))
-        , m_right(std::move(r))
-        , m_top(std::move(t))
-        , m_bottom(std::move(b))
+    LengthBox(Length top, Length right, Length bottom, Length left)
+        : m_left(std::move(left))
+        , m_right(std::move(right))
+        , m_top(std::move(top))
+        , m_bottom(std::move(bottom))
     {
     }
-    
-    LengthBox(int t, int r, int b, int l)
-        : m_left(Length(l, Fixed))
-        , m_right(Length(r, Fixed))
-        , m_top(Length(t, Fixed))
-        , m_bottom(Length(b, Fixed))
+
+    LengthBox(int top, int right, int bottom, int left)
+        : m_left(Length(left, Fixed))
+        , m_right(Length(right, Fixed))
+        , m_top(Length(top, Fixed))
+        , m_bottom(Length(bottom, Fixed))
     {
     }
 
@@ -80,14 +78,14 @@ struct LengthBox {
     const Length& start(WritingMode, TextDirection) const;
     const Length& end(WritingMode, TextDirection) const;
 
-    bool operator==(const LengthBox& o) const
+    bool operator==(const LengthBox& other) const
     {
-        return m_left == o.m_left && m_right == o.m_right && m_top == o.m_top && m_bottom == o.m_bottom;
+        return m_left == other.m_left && m_right == other.m_right && m_top == other.m_top && m_bottom == other.m_bottom;
     }
 
-    bool operator!=(const LengthBox& o) const
+    bool operator!=(const LengthBox& other) const
     {
-        return !(*this == o);
+        return !(*this == other);
     }
 
     bool nonZero() const
index 4cd8f87..de5f041 100644 (file)
@@ -85,9 +85,9 @@ void AutoTableLayout::recalcColumn(unsigned effCol)
                     const int cCellMaxWidth = 32760;
                     Length cellLogicalWidth = cell->styleOrColLogicalWidth();
                     if (cellLogicalWidth.value() > cCellMaxWidth)
-                        cellLogicalWidth.setValue(cCellMaxWidth);
+                        cellLogicalWidth.setValue(Fixed, cCellMaxWidth);
                     if (cellLogicalWidth.isNegative())
-                        cellLogicalWidth.setValue(0);
+                        cellLogicalWidth.setValue(Fixed, 0);
                     switch (cellLogicalWidth.type()) {
                     case Fixed:
                         // ignore width=0
index a460f8c..cecea72 100644 (file)
@@ -143,7 +143,7 @@ int FixedTableLayout::calcWidthArray()
         // RenderBox::computeLogicalWidthInRegionUsing to compute the width.
         if (logicalWidth.isFixed() && logicalWidth.isPositive()) {
             fixedBorderBoxLogicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(logicalWidth.value());
-            logicalWidth.setValue(fixedBorderBoxLogicalWidth);
+            logicalWidth.setValue(Fixed, fixedBorderBoxLogicalWidth);
         }
 
         unsigned usedSpan = 0;
index be4818f..d49a5c2 100644 (file)
@@ -187,8 +187,8 @@ public:
     static EFillSizeType initialFillSizeType(EFillLayerType) { return SizeNone; }
     static LengthSize initialFillSizeLength(EFillLayerType) { return LengthSize(); }
     static FillSize initialFillSize(EFillLayerType type) { return FillSize(initialFillSizeType(type), initialFillSizeLength(type)); }
-    static Length initialFillXPosition(EFillLayerType) { return Length(0.0, Percent); }
-    static Length initialFillYPosition(EFillLayerType) { return Length(0.0, Percent); }
+    static Length initialFillXPosition(EFillLayerType) { return Length(0.0f, Percent); }
+    static Length initialFillYPosition(EFillLayerType) { return Length(0.0f, Percent); }
     static StyleImage* initialFillImage(EFillLayerType) { return 0; }
     static EMaskSourceType initialMaskSourceType(EFillLayerType) { return MaskAlpha; }
 
index 4cd8d86..9beed52 100644 (file)
@@ -1348,18 +1348,18 @@ int RenderStyle::computedLineHeight(RenderView* renderView) const
     return lh.value();
 }
 
-void RenderStyle::setWordSpacing(Length v)
+void RenderStyle::setWordSpacing(Length value)
 {
     float fontWordSpacing;
-    switch (v.type()) {
+    switch (value.type()) {
     case Auto:
         fontWordSpacing = 0;
-        FALLTHROUGH;
+        break;
     case Percent:
-        fontWordSpacing = v.getFloatValue() * font().spaceWidth() / 100;
+        fontWordSpacing = value.percent() * font().spaceWidth() / 100;
         break;
     case Fixed:
-        fontWordSpacing = v.getFloatValue();
+        fontWordSpacing = value.value();
         break;
     default:
         ASSERT_NOT_REACHED();
@@ -1367,7 +1367,7 @@ void RenderStyle::setWordSpacing(Length v)
         break;
     }
     inherited.access()->font.setWordSpacing(fontWordSpacing);
-    rareInheritedData.access()->wordSpacing = std::move(v);
+    rareInheritedData.access()->wordSpacing = std::move(value);
 }
 
 void RenderStyle::setLetterSpacing(float v) { inherited.access()->font.setLetterSpacing(v); }
index 5bd2b94..84ea942 100644 (file)
@@ -522,8 +522,8 @@ public:
     bool hasBorder() const { return surround->border.hasBorder(); }
     bool hasPadding() const { return surround->padding.nonZero(); }
     bool hasOffset() const { return surround->offset.nonZero(); }
-    bool hasMarginBeforeQuirk() const { return marginBefore().quirk(); }
-    bool hasMarginAfterQuirk() const { return marginAfter().quirk(); }
+    bool hasMarginBeforeQuirk() const { return marginBefore().hasQuirk(); }
+    bool hasMarginAfterQuirk() const { return marginAfter().hasQuirk(); }
 
     bool hasBackgroundImage() const { return m_background->background().hasImage(); }
     bool hasFixedBackgroundImage() const { return m_background->background().hasFixedImage(); }
@@ -1775,9 +1775,9 @@ public:
 #endif
     static short initialWidows() { return 2; }
     static short initialOrphans() { return 2; }
-    static Length initialLineHeight() { return Length(-100.0, Percent); }
+    static Length initialLineHeight() { return Length(-100.0f, Percent); }
 #if ENABLE(IOS_TEXT_AUTOSIZING)
-    static Length initialSpecifiedLineHeight() { return Length(-100, Percent); }
+    static Length initialSpecifiedLineHeight() { return Length(-100.0f, Percent); }
 #endif
     static ETextAlign initialTextAlign() { return TASTART; }
     static TextDecoration initialTextDecoration() { return TextDecorationNone; }
@@ -1846,15 +1846,15 @@ public:
     static ColumnFill initialColumnFill() { return ColumnFillBalance; }
     static ColumnSpan initialColumnSpan() { return ColumnSpanNone; }
     static const TransformOperations& initialTransform() { DEPRECATED_DEFINE_STATIC_LOCAL(TransformOperations, ops, ()); return ops; }
-    static Length initialTransformOriginX() { return Length(50.0, Percent); }
-    static Length initialTransformOriginY() { return Length(50.0, Percent); }
+    static Length initialTransformOriginX() { return Length(50.0f, Percent); }
+    static Length initialTransformOriginY() { return Length(50.0f, Percent); }
     static EPointerEvents initialPointerEvents() { return PE_AUTO; }
     static float initialTransformOriginZ() { return 0; }
     static ETransformStyle3D initialTransformStyle3D() { return TransformStyle3DFlat; }
     static EBackfaceVisibility initialBackfaceVisibility() { return BackfaceVisibilityVisible; }
     static float initialPerspective() { return 0; }
-    static Length initialPerspectiveOriginX() { return Length(50.0, Percent); }
-    static Length initialPerspectiveOriginY() { return Length(50.0, Percent); }
+    static Length initialPerspectiveOriginX() { return Length(50.0f, Percent); }
+    static Length initialPerspectiveOriginY() { return Length(50.0f, Percent); }
     static Color initialBackgroundColor() { return Color::transparent; }
     static Color initialTextEmphasisColor() { return TextEmphasisFillFilled; }
     static TextEmphasisFill initialTextEmphasisFill() { return TextEmphasisFillFilled; }
index e857150..3e41252 100644 (file)
@@ -1,3 +1,13 @@
+2014-04-06  Darin Adler  <darin@apple.com>
+
+        Rework CSS calc logic, fixing some reference count mistakes in Length
+        https://bugs.webkit.org/show_bug.cgi?id=131280
+
+        Reviewed by Andreas Kling.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Added CalculationValue.cpp.
+        * TestWebKitAPI/Tests/WebCore/CalculationValue.cpp: Added.
+
 2014-04-04  Brian J. Burg  <burg@cs.washington.edu>
 
         Enable WEB_REPLAY for PLATFORM(MAC)
index a02bc50..d30bd3b 100644 (file)
                939BFE3A18E5548900883275 /* StringTruncator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 939BFE3918E5548900883275 /* StringTruncator.mm */; };
                93A427A9180D9B0700CD24D7 /* RefPtr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93A427A8180D9B0700CD24D7 /* RefPtr.cpp */; };
                93A427AB180DA26400CD24D7 /* Ref.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93A427AA180DA26400CD24D7 /* Ref.cpp */; };
+               93A720E618F1A0E800A848E1 /* CalculationValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93A720E518F1A0E800A848E1 /* CalculationValue.cpp */; };
                93ABA80916DDAB91002DB2FA /* StringHasher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93ABA80816DDAB91002DB2FA /* StringHasher.cpp */; };
                93AF4ECE1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93AF4ECD1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp */; };
                93AF4ED01506F123007FD57E /* lots-of-images.html in Resources */ = {isa = PBXBuildFile; fileRef = 93AF4ECF1506F123007FD57E /* lots-of-images.html */; };
                93A427AA180DA26400CD24D7 /* Ref.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ref.cpp; sourceTree = "<group>"; };
                93A427AC180DA60F00CD24D7 /* MoveOnly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MoveOnly.h; sourceTree = "<group>"; };
                93A427AD180DA60F00CD24D7 /* RefLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RefLogger.h; sourceTree = "<group>"; };
+               93A720E518F1A0E800A848E1 /* CalculationValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CalculationValue.cpp; sourceTree = "<group>"; };
                93ABA80816DDAB91002DB2FA /* StringHasher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringHasher.cpp; sourceTree = "<group>"; };
                93AF4ECA1506F035007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutForImages.cpp; sourceTree = "<group>"; };
                93AF4ECD1506F064007FD57E /* NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NewFirstVisuallyNonEmptyLayoutForImages_Bundle.cpp; sourceTree = "<group>"; };
                440A1D3614A01000008A66F2 /* WebCore */ = {
                        isa = PBXGroup;
                        children = (
+                               93A720E518F1A0E800A848E1 /* CalculationValue.cpp */,
                                CDC2C7141797089D00E627FB /* TimeRanges.cpp */,
                                440A1D3814A0103A008A66F2 /* URL.cpp */,
                                14464012167A8305000BD218 /* LayoutUnit.cpp */,
                                3722C8691461E03E00C45D00 /* RenderedImageFromDOMRange.mm in Sources */,
                                C0BD669D131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp in Sources */,
                                C0ADBE8312FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp in Sources */,
+                               93A720E618F1A0E800A848E1 /* CalculationValue.cpp in Sources */,
                                1AEF994917A09F5400998EF0 /* GetPIDAfterAbortedProcessLaunch.cpp in Sources */,
                                BC029B181486AD6400817DA9 /* RetainPtr.cpp in Sources */,
                                BC029B1C1486B25900817DA9 /* RetainPtr.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CalculationValue.cpp
new file mode 100644 (file)
index 0000000..49e7504
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <WebCore/CalculationValue.h>
+
+namespace TestWebKitAPI {
+
+static unsigned deletionCount;
+
+class CalculationDeletionTestNode : public WebCore::CalcExpressionNode {
+public:
+    virtual ~CalculationDeletionTestNode()
+    {
+        ++deletionCount;
+    }
+
+    virtual float evaluate(float) const override { return 0; }
+    bool operator==(const CalcExpressionNode&) const { ASSERT_NOT_REACHED(); return false; }
+};
+
+static PassRef<WebCore::CalculationValue> createTestValue()
+{
+    auto node = std::make_unique<CalculationDeletionTestNode>();
+    return WebCore::CalculationValue::create(std::move(node), WebCore::CalculationRangeAll);
+}
+
+TEST(CalculationValue, LengthConstruction)
+{
+    RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        WebCore::Length length(*value);
+        EXPECT_EQ(2U, value->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        WebCore::Length lengthA(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthB(lengthA);
+        EXPECT_EQ(2U, value->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        WebCore::Length lengthC(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthD(std::move(lengthC));
+        EXPECT_EQ(2U, value->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+
+    EXPECT_EQ(0U, deletionCount);
+    value = nullptr;
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthConstructionReleasedValue)
+{
+    RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length length(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+
+        EXPECT_EQ(0U, deletionCount);
+    }
+
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthA(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        WebCore::Length lengthB(lengthA);
+        EXPECT_EQ(1U, rawValue->refCount());
+
+        EXPECT_EQ(0U, deletionCount);
+    }
+
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthC(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        WebCore::Length lengthD(std::move(lengthC));
+        EXPECT_EQ(1U, rawValue->refCount());
+
+        EXPECT_EQ(0U, deletionCount);
+    }
+
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthAssignment)
+{
+    RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        WebCore::Length lengthA(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthB;
+        lengthB = lengthA;
+        EXPECT_EQ(2U, value->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+
+    {
+        WebCore::Length lengthC(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthD;
+        lengthD = std::move(lengthC);
+        EXPECT_EQ(2U, value->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+
+    EXPECT_EQ(0U, deletionCount);
+    value = nullptr;
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+    RefPtr<WebCore::CalculationValue> value2 = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+    EXPECT_EQ(1U, value2->refCount());
+
+    {
+        WebCore::Length lengthE(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthF(*value2);
+        EXPECT_EQ(2U, value2->refCount());
+        lengthE = lengthF;
+        EXPECT_EQ(1U, value->refCount());
+        EXPECT_EQ(2U, value2->refCount());
+    }
+
+    EXPECT_EQ(1U, value->refCount());
+    EXPECT_EQ(1U, value2->refCount());
+
+    {
+        WebCore::Length lengthG(*value);
+        EXPECT_EQ(2U, value->refCount());
+        WebCore::Length lengthH(*value2);
+        EXPECT_EQ(2U, value2->refCount());
+        lengthG = std::move(lengthH);
+        EXPECT_EQ(1U, value->refCount());
+        EXPECT_EQ(2U, value2->refCount());
+    }
+
+    EXPECT_EQ(0U, deletionCount);
+    value = nullptr;
+    EXPECT_EQ(1U, deletionCount);
+    value2 = nullptr;
+    EXPECT_EQ(2U, deletionCount);
+    deletionCount = 0;
+}
+
+TEST(CalculationValue, LengthAssignmentReleasedValue)
+{
+    RefPtr<WebCore::CalculationValue> value = createTestValue();
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthA(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        WebCore::Length lengthB;
+        lengthB = lengthA;
+        EXPECT_EQ(1U, rawValue->refCount());
+
+        EXPECT_EQ(0U, deletionCount);
+    }
+
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthC(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        WebCore::Length lengthD;
+        lengthD = std::move(lengthC);
+        EXPECT_EQ(1U, rawValue->refCount());
+
+        EXPECT_EQ(0U, deletionCount);
+    }
+
+    EXPECT_EQ(1U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+    RefPtr<WebCore::CalculationValue> value2 = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+    EXPECT_EQ(1U, value2->refCount());
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthE(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        auto* rawValue2 = value2.get();
+        WebCore::Length lengthF(value2.releaseNonNull());
+        EXPECT_EQ(1U, rawValue2->refCount());
+
+        lengthE = lengthF;
+        EXPECT_EQ(1U, deletionCount);
+        EXPECT_EQ(1U, rawValue2->refCount());
+    }
+
+    EXPECT_EQ(2U, deletionCount);
+    deletionCount = 0;
+
+    value = createTestValue();
+    value2 = createTestValue();
+
+    EXPECT_EQ(1U, value->refCount());
+    EXPECT_EQ(1U, value2->refCount());
+
+    {
+        auto* rawValue = value.get();
+        WebCore::Length lengthG(value.releaseNonNull());
+        EXPECT_EQ(1U, rawValue->refCount());
+        auto* rawValue2 = value2.get();
+        WebCore::Length lengthH(value2.releaseNonNull());
+        EXPECT_EQ(1U, rawValue2->refCount());
+
+        lengthG = std::move(lengthH);
+        EXPECT_EQ(1U, deletionCount);
+        EXPECT_EQ(1U, rawValue2->refCount());
+    }
+
+    EXPECT_EQ(2U, deletionCount);
+    deletionCount = 0;
+}
+
+}