Changeset 110126 in webkit


Ignore:
Timestamp:
Mar 7, 2012 6:12:26 PM (12 years ago)
Author:
mikelawther@chromium.org
Message:

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

Reviewed by Andreas Kling.

Source/WebCore:

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

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

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

  • WebCore.exp.in:
  • css/CSSCalculationValue.cpp:

(WebCore::CSSCalcPrimitiveValue::toCalcValue):
(CSSCalcPrimitiveValue):
(WebCore::CSSCalcBinaryOperation::toCalcValue):
(CSSCalcBinaryOperation):

  • css/CSSCalculationValue.h:

(WebCore):
(CSSCalcExpressionNode):
(CSSCalcValue):
(WebCore::CSSCalcValue::toCalcValue):

  • css/CSSPrimitiveValue.cpp:

(WebCore::CSSPrimitiveValue::CSSPrimitiveValue):

  • css/CSSStyleApplyProperty.cpp:

(WebCore::ApplyPropertyLength::applyValue):

  • css/CSSStyleSelector.cpp:

(WebCore::CSSStyleSelector::collectMatchingRulesForList):

  • css/CSSStyleSelector.h:

(CSSStyleSelector):

  • platform/CalculationValue.cpp:

(WebCore::CalcExpressionBinaryOperation::evaluate):
(WebCore):
(WebCore::CalculationValue::create):
(WebCore::CalculationValue::evaluate):

  • platform/CalculationValue.h:

(CalcExpressionNode):
(WebCore::CalcExpressionNode::~CalcExpressionNode):
(WebCore):
(CalculationValue):
(WebCore::CalculationValue::CalculationValue):
(CalcExpressionNumber):
(WebCore::CalcExpressionNumber::CalcExpressionNumber):
(WebCore::CalcExpressionNumber::evaluate):
(CalcExpressionLength):
(WebCore::CalcExpressionLength::CalcExpressionLength):
(WebCore::CalcExpressionLength::evaluate):
(CalcExpressionBinaryOperation):
(WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation):

  • platform/Length.cpp:

(WebCore):
(WebCore::Length::~Length):
(CalculationValueHandleMap):
(WebCore::CalculationValueHandleMap::CalculationValueHandleMap):
(WebCore::CalculationValueHandleMap::insert):
(WebCore::CalculationValueHandleMap::remove):
(WebCore::CalculationValueHandleMap::get):
(WebCore::calcHandles):
(WebCore::Length::Length):
(WebCore::Length::calculationValue):
(WebCore::Length::calculatedValue):
(WebCore::Length::calculatedMinValue):
(WebCore::Length::calculatedFloatValue):
(WebCore::Length::incrementCalculatedRef):
(WebCore::Length::decrementCalculatedRef):
(WebCore::Length::nonNanCalculatedValue):

  • platform/Length.h:

(Length):
(WebCore::Length::Length):
(WebCore::Length::operator=):
(WebCore::Length::operator*=):
(WebCore::Length::value):
(WebCore::Length::setValue):
(WebCore::Length::calcValue):
(WebCore::Length::calcMinValue):
(WebCore::Length::calcFloatValue):
(WebCore::Length::isZero):
(WebCore::Length::isPositive):
(WebCore::Length::isNegative):
(WebCore::Length::isPercent):
(WebCore::Length::isSpecified):
(WebCore::Length::isCalculated):
(WebCore::Length::initFromLength):
(WebCore::Length::calculationHandle):

LayoutTests:

  • css3/calc/margin-expected.txt:
  • css3/calc/padding-expected.txt:
  • css3/calc/simple-calcs-expected.txt:
