Diff
Modified: trunk/LayoutTests/ChangeLog (110147 => 110148)
--- trunk/LayoutTests/ChangeLog 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/ChangeLog 2012-03-08 06:48:35 UTC (rev 110148)
@@ -1,3 +1,14 @@
+2012-03-07 Mike Lawther <mikelawt...@chromium.org>
+
+ CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
+ https://bugs.webkit.org/show_bug.cgi?id=79621
+
+ Reviewed by Andreas Kling.
+
+ * css3/calc/margin-expected.txt:
+ * css3/calc/padding-expected.txt:
+ * css3/calc/simple-calcs-expected.txt:
+
2012-03-07 Fumitoshi Ukai <u...@chromium.org>
Unreviewed. update chromium test expectations.
Modified: trunk/LayoutTests/css3/calc/margin-expected.txt (110147 => 110148)
--- trunk/LayoutTests/css3/calc/margin-expected.txt 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/margin-expected.txt 2012-03-08 06:48:35 UTC (rev 110148)
@@ -18,26 +18,26 @@
PASS computedMarginTop("simple-bottom") is "0px"
PASS computedMarginRight("simple-bottom") is "0px"
PASS computedMarginBottom("simple-bottom") is "25px"
-FAIL computedMarginLeft("percent-all") should be 25px. Was 0px.
-FAIL computedMarginTop("percent-all") should be 25px. Was 0px.
-FAIL computedMarginRight("percent-all") should be 25px. Was 0px.
-FAIL computedMarginBottom("percent-all") should be 25px. Was 0px.
-FAIL computedMarginLeft("percent-left") should be 25px. Was 0px.
+PASS computedMarginLeft("percent-all") is "25px"
+PASS computedMarginTop("percent-all") is "25px"
+PASS computedMarginRight("percent-all") is "25px"
+PASS computedMarginBottom("percent-all") is "25px"
+PASS computedMarginLeft("percent-left") is "25px"
PASS computedMarginTop("percent-left") is "0px"
PASS computedMarginRight("percent-left") is "0px"
PASS computedMarginBottom("percent-left") is "0px"
PASS computedMarginLeft("percent-right") is "0px"
PASS computedMarginTop("percent-right") is "0px"
-FAIL computedMarginRight("percent-right") should be 25px. Was 0px.
+PASS computedMarginRight("percent-right") is "25px"
PASS computedMarginBottom("percent-right") is "0px"
PASS computedMarginLeft("percent-top") is "0px"
-FAIL computedMarginTop("percent-top") should be 25px. Was 0px.
+PASS computedMarginTop("percent-top") is "25px"
PASS computedMarginRight("percent-top") is "0px"
PASS computedMarginBottom("percent-top") is "0px"
PASS computedMarginLeft("percent-bottom") is "0px"
PASS computedMarginTop("percent-bottom") is "0px"
PASS computedMarginRight("percent-bottom") is "0px"
-FAIL computedMarginBottom("percent-bottom") should be 25px. Was 0px.
+PASS computedMarginBottom("percent-bottom") is "25px"
PASS successfullyParsed is true
TEST COMPLETE
Modified: trunk/LayoutTests/css3/calc/padding-expected.txt (110147 => 110148)
--- trunk/LayoutTests/css3/calc/padding-expected.txt 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/padding-expected.txt 2012-03-08 06:48:35 UTC (rev 110148)
@@ -8,12 +8,12 @@
This element should have a bottom padding of 25 pixels. => PASS
-This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width, wrong height
+This element should have an overall padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
-This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
+This element should have a left padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
-This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong width
+This element should have a right padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
-This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
+This element should have a top padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
-This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => FAIL: wrong height
+This element should have a bottom padding of 25 pixels (10% of parent width of 300px minus 5px). => PASS
Modified: trunk/LayoutTests/css3/calc/simple-calcs-expected.txt (110147 => 110148)
--- trunk/LayoutTests/css3/calc/simple-calcs-expected.txt 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/LayoutTests/css3/calc/simple-calcs-expected.txt 2012-03-08 06:48:35 UTC (rev 110148)
@@ -20,10 +20,10 @@
10px* (5 * 2) => PASS
50px + 10px * 5 (operation order) => PASS
100%/2 (where 100% is 200px) => PASS
-100% + -100px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
-80% - 60px (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
-300px - 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
--100px + 100% (where 100% is 200px) => FAIL: @zoom=1 expected width of 100, but was 256; @zoom=1.2 expected width of 100, but was 256; @zoom=2 expected width of 100, but was 256
+100% + -100px (where 100% is 200px) => PASS
+80% - 60px (where 100% is 200px) => PASS
+300px - 100% (where 100% is 200px) => PASS
+-100px + 100% (where 100% is 200px) => PASS
20% + 30% (where 100% is 200px) => PASS
80% - 30% (where 100% is 200px) => PASS
10% * 5 (where 100% is 200px) => PASS
Modified: trunk/Source/WebCore/ChangeLog (110147 => 110148)
--- trunk/Source/WebCore/ChangeLog 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/ChangeLog 2012-03-08 06:48:35 UTC (rev 110148)
@@ -1,3 +1,96 @@
+2012-03-07 Mike Lawther <mikelawt...@chromium.org>
+
+ CSS3 calc: mixed absolute/percentages work for width, height, margin and padding
+ https://bugs.webkit.org/show_bug.cgi?id=79621
+
+ Reviewed by Andreas Kling.
+
+ ApplyPropertyLength in CSSStyleApplyPropery now handles mixed absolute/percentage
+ length expressions. All property handlers using this template now work with
+ mixed expressions.
+
+ This patch adds a new _expression_ evaluator in CalculationValue.cpp. This is because
+ Length.[cpp|h] (in platform) cannot refer to CSSCalculationValue.[cpp|h] (in css)
+ due to layering restrictions.
+
+ Lengths can be copied, and so the expressions are stored in a hashmap, and only their
+ ids are copied along with Length. The expressions are RefCounted, and will get
+ cleaned up when the last referring Length is destructed.
+
+ * WebCore.exp.in:
+ * css/CSSCalculationValue.cpp:
+ (WebCore::CSSCalcPrimitiveValue::toCalcValue):
+ (CSSCalcPrimitiveValue):
+ (WebCore::CSSCalcBinaryOperation::toCalcValue):
+ (CSSCalcBinaryOperation):
+ * css/CSSCalculationValue.h:
+ (WebCore):
+ (CSSCalcExpressionNode):
+ (CSSCalcValue):
+ (WebCore::CSSCalcValue::toCalcValue):
+ * css/CSSPrimitiveValue.cpp:
+ (WebCore::CSSPrimitiveValue::CSSPrimitiveValue):
+ * css/CSSStyleApplyProperty.cpp:
+ (WebCore::ApplyPropertyLength::applyValue):
+ * css/CSSStyleSelector.cpp:
+ (WebCore::CSSStyleSelector::collectMatchingRulesForList):
+ * css/CSSStyleSelector.h:
+ (CSSStyleSelector):
+ * platform/CalculationValue.cpp:
+ (WebCore::CalcExpressionBinaryOperation::evaluate):
+ (WebCore):
+ (WebCore::CalculationValue::create):
+ (WebCore::CalculationValue::evaluate):
+ * platform/CalculationValue.h:
+ (CalcExpressionNode):
+ (WebCore::CalcExpressionNode::~CalcExpressionNode):
+ (WebCore):
+ (CalculationValue):
+ (WebCore::CalculationValue::CalculationValue):
+ (CalcExpressionNumber):
+ (WebCore::CalcExpressionNumber::CalcExpressionNumber):
+ (WebCore::CalcExpressionNumber::evaluate):
+ (CalcExpressionLength):
+ (WebCore::CalcExpressionLength::CalcExpressionLength):
+ (WebCore::CalcExpressionLength::evaluate):
+ (CalcExpressionBinaryOperation):
+ (WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation):
+ * platform/Length.cpp:
+ (WebCore):
+ (WebCore::Length::~Length):
+ (CalculationValueHandleMap):
+ (WebCore::CalculationValueHandleMap::CalculationValueHandleMap):
+ (WebCore::CalculationValueHandleMap::insert):
+ (WebCore::CalculationValueHandleMap::remove):
+ (WebCore::CalculationValueHandleMap::get):
+ (WebCore::calcHandles):
+ (WebCore::Length::Length):
+ (WebCore::Length::calculationValue):
+ (WebCore::Length::calculatedValue):
+ (WebCore::Length::calculatedMinValue):
+ (WebCore::Length::calculatedFloatValue):
+ (WebCore::Length::incrementCalculatedRef):
+ (WebCore::Length::decrementCalculatedRef):
+ (WebCore::Length::nonNanCalculatedValue):
+ * platform/Length.h:
+ (Length):
+ (WebCore::Length::Length):
+ (WebCore::Length::operator=):
+ (WebCore::Length::operator*=):
+ (WebCore::Length::value):
+ (WebCore::Length::setValue):
+ (WebCore::Length::calcValue):
+ (WebCore::Length::calcMinValue):
+ (WebCore::Length::calcFloatValue):
+ (WebCore::Length::isZero):
+ (WebCore::Length::isPositive):
+ (WebCore::Length::isNegative):
+ (WebCore::Length::isPercent):
+ (WebCore::Length::isSpecified):
+ (WebCore::Length::isCalculated):
+ (WebCore::Length::initFromLength):
+ (WebCore::Length::calculationHandle):
+
2012-03-07 Kent Tamura <tk...@chromium.org>
Do not refer to resutlsButtonElement and cancelButtonElement to compute paddings of search popups
Modified: trunk/Source/WebCore/WebCore.exp.in (110147 => 110148)
--- trunk/Source/WebCore/WebCore.exp.in 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/WebCore.exp.in 2012-03-08 06:48:35 UTC (rev 110148)
@@ -1422,6 +1422,7 @@
__ZNK7WebCore6Editor8canPasteEv
__ZNK7WebCore6Editor9canDeleteEv
__ZNK7WebCore6JSNode21pushEventHandlerScopeEPN3JSC9ExecStateEPNS1_14ScopeChainNodeE
+__ZNK7WebCore6Length22decrementCalculatedRefEv
__ZNK7WebCore6Region5rectsEv
__ZNK7WebCore6Widget14platformWidgetEv
__ZNK7WebCore6Widget23convertToContainingViewERKNS_7IntRectE
Modified: trunk/Source/WebCore/css/CSSCalculationValue.cpp (110147 => 110148)
--- trunk/Source/WebCore/css/CSSCalculationValue.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSCalculationValue.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -114,6 +114,25 @@
return m_value->cssText();
}
+ virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
+ {
+ switch (m_category) {
+ case CalcNumber:
+ return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue()));
+ case CalcLength:
+ return adoptPtr(new CalcExpressionNumber(m_value->computeLength<float>(style, rootStyle, zoom)));
+ case CalcPercent:
+ case CalcPercentLength:
+ return adoptPtr(new CalcExpressionLength(CSSStyleSelector::convertToFloatLength(m_value.get(), style, rootStyle, zoom)));
+ // Only types that could be part of a Length _expression_ can be converted
+ // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length.
+ case CalcPercentNumber:
+ case CalcOther:
+ ASSERT_NOT_REACHED();
+ }
+ return nullptr;
+ }
+
virtual double doubleValue() const
{
switch (m_category) {
@@ -208,6 +227,17 @@
return !doubleValue();
}
+ virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom) const
+ {
+ OwnPtr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom));
+ if (!left)
+ return nullptr;
+ OwnPtr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom));
+ if (!right)
+ return nullptr;
+ return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator));
+ }
+
virtual double doubleValue() const
{
return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
Modified: trunk/Source/WebCore/css/CSSCalculationValue.h (110147 => 110148)
--- trunk/Source/WebCore/css/CSSCalculationValue.h 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSCalculationValue.h 2012-03-08 06:48:35 UTC (rev 110148)
@@ -43,7 +43,7 @@
class CSSParserValueList;
class CSSValueList;
class RenderStyle;
-class CalcValue;
+class CalculationValue;
class CalcExpressionNode;
enum CalculationCategory {
@@ -58,8 +58,9 @@
class CSSCalcExpressionNode : public RefCounted<CSSCalcExpressionNode> {
public:
- virtual ~CSSCalcExpressionNode() = 0;
+ virtual ~CSSCalcExpressionNode() = 0;
virtual bool isZero() const = 0;
+ virtual PassOwnPtr<CalcExpressionNode> toCalcValue(RenderStyle*, RenderStyle* rootStyle, double zoom = 1.0) const = 0;
virtual double doubleValue() const = 0;
virtual double computeLengthPx(RenderStyle* currentStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false) const = 0;
@@ -80,7 +81,12 @@
class CSSCalcValue : public CSSValue {
public:
static PassRefPtr<CSSCalcValue> create(CSSParserString name, CSSParserValueList*, CalculationPermittedValueRange);
+ static PassRefPtr<CSSCalcValue> create(CalculationValue*);
+ PassRefPtr<CalculationValue> toCalcValue(RenderStyle* style, RenderStyle* rootStyle, double zoom = 1.0) const
+ {
+ return CalculationValue::create(m_expression->toCalcValue(style, rootStyle, zoom), m_nonNegative ? CalculationRangeNonNegative : CalculationRangeAll);
+ }
CalculationCategory category() const { return m_expression->category(); }
bool isInt() const { return m_expression->isInteger(); }
double doubleValue() const;
Modified: trunk/Source/WebCore/css/CSSPrimitiveValue.cpp (110147 => 110148)
--- trunk/Source/WebCore/css/CSSPrimitiveValue.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSPrimitiveValue.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -266,6 +266,7 @@
ASSERT(isfinite(length.percent()));
m_value.num = length.percent();
break;
+ case Calculated:
case Relative:
case Undefined:
ASSERT_NOT_REACHED();
Modified: trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp (110147 => 110148)
--- trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleApplyProperty.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -26,6 +26,7 @@
#include "CSSStyleApplyProperty.h"
#include "CSSAspectRatioValue.h"
+#include "CSSCalculationValue.h"
#include "CSSCursorImageValue.h"
#include "CSSFlexValue.h"
#include "CSSPrimitiveValueMappings.h"
@@ -389,6 +390,8 @@
setValue(selector->style(), length);
} else if (primitiveValue->isPercentage())
setValue(selector->style(), Length(primitiveValue->getDoubleValue(), Percent));
+ else if (primitiveValue->isCalculatedPercentageWithLength())
+ setValue(selector->style(), Length(primitiveValue->cssCalcValue()->toCalcValue(selector->style(), selector->rootElementStyle(), selector->style()->effectiveZoom())));
}
}
Modified: trunk/Source/WebCore/css/CSSStyleSelector.cpp (110147 => 110148)
--- trunk/Source/WebCore/css/CSSStyleSelector.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleSelector.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -30,10 +30,12 @@
#include "Attribute.h"
#include "CachedImage.h"
+#include "CalculationValue.h"
#include "ContentData.h"
#include "Counter.h"
#include "CounterContent.h"
#include "CSSBorderImage.h"
+#include "CSSCalculationValue.h"
#include "CSSCursorImageValue.h"
#include "CSSFontFaceRule.h"
#include "CSSFontSelector.h"
@@ -2547,12 +2549,12 @@
return l;
}
-static Length convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
+Length CSSStyleSelector::convertToIntLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
{
return convertToLength(primitiveValue, style, rootStyle, false, multiplier);
}
-static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier = 1)
+Length CSSStyleSelector::convertToFloatLength(CSSPrimitiveValue* primitiveValue, RenderStyle* style, RenderStyle* rootStyle, double multiplier)
{
return convertToLength(primitiveValue, style, rootStyle, true, multiplier);
}
Modified: trunk/Source/WebCore/css/CSSStyleSelector.h (110147 => 110148)
--- trunk/Source/WebCore/css/CSSStyleSelector.h 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/css/CSSStyleSelector.h 2012-03-08 06:48:35 UTC (rev 110148)
@@ -362,6 +362,9 @@
bool applyPropertyToRegularStyle() const { return m_applyPropertyToRegularStyle; }
bool applyPropertyToVisitedLinkStyle() const { return m_applyPropertyToVisitedLinkStyle; }
+ static Length convertToIntLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
+ static Length convertToFloatLength(CSSPrimitiveValue*, RenderStyle*, RenderStyle* rootStyle, double multiplier = 1);
+
private:
static RenderStyle* s_styleNotYetAvailable;
Modified: trunk/Source/WebCore/platform/CalculationValue.cpp (110147 => 110148)
--- trunk/Source/WebCore/platform/CalculationValue.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/CalculationValue.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -31,6 +31,43 @@
#include "config.h"
#include "CalculationValue.h"
+#include <limits>
+
namespace WebCore {
+float CalcExpressionBinaryOperation::evaluate(float maxValue) const
+{
+ float left = m_leftSide->evaluate(maxValue);
+ float right = m_rightSide->evaluate(maxValue);
+ switch (m_operator) {
+ case CalcAdd:
+ return left + right;
+ case CalcSubtract:
+ return left - right;
+ case CalcMultiply:
+ return left * right;
+ case CalcDivide:
+ if (!right)
+ return std::numeric_limits<float>::quiet_NaN();
+ return left / right;
+ }
+ ASSERT_NOT_REACHED();
+ return std::numeric_limits<float>::quiet_NaN();
+}
+
+PassRefPtr<CalculationValue> CalculationValue::create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+{
+ return adoptRef(new CalculationValue(value, range));
+}
+
+float CalculationValue::evaluate(float maxValue) const
+{
+ float result = m_value->evaluate(maxValue);
+ // FIXME calc https://webkit.org/b/80411 : result is NaN when there is a division
+ // by zero which isn't found at parse time.
+ if (isnan(result))
+ return 0;
+ return m_isNonNegative && result < 0 ? 0 : result;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/CalculationValue.h (110147 => 110148)
--- trunk/Source/WebCore/platform/CalculationValue.h 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/CalculationValue.h 2012-03-08 06:48:35 UTC (rev 110148)
@@ -50,7 +50,81 @@
CalculationRangeAll,
CalculationRangeNonNegative
};
+
+class CalcExpressionNode {
+public:
+ virtual ~CalcExpressionNode()
+ {
+ }
+
+ virtual float evaluate(float maxValue) const = 0;
+};
+
+class CalculationValue : public RefCounted<CalculationValue> {
+public:
+ static PassRefPtr<CalculationValue> create(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange);
+ float evaluate(float maxValue) const;
+
+private:
+ CalculationValue(PassOwnPtr<CalcExpressionNode> value, CalculationPermittedValueRange range)
+ : m_value(value)
+ , m_isNonNegative(range == CalculationRangeNonNegative)
+ {
+ }
+
+ OwnPtr<CalcExpressionNode> m_value;
+ bool m_isNonNegative;
+};
+class CalcExpressionNumber : public CalcExpressionNode {
+public:
+ explicit CalcExpressionNumber(float value)
+ : m_value(value)
+ {
+ }
+
+ virtual float evaluate(float) const
+ {
+ return m_value;
+ }
+
+private:
+ float m_value;
+};
+
+class CalcExpressionLength : public CalcExpressionNode {
+public:
+ explicit CalcExpressionLength(Length length)
+ : m_length(length)
+ {
+ }
+
+ virtual float evaluate(float maxValue) const
+ {
+ return m_length.calcFloatValue(maxValue);
+ }
+
+private:
+ Length m_length;
+};
+
+class CalcExpressionBinaryOperation : public CalcExpressionNode {
+public:
+ CalcExpressionBinaryOperation(PassOwnPtr<CalcExpressionNode> leftSide, PassOwnPtr<CalcExpressionNode> rightSide, CalcOperator op)
+ : m_leftSide(leftSide)
+ , m_rightSide(rightSide)
+ , m_operator(op)
+ {
+ }
+
+ virtual float evaluate(float) const;
+
+private:
+ OwnPtr<CalcExpressionNode> m_leftSide;
+ OwnPtr<CalcExpressionNode> m_rightSide;
+ CalcOperator m_operator;
+};
+
} // namespace WebCore
#endif // CalculationValue_h
Modified: trunk/Source/WebCore/platform/Length.cpp (110147 => 110148)
--- trunk/Source/WebCore/platform/Length.cpp 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/Length.cpp 2012-03-08 06:48:35 UTC (rev 110148)
@@ -25,6 +25,7 @@
#include "config.h"
#include "Length.h"
+#include "CalculationValue.h"
#include "PlatformString.h"
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
@@ -148,7 +149,89 @@
return r.release();
}
+
+class CalculationValueHandleMap {
+public:
+ CalculationValueHandleMap()
+ : m_index(1)
+ {
+ }
+
+ int insert(PassRefPtr<CalculationValue> calcValue)
+ {
+ ASSERT(m_index);
+ // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
+ // This monotonically increasing handle generation scheme is potentially wasteful
+ // of the handle space. Consider reusing empty handles.
+ while (m_map.contains(m_index))
+ m_index++;
+
+ m_map.set(m_index, calcValue);
+
+ return m_index;
+ }
+ void remove(int index)
+ {
+ ASSERT(m_map.contains(index));
+ m_map.remove(index);
+ }
+
+ PassRefPtr<CalculationValue> get(int index)
+ {
+ ASSERT(m_map.contains(index));
+ return m_map.get(index);
+ }
+
+private:
+ int m_index;
+ HashMap<int, RefPtr<CalculationValue> > m_map;
+};
+
+static CalculationValueHandleMap& calcHandles()
+{
+ DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handleMap, ());
+ return handleMap;
+}
+
+Length::Length(PassRefPtr<CalculationValue> calc)
+ : m_quirk(false)
+ , m_type(Calculated)
+ , m_isFloat(false)
+{
+ m_intValue = calcHandles().insert(calc);
+}
+
+PassRefPtr<CalculationValue> Length::calculationValue() const
+{
+ ASSERT(isCalculated());
+ return calcHandles().get(calculationHandle());
+}
+
+void Length::incrementCalculatedRef() const
+{
+ ASSERT(isCalculated());
+ calculationValue()->ref();
+}
+
+void Length::decrementCalculatedRef() const
+{
+ ASSERT(isCalculated());
+ RefPtr<CalculationValue> calcLength = calculationValue();
+ if (calcLength->hasOneRef())
+ calcHandles().remove(calculationHandle());
+ calcLength->deref();
+}
+
+float Length::nonNanCalculatedValue(int maxValue) const
+{
+ ASSERT(isCalculated());
+ float result = calculationValue()->evaluate(maxValue);
+ if (isnan(result))
+ return 0;
+ return result;
+}
+
class SameSizeAsLength {
int32_t value;
int32_t metaData;
Modified: trunk/Source/WebCore/platform/Length.h (110147 => 110148)
--- trunk/Source/WebCore/platform/Length.h 2012-03-08 06:15:01 UTC (rev 110147)
+++ trunk/Source/WebCore/platform/Length.h 2012-03-08 06:48:35 UTC (rev 110148)
@@ -26,6 +26,7 @@
#include <wtf/Assertions.h>
#include <wtf/FastAllocBase.h>
#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
#include <wtf/PassOwnArrayPtr.h>
@@ -34,8 +35,10 @@
const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int
const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int
-enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Undefined };
-
+enum LengthType { Auto, Relative, Percent, Fixed, Intrinsic, MinIntrinsic, Calculated, Undefined };
+
+class CalculationValue;
+
struct Length {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -65,11 +68,35 @@
m_floatValue = static_cast<float>(v);
}
+ explicit Length(PassRefPtr<CalculationValue>);
+
+ Length(const Length& length)
+ {
+ initFromLength(length);
+ }
+
+ Length& operator=(const Length& length)
+ {
+ initFromLength(length);
+ return *this;
+ }
+
+ ~Length()
+ {
+ if (isCalculated())
+ decrementCalculatedRef();
+ }
+
bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue())); }
bool operator!=(const Length& o) const { return !(*this == o); }
const Length& operator*=(float v)
- {
+ {
+ if (isCalculated()) {
+ ASSERT_NOT_REACHED();
+ return *this;
+ }
+
if (m_isFloat)
m_floatValue = static_cast<float>(m_floatValue * v);
else
@@ -80,6 +107,10 @@
int value() const
{
+ if (isCalculated()) {
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
return getIntValue();
}
@@ -89,6 +120,8 @@
return getFloatValue();
}
+ PassRefPtr<CalculationValue> calculationValue() const;
+
LengthType type() const { return static_cast<LengthType>(m_type); }
bool quirk() const { return m_quirk; }
@@ -106,6 +139,10 @@
void setValue(int value)
{
+ if (isCalculated()) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
setValue(Fixed, value);
}
@@ -121,13 +158,12 @@
*this = Length(value, Fixed);
}
- // Note: May only be called for Fixed, Percent and Auto lengths.
- // Other types will ASSERT in order to catch invalid length calculations.
int calcValue(int maxValue, bool roundPercentages = false) const
{
switch (type()) {
case Fixed:
case Percent:
+ case Calculated:
return calcMinValue(maxValue, roundPercentages);
case Auto:
return maxValue;
@@ -152,6 +188,8 @@
return static_cast<int>(round(maxValue * percent() / 100.0f));
// Don't remove the extra cast to float. It is needed for rounding on 32-bit Intel machines that use the FPU stack.
return static_cast<int>(static_cast<float>(maxValue * percent() / 100.0f));
+ case Calculated:
+ return nonNanCalculatedValue(maxValue);
case Auto:
return 0;
case Relative:
@@ -174,6 +212,8 @@
return static_cast<float>(maxValue * percent() / 100.0f);
case Auto:
return static_cast<float>(maxValue);
+ case Calculated:
+ return nonNanCalculatedValue(maxValue);
case Relative:
case Intrinsic:
case MinIntrinsic:
@@ -186,21 +226,43 @@
}
bool isUndefined() const { return type() == Undefined; }
+
+ // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
+ // always contains a percentage, and without a maxValue passed to these functions
+ // it's impossible to determine the sign or zero-ness. We assume all calc values
+ // are positive and non-zero for now.
bool isZero() const
{
ASSERT(!isUndefined());
+ if (isCalculated())
+ return false;
+
return m_isFloat ? !m_floatValue : !m_intValue;
}
+ bool isPositive() const
+ {
+ if (isUndefined())
+ return false;
+ if (isCalculated())
+ return true;
+
+ return getFloatValue() > 0;
+ }
+ bool isNegative() const
+ {
+ if (isUndefined() || isCalculated())
+ return false;
+
+ return getFloatValue() < 0;
+ }
- bool isPositive() const { return isUndefined() ? false : getFloatValue() > 0; }
- bool isNegative() const { return isUndefined() ? false : getFloatValue() < 0; }
-
bool isAuto() const { return type() == Auto; }
bool isRelative() const { return type() == Relative; }
- bool isPercent() const { return type() == Percent; }
+ bool isPercent() const { return type() == Percent || type() == Calculated; }
bool isFixed() const { return type() == Fixed; }
bool isIntrinsicOrAuto() const { return type() == Auto || type() == MinIntrinsic || type() == Intrinsic; }
- bool isSpecified() const { return type() == Fixed || type() == Percent; }
+ bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
+ bool isCalculated() const { return type() == Calculated; }
Length blend(const Length& from, double progress) const
{
@@ -239,6 +301,30 @@
return m_isFloat ? m_floatValue : m_intValue;
}
+ void initFromLength(const Length &length)
+ {
+ m_quirk = length.m_quirk;
+ m_type = length.m_type;
+ m_isFloat = length.m_isFloat;
+
+ if (m_isFloat)
+ m_floatValue = length.m_floatValue;
+ else
+ m_intValue = length.m_intValue;
+
+ if (isCalculated())
+ incrementCalculatedRef();
+ }
+
+ float nonNanCalculatedValue(int maxValue) const;
+ int calculationHandle() const
+ {
+ ASSERT(isCalculated());
+ return getIntValue();
+ }
+ void incrementCalculatedRef() const;
+ void decrementCalculatedRef() const;
+
union {
int m_intValue;
float m_floatValue;