Location:
trunk
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r110124 r110126  
     12012-03-07  Mike Lawther  <mikelawther@chromium.org>
     2
     3        CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
     4        https://bugs.webkit.org/show_bug.cgi?id=79621
     5
     6        Reviewed by Andreas Kling.
     7
     8        * css3/calc/margin-expected.txt:
     9        * css3/calc/padding-expected.txt:
     10        * css3/calc/simple-calcs-expected.txt:
     11
    1122012-03-07  Stephen White  <senorblanco@chromium.org>
    213
  • trunk/LayoutTests/css3/calc/margin-expected.txt

    r109874 r110126  
    1919PASS computedMarginRight("simple-bottom") is "0px"
    2020PASS computedMarginBottom("simple-bottom") is "25px"
    21 FAIL computedMarginLeft("percent-all") should be 25px. Was 0px.
    22 FAIL computedMarginTop("percent-all") should be 25px. Was 0px.
    23 FAIL computedMarginRight("percent-all") should be 25px. Was 0px.
    24 FAIL computedMarginBottom("percent-all") should be 25px. Was 0px.
    25 FAIL computedMarginLeft("percent-left") should be 25px. Was 0px.
     21PASS computedMarginLeft("percent-all") is "25px"
     22PASS computedMarginTop("percent-all") is "25px"
     23PASS computedMarginRight("percent-all") is "25px"
     24PASS computedMarginBottom("percent-all") is "25px"
     25PASS computedMarginLeft("percent-left") is "25px"
    2626PASS computedMarginTop("percent-left") is "0px"
    2727PASS computedMarginRight("percent-left") is "0px"
     
    2929PASS computedMarginLeft("percent-right") is "0px"
    3030PASS computedMarginTop("percent-right") is "0px"
    31 FAIL computedMarginRight("percent-right") should be 25px. Was 0px.
     31PASS computedMarginRight("percent-right") is "25px"
    3232PASS computedMarginBottom("percent-right") is "0px"
    3333PASS computedMarginLeft("percent-top") is "0px"
    34 FAIL computedMarginTop("percent-top") should be 25px. Was 0px.
     34PASS computedMarginTop("percent-top") is "25px"
    3535PASS computedMarginRight("percent-top") is "0px"
    3636PASS computedMarginBottom("percent-top") is "0px"
     
    3838PASS computedMarginTop("percent-bottom") is "0px"
    3939PASS computedMarginRight("percent-bottom") is "0px"
    40 FAIL computedMarginBottom("percent-bottom") should be 25px. Was 0px.
     40PASS computedMarginBottom("percent-bottom") is "25px"
    4141PASS successfullyParsed is true
    4242
  • trunk/LayoutTests/css3/calc/padding-expected.txt

    r107688 r110126  
    99This element should have a bottom padding of 25 pixels. => PASS
    1010
    11 This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width, wrong height
     11This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
    1212
    13 This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
     13This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
    1414
    15 This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
     15This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
    1616
    17 This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
     17This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
    1818
    19 This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
     19This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
  • trunk/LayoutTests/css3/calc/simple-calcs-expected.txt

    r107688 r110126  
    212150px + 10px * 5 (operation order) => PASS
    2222100%/2 (where 100% is 200px) => PASS
    23 100% + -100px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
    24 80% - 60px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
    25 300px - 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
    26 -100px + 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
     23100% + -100px (where 100% is 200px) => PASS
     2480% - 60px (where 100% is 200px) => PASS
     25300px - 100% (where 100% is 200px) => PASS
     26-100px + 100% (where 100% is 200px) => PASS
    272720% + 30% (where 100% is 200px) => PASS
    282880% - 30% (where 100% is 200px) => PASS
  • trunk/Source/WebCore/ChangeLog

    r110120 r110126  
     12012-03-07  Mike Lawther  <mikelawther@chromium.org>
     2
     3        CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
     4        https://bugs.webkit.org/show_bug.cgi?id=79621
     5
     6        Reviewed by Andreas Kling.
     7
     8        ApplyPropertyLength in CSSStyleApplyPropery now handles mixed absolute/percentage
     9        length expressions. All property handlers using this template now work with
     10        mixed expressions.
     11
     12        This patch adds a new expression evaluator in CalculationValue.cpp. This is because
     13        Length.[cpp|h] (in platform) cannot refer to CSSCalculationValue.[cpp|h] (in css)
     14        due to layering restrictions.
     15
     16        Lengths can be copied, and so the expressions are stored in a hashmap, and only their
     17        ids are copied along with Length. The expressions are RefCounted, and will get
     18        cleaned up when the last referring Length is destructed.
     19
     20        * WebCore.exp.in:
     21        * css/CSSCalculationValue.cpp:
     22        (WebCore::CSSCalcPrimitiveValue::toCalcValue):
     23        (CSSCalcPrimitiveValue):
     24        (WebCore::CSSCalcBinaryOperation::toCalcValue):
     25        (CSSCalcBinaryOperation):
     26        * css/CSSCalculationValue.h:
     27        (WebCore):
     28        (CSSCalcExpressionNode):
     29        (CSSCalcValue):
     30        (WebCore::CSSCalcValue::toCalcValue):
     31        * css/CSSPrimitiveValue.cpp:
     32        (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
     33        * css/CSSStyleApplyProperty.cpp:
     34        (WebCore::ApplyPropertyLength::applyValue):
     35        * css/CSSStyleSelector.cpp:
     36        (WebCore::CSSStyleSelector::collectMatchingRulesForList):
     37        * css/CSSStyleSelector.h:
     38        (CSSStyleSelector):
     39        * platform/CalculationValue.cpp:
     40        (WebCore::CalcExpressionBinaryOperation::evaluate):
     41        (WebCore):
     42        (WebCore::CalculationValue::create):
     43        (WebCore::CalculationValue::evaluate):
     44        * platform/CalculationValue.h:
     45        (CalcExpressionNode):
     46        (WebCore::CalcExpressionNode::~CalcExpressionNode):
     47        (WebCore):
     48        (CalculationValue):
     49        (WebCore::CalculationValue::CalculationValue):
     50        (CalcExpressionNumber):
     51        (WebCore::CalcExpressionNumber::CalcExpressionNumber):
     52        (WebCore::CalcExpressionNumber::evaluate):
     53        (CalcExpressionLength):
     54        (WebCore::CalcExpressionLength::CalcExpressionLength):
     55        (WebCore::CalcExpressionLength::evaluate):
     56        (CalcExpressionBinaryOperation):
     57        (WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation):
     58        * platform/Length.cpp:
     59        (WebCore):
     60        (WebCore::Length::~Length):
     61        (CalculationValueHandleMap):
     62        (WebCore::CalculationValueHandleMap::CalculationValueHandleMap):
     63        (WebCore::CalculationValueHandleMap::insert):
     64        (WebCore::CalculationValueHandleMap::remove):
     65        (WebCore::CalculationValueHandleMap::get):
     66        (WebCore::calcHandles):
     67        (WebCore::Length::Length):
     68        (WebCore::Length::calculationValue):
     69        (WebCore::Length::calculatedValue):
     70        (WebCore::Length::calculatedMinValue):
     71        (WebCore::Length::calculatedFloatValue):
     72        (WebCore::Length::incrementCalculatedRef):
     73        (WebCore::Length::decrementCalculatedRef):
     74        (WebCore::Length::nonNanCalculatedValue):
     75        * platform/Length.h:
     76        (Length):
     77        (WebCore::Length::Length):
     78        (WebCore::Length::operator=):
     79        (WebCore::Length::operator*=):
     80        (WebCore::Length::value):
     81        (WebCore::Length::setValue):
     82        (WebCore::Length::calcValue):
     83        (WebCore::Length::calcMinValue):
     84        (WebCore::Length::calcFloatValue):
     85        (WebCore::Length::isZero):
     86        (WebCore::Length::isPositive):
     87        (WebCore::Length::isNegative):
     88        (WebCore::Length::isPercent):
     89        (WebCore::Length::isSpecified):
     90        (WebCore::Length::isCalculated):
     91        (WebCore::Length::initFromLength):
     92        (WebCore::Length::calculationHandle):
     93
    1942012-03-07  Emil A Eklund  <eae@chromium.org>
    295
  • trunk/Source/WebCore/WebCore.exp.in

    r110014 r110126  
    14231423__ZNK7WebCore6Editor9canDeleteEv
    14241424__ZNK7WebCore6JSNode21pushEventHandlerScopeEPN3JSC9ExecStateEPNS1_14ScopeChainNodeE
     1425__ZNK7WebCore6Length22decrementCalculatedRefEv
    14251426__ZNK7WebCore6Region5rectsEv
    14261427__ZNK7WebCore6Widget14platformWidgetEv
  • trunk/Source/WebCore/css/CSSCalculationValue.cpp

    r108750 r110126  
    115115    }
    116116
     117    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
     118    {
     119        switch (m_category) {
     120        case CalcNumber:
     121            return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue()));
     122        case CalcLength:
     123            return adoptPtr(new CalcExpressionNumber(m_value->computeLength<float>(style, rootStyle, zoom)));
     124        case CalcPercent:
     125        case CalcPercentLength:
     126            return adoptPtr(new CalcExpressionLength(CSSStyleSelector::convertToFloatLength(m_value.get(), style, rootStyle, zoom)));
     127        // Only types that could be part of a Length expression can be converted
     128        // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length.
     129        case CalcPercentNumber:
     130        case CalcOther:
     131            ASSERT_NOT_REACHED();
     132        }
     133        return nullptr;
     134    }
     135
    117136    virtual double doubleValue() const
    118137    {
     
    209228    }
    210229
     230    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
     231    {
     232        OwnPtr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom));
     233        if (!left)
     234            return nullptr;
     235        OwnPtr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom));
     236        if (!right)
     237            return nullptr;
     238        return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator));
     239    }
     240
    211241    virtual double doubleValue() const
    212242    {
  • trunk/Source/WebCore/css/CSSCalculationValue.h

    r108750 r110126  
    4444class CSSValueList;
    4545class RenderStyle;
    46 class CalcValue;
     46class CalculationValue;
    4747class CalcExpressionNode;
    4848
     
    5959public:
    6060   
    61     virtual ~CSSCalcExpressionNode() = 0; 
     61    virtual ~CSSCalcExpressionNode() = 0;
    6262    virtual bool isZero() const = 0;
     63    virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle*, RenderStyle* rootStyle, double zoom = 1.0) const = 0;   
    6364    virtual double doubleValue() const = 0;
    6465    virtual double computeLengthPx(RenderStyle* currentStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const = 0;
     
    8182public:
    8283    static PassRefPtr<CSSCalcValue> create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange);
     84    static PassRefPtr<CSSCalcValue> create(CalculationValue*);
    8385
     86    PassRefPtr<CalculationValue> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom = 1.0) const
     87    {
     88        return CalculationValue::create(m_expression->toCalcValue(style, rootStyle, zoom), m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll);
     89    }
    8490    CalculationCategory category() const { return m_expression->category(); }
    8591    bool isInt() const { return m_expression->isInteger(); }   
  • trunk/Source/WebCore/css/CSSPrimitiveValue.cpp

    r109785 r110126  
    267267            m_value.num = length.percent();
    268268            break;
     269        case Calculated:
    269270        case Relative:
    270271        case Undefined:
  • trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp

    r109806 r110126  
    2727
    2828#include "CSSAspectRatioValue.h"
     29#include "CSSCalculationValue.h"
    2930#include "CSSCursorImageValue.h"
    3031#include "CSSFlexValue.h"
     
    390391            } else if (primitiveValue->isPercentage())
    391392                setValue(selector->style(), Length(primitiveValue->getDoubleValue(), Percent));
     393            else if (primitiveValue->isCalculatedPercentageWithLength())
     394                setValue(selector->style(), Length(primitiveValue->cssCalcValue()->toCalcValue(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom())));           
    392395        }
    393396    }
  • trunk/Source/WebCore/css/CSSStyleSelector.cpp

    r109964 r110126  
    3131#include "Attribute.h"
    3232#include "CachedImage.h"
     33#include "CalculationValue.h"
    3334#include "ContentData.h"
    3435#include "Counter.h"
    3536#include "CounterContent.h"
    3637#include "CSSBorderImage.h"
     38#include "CSSCalculationValue.h"
    3739#include "CSSCursorImageValue.h"
    3840#include "CSSFontFaceRule.h"
     
    25482550}
    25492551
    2550 static Length convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
     2552Length CSSStyleSelector::convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
    25512553{
    25522554    return convertToLength(primitiveValue, style, rootStyle, false, multiplier);
    25532555}
    25542556
    2555 static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
     2557Length CSSStyleSelector::convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
    25562558{
    25572559    return convertToLength(primitiveValue, style, rootStyle, true, multiplier);
  • trunk/Source/WebCore/css/CSSStyleSelector.h

    r109563 r110126  
    363363    bool applyPropertyToVisitedLinkStyle() const { return m_applyPropertyToVisitedLinkStyle; }
    364364
     365    static Length convertToIntLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
     366    static Length convertToFloatLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
     367
    365368private:
    366369    static RenderStyle* s_styleNotYetAvailable;
  • trunk/Source/WebCore/platform/CalculationValue.cpp

    r106166 r110126  
    3232#include "CalculationValue.h"
    3333
     34#include <limits>
     35
    3436namespace WebCore {
    3537
     38float CalcExpressionBinaryOperation::evaluate(float maxValue) const
     39{
     40    float left = m_leftSide->evaluate(maxValue);
     41    float right = m_rightSide->evaluate(maxValue);
     42    switch (m_operator) {
     43    case CalcAdd:
     44        return left + right;
     45    case CalcSubtract:
     46        return left - right;
     47    case CalcMultiply:
     48        return left * right;
     49    case CalcDivide:
     50        if (!right)
     51            return std::numeric_limits<float>::quiet_NaN();
     52        return left / right;
     53    }
     54    ASSERT_NOT_REACHED();
     55    return std::numeric_limits<float>::quiet_NaN();
     56}
     57
     58PassRefPtr<CalculationValue> CalculationValue::create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
     59{
     60    return adoptRef(new CalculationValue(value, range));
     61}
     62
     63float CalculationValue::evaluate(float maxValue) const
     64{
     65    float result = m_value->evaluate(maxValue);
     66    // FIXME calc https://webkit.org/b/80411 : result is NaN when there is a division
     67    // by zero which isn't found at parse time.
     68    if (isnan(result))
     69        return 0;
     70    return m_isNonNegative && result < 0 ? 0 : result;
     71}
     72
    3673} // namespace WebCore
  • trunk/Source/WebCore/platform/CalculationValue.h

    r108750 r110126  
    5151    CalculationRangeNonNegative
    5252};
     53       
     54class CalcExpressionNode {
     55public:
     56    virtual ~CalcExpressionNode()
     57    {
     58    }
     59   
     60    virtual float evaluate(float maxValue) const = 0;
     61};
     62   
     63class CalculationValue : public RefCounted<CalculationValue> {
     64public:
     65    static PassRefPtr<CalculationValue> create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange);
     66    float evaluate(float maxValue) const;
     67   
     68private:
     69    CalculationValue(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
     70        : m_value(value)
     71        , m_isNonNegative(range == CalculationRangeNonNegative)
     72    {
     73    }
     74   
     75    OwnPtr<CalcExpressionNode> m_value;
     76    bool m_isNonNegative;
     77};
     78
     79class CalcExpressionNumber : public CalcExpressionNode {
     80public:
     81    explicit CalcExpressionNumber(float value)
     82        : m_value(value)
     83    {
     84    }
     85
     86    virtual float evaluate(float) const
     87    {
     88        return m_value;
     89    }
     90   
     91private:
     92    float m_value;
     93};
     94
     95class CalcExpressionLength : public CalcExpressionNode {
     96public:
     97    explicit CalcExpressionLength(Length length)
     98        : m_length(length)
     99    {
     100    }
     101
     102    virtual float evaluate(float maxValue) const
     103    {
     104        return m_length.calcFloatValue(maxValue);
     105    }
     106   
     107private:
     108    Length m_length;
     109};
     110
     111class CalcExpressionBinaryOperation : public CalcExpressionNode {
     112public:
     113    CalcExpressionBinaryOperation(PassOwnPtr<CalcExpressionNode> leftSide, PassOwnPtr<CalcExpressionNode> rightSide, CalcOperator op)
     114        : m_leftSide(leftSide)
     115        , m_rightSide(rightSide)
     116        , m_operator(op)
     117    {
     118    }
     119
     120    virtual float evaluate(float) const;
     121
     122private:
     123    OwnPtr<CalcExpressionNode> m_leftSide;
     124    OwnPtr<CalcExpressionNode> m_rightSide;
     125    CalcOperator m_operator;
     126};
    53127
    54128} // namespace WebCore
  • trunk/Source/WebCore/platform/Length.cpp

    r107487 r110126  
    2626#include "Length.h"
    2727
     28#include "CalculationValue.h"
    2829#include "PlatformString.h"
    2930#include <wtf/ASCIICType.h>
     
    149150    return r.release();
    150151}
     152       
     153class CalculationValueHandleMap {
     154public:
     155    CalculationValueHandleMap()
     156        : m_index(1)
     157    {
     158    }
     159   
     160    int insert(PassRefPtr<CalculationValue> calcValue)
     161    {
     162        ASSERT(m_index);
     163        // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
     164        // This monotonically increasing handle generation scheme is potentially wasteful
     165        // of the handle space. Consider reusing empty handles.
     166        while (m_map.contains(m_index))
     167            m_index++;
     168       
     169        m_map.set(m_index, calcValue);       
     170       
     171        return m_index;
     172    }
     173
     174    void remove(int index)
     175    {
     176        ASSERT(m_map.contains(index));
     177        m_map.remove(index);
     178    }
     179   
     180    PassRefPtr<CalculationValue> get(int index)
     181    {
     182        ASSERT(m_map.contains(index));
     183        return m_map.get(index);
     184    }
     185   
     186private:       
     187    int m_index;
     188    HashMap<int, RefPtr<CalculationValue> > m_map;
     189};
     190   
     191static CalculationValueHandleMap& calcHandles()
     192{
     193    DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
     194    return handleMap;
     195}
     196
     197Length::Length(PassRefPtr<CalculationValue> calc)
     198    : m_quirk(false)
     199    , m_type(Calculated)
     200    , m_isFloat(false)
     201{
     202    m_intValue = calcHandles().insert(calc);
     203}
     204   
     205PassRefPtr<CalculationValue> Length::calculationValue() const
     206{
     207    ASSERT(isCalculated());
     208    return calcHandles().get(calculationHandle());
     209}
     210   
     211void Length::incrementCalculatedRef() const
     212{
     213    ASSERT(isCalculated());
     214    calculationValue()->ref();
     215}
     216
     217void Length::decrementCalculatedRef() const
     218{
     219    ASSERT(isCalculated());
     220    RefPtr<CalculationValue> calcLength = calculationValue();
     221    if (calcLength->hasOneRef())
     222        calcHandles().remove(calculationHandle());
     223    calcLength->deref();
     224}   
     225
     226float Length::nonNanCalculatedValue(int maxValue) const
     227{
     228    ASSERT(isCalculated());
     229    float result = calculationValue()->evaluate(maxValue);
     230    if (isnan(result))
     231        return 0;
     232    return result;
     233}
    151234
    152235class SameSizeAsLength {
  • trunk/Source/WebCore/platform/Length.h

    r109785 r110126  
    2727#include <wtf/FastAllocBase.h>
    2828#include <wtf/Forward.h>
     29#include <wtf/HashMap.h>
    2930#include <wtf/MathExtras.h>
    3031#include <wtf/PassOwnArrayPtr.h>
     
    3536const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
    3637
    37 enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Undefined };
    38 
     38enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Calculated, Undefined };
     39 
     40class CalculationValue;   
     41   
    3942struct Length {
    4043    WTF_MAKE_FAST_ALLOCATED;
     
    6669    }
    6770
     71    explicit Length(PassRefPtr<CalculationValue>);
     72
     73    Length(const Length& length)
     74    {
     75        initFromLength(length);
     76    }
     77   
     78    Length& operator=(const Length& length)
     79    {
     80        initFromLength(length);
     81        return *this;
     82    }
     83   
     84    ~Length()
     85    {
     86        if (isCalculated())
     87            decrementCalculatedRef();
     88    } 
     89   
    6890    bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue())); }
    6991    bool operator!=(const Length& o) const { return !(*this == o); }
    7092
    7193    const Length& operator*=(float v)
    72     {       
     94    {       
     95        if (isCalculated()) {
     96            ASSERT_NOT_REACHED();
     97            return *this;
     98        }
     99       
    73100        if (m_isFloat)
    74101            m_floatValue = static_cast<float>(m_floatValue * v);
     
    81108    int value() const
    82109    {
     110        if (isCalculated()) {
     111            ASSERT_NOT_REACHED();
     112            return 0;
     113        }
    83114        return getIntValue();
    84115    }
     
    89120        return getFloatValue();
    90121    }
     122
     123    PassRefPtr<CalculationValue> calculationValue() const;
    91124
    92125    LengthType type() const { return static_cast<LengthType>(m_type); }
     
    107140    void setValue(int value)
    108141    {
     142        if (isCalculated()) {
     143            ASSERT_NOT_REACHED();
     144            return;
     145        }
    109146        setValue(Fixed, value);
    110147    }
     
    122159    }
    123160
    124     // Note: May only be called for Fixed, Percent and Auto lengths.
    125     // Other types will ASSERT in order to catch invalid length calculations.
    126161    int calcValue(int maxValue, bool roundPercentages = false) const
    127162    {
     
    129164            case Fixed:
    130165            case Percent:
     166            case Calculated:
    131167                return calcMinValue(maxValue, roundPercentages);
    132168            case Auto:
     
    153189                // Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
    154190                return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
     191            case Calculated:
     192                return nonNanCalculatedValue(maxValue);
    155193            case Auto:
    156194                return 0;
     
    175213            case Auto:
    176214                return static_cast<float>(maxValue);
     215            case Calculated:
     216                return nonNanCalculatedValue(maxValue);               
    177217            case Relative:
    178218            case Intrinsic:
     
    187227
    188228    bool isUndefined() const { return type() == Undefined; }
     229
     230    // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
     231    // always contains a percentage, and without a maxValue passed to these functions
     232    // it's impossible to determine the sign or zero-ness. We assume all calc values
     233    // are positive and non-zero for now.   
    189234    bool isZero() const
    190235    {
    191236        ASSERT(!isUndefined());
     237        if (isCalculated())
     238            return false;
     239           
    192240        return m_isFloat ? !m_floatValue : !m_intValue;
    193241    }
    194    
    195     bool isPositive() const { return isUndefined() ? false : getFloatValue() > 0; }
    196     bool isNegative() const { return isUndefined() ? false : getFloatValue() < 0; }
    197 
     242    bool isPositive() const
     243    {
     244        if (isUndefined())
     245            return false;
     246        if (isCalculated())
     247            return true;
     248               
     249        return getFloatValue() > 0;
     250    }
     251    bool isNegative() const
     252    {
     253        if (isUndefined() || isCalculated())
     254            return false;
     255           
     256        return getFloatValue() < 0;
     257    }
     258   
    198259    bool isAuto() const { return type() == Auto; }
    199260    bool isRelative() const { return type() == Relative; }
    200     bool isPercent() const { return type() == Percent; }
     261    bool isPercent() const { return type() == Percent || type() == Calculated; }
    201262    bool isFixed() const { return type() == Fixed; }
    202263    bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
    203     bool isSpecified() const { return type() == Fixed || type() == Percent; }
     264    bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
     265    bool isCalculated() const { return type() == Calculated; }
    204266
    205267    Length blend(const Length& from, double progress) const
     
    240302    }
    241303
     304    void initFromLength(const Length &length)
     305    {
     306        m_quirk = length.m_quirk;
     307        m_type = length.m_type;
     308        m_isFloat = length.m_isFloat;
     309       
     310        if (m_isFloat)
     311            m_floatValue = length.m_floatValue;
     312        else
     313            m_intValue = length.m_intValue;
     314       
     315        if (isCalculated())
     316            incrementCalculatedRef();
     317    }
     318   
     319    float nonNanCalculatedValue(int maxValue) const;
     320    int calculationHandle() const
     321    {
     322        ASSERT(isCalculated());
     323        return getIntValue();
     324    }
     325    void incrementCalculatedRef() const;
     326    void decrementCalculatedRef() const;   
     327   
    242328    union {
    243329        int m_intValue;
Note: See TracChangeset for help on using the changeset viewer.