Home | History | Annotate | Download | only in platform
      1 /*
      2     Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3     Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
      4     Copyright (C) 2011 Rik Cabanier (cabanier (at) adobe.com)
      5     Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
      6 
      7     This library is free software; you can redistribute it and/or
      8     modify it under the terms of the GNU Library General Public
      9     License as published by the Free Software Foundation; either
     10     version 2 of the License, or (at your option) any later version.
     11 
     12     This library is distributed in the hope that it will be useful,
     13     but WITHOUT ANY WARRANTY; without even the implied warranty of
     14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15     Library General Public License for more details.
     16 
     17     You should have received a copy of the GNU Library General Public License
     18     along with this library; see the file COPYING.LIB.  If not, write to
     19     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20     Boston, MA 02110-1301, USA.
     21 */
     22 
     23 #ifndef Length_h
     24 #define Length_h
     25 
     26 #include "platform/PlatformExport.h"
     27 #include "platform/animation/AnimationUtilities.h"
     28 #include "wtf/Assertions.h"
     29 #include "wtf/FastAllocBase.h"
     30 #include "wtf/Forward.h"
     31 #include "wtf/HashMap.h"
     32 #include "wtf/MathExtras.h"
     33 #include "wtf/Vector.h"
     34 #include <cstring>
     35 
     36 namespace WebCore {
     37 
     38 enum LengthType {
     39     Auto, Percent, Fixed,
     40     Intrinsic, MinIntrinsic,
     41     MinContent, MaxContent, FillAvailable, FitContent,
     42     Calculated,
     43     ViewportPercentageWidth, ViewportPercentageHeight, ViewportPercentageMin, ViewportPercentageMax,
     44     ExtendToZoom,
     45     Undefined
     46 };
     47 
     48 enum ValueRange {
     49     ValueRangeAll,
     50     ValueRangeNonNegative
     51 };
     52 
     53 class CalculationValue;
     54 
     55 class PLATFORM_EXPORT Length {
     56     WTF_MAKE_FAST_ALLOCATED;
     57 public:
     58     Length()
     59         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
     60     {
     61     }
     62 
     63     Length(LengthType t)
     64         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
     65     {
     66         ASSERT(t != Calculated);
     67     }
     68 
     69     Length(int v, LengthType t, bool q = false)
     70         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
     71     {
     72         ASSERT(t != Calculated);
     73     }
     74 
     75     Length(LayoutUnit v, LengthType t, bool q = false)
     76         : m_floatValue(v.toFloat()), m_quirk(q), m_type(t), m_isFloat(true)
     77     {
     78         ASSERT(t != Calculated);
     79     }
     80 
     81     Length(float v, LengthType t, bool q = false)
     82         : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
     83     {
     84         ASSERT(t != Calculated);
     85     }
     86 
     87     Length(double v, LengthType t, bool q = false)
     88         : m_quirk(q), m_type(t), m_isFloat(true)
     89     {
     90         m_floatValue = static_cast<float>(v);
     91     }
     92 
     93     explicit Length(PassRefPtr<CalculationValue>);
     94 
     95     Length(const Length& length)
     96     {
     97         initFromLength(length);
     98     }
     99 
    100     Length& operator=(const Length& length)
    101     {
    102         initFromLength(length);
    103         return *this;
    104     }
    105 
    106     ~Length()
    107     {
    108         if (isCalculated())
    109             decrementCalculatedRef();
    110     }
    111 
    112     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue()) || isCalculatedEqual(o)); }
    113     bool operator!=(const Length& o) const { return !(*this == o); }
    114 
    115     const Length& operator*=(float v)
    116     {
    117         if (isCalculated()) {
    118             ASSERT_NOT_REACHED();
    119             return *this;
    120         }
    121 
    122         if (m_isFloat)
    123             m_floatValue = static_cast<float>(m_floatValue * v);
    124         else
    125             m_intValue = static_cast<int>(m_intValue * v);
    126 
    127         return *this;
    128     }
    129 
    130     inline float value() const
    131     {
    132         return getFloatValue();
    133     }
    134 
    135     int intValue() const
    136     {
    137         if (isCalculated()) {
    138             ASSERT_NOT_REACHED();
    139             return 0;
    140         }
    141         return getIntValue();
    142     }
    143 
    144     float percent() const
    145     {
    146         ASSERT(type() == Percent);
    147         return getFloatValue();
    148     }
    149 
    150     CalculationValue* calculationValue() const;
    151 
    152     LengthType type() const { return static_cast<LengthType>(m_type); }
    153     bool quirk() const { return m_quirk; }
    154 
    155     void setQuirk(bool quirk)
    156     {
    157         m_quirk = quirk;
    158     }
    159 
    160     void setValue(LengthType t, int value)
    161     {
    162         m_type = t;
    163         m_intValue = value;
    164         m_isFloat = false;
    165     }
    166 
    167     void setValue(int value)
    168     {
    169         if (isCalculated()) {
    170             ASSERT_NOT_REACHED();
    171             return;
    172         }
    173         setValue(Fixed, value);
    174     }
    175 
    176     void setValue(LengthType t, float value)
    177     {
    178         m_type = t;
    179         m_floatValue = value;
    180         m_isFloat = true;
    181     }
    182 
    183     void setValue(LengthType t, LayoutUnit value)
    184     {
    185         m_type = t;
    186         m_floatValue = value;
    187         m_isFloat = true;
    188     }
    189 
    190     void setValue(float value)
    191     {
    192         *this = Length(value, Fixed);
    193     }
    194 
    195     bool isUndefined() const { return type() == Undefined; }
    196 
    197     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
    198     // always contains a percentage, and without a maxValue passed to these functions
    199     // it's impossible to determine the sign or zero-ness. We assume all calc values
    200     // are positive and non-zero for now.
    201     bool isZero() const
    202     {
    203         ASSERT(!isUndefined());
    204         if (isCalculated())
    205             return false;
    206 
    207         return m_isFloat ? !m_floatValue : !m_intValue;
    208     }
    209     bool isPositive() const
    210     {
    211         if (isUndefined())
    212             return false;
    213         if (isCalculated())
    214             return true;
    215 
    216         return getFloatValue() > 0;
    217     }
    218     bool isNegative() const
    219     {
    220         if (isUndefined() || isCalculated())
    221             return false;
    222 
    223         return getFloatValue() < 0;
    224     }
    225 
    226     bool isAuto() const { return type() == Auto; }
    227     bool isPercent() const { return type() == Percent || type() == Calculated; }
    228     bool isFixed() const { return type() == Fixed; }
    229     bool isIntrinsicOrAuto() const { return type() == Auto || isLegacyIntrinsic() || isIntrinsic(); }
    230     bool isLegacyIntrinsic() const { return type() == Intrinsic || type() == MinIntrinsic; }
    231     bool isIntrinsic() const { return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent; }
    232     bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated || isViewportPercentage(); }
    233     bool isSpecifiedOrIntrinsic() const { return isSpecified() || isIntrinsic(); }
    234     bool isCalculated() const { return type() == Calculated; }
    235     bool isCalculatedEqual(const Length&) const;
    236     bool isMinContent() const { return type() == MinContent; }
    237     bool isMaxContent() const { return type() == MaxContent; }
    238     bool isFillAvailable() const { return type() == FillAvailable; }
    239     bool isFitContent() const { return type() == FitContent; }
    240 
    241     Length blend(const Length& from, double progress, ValueRange range) const
    242     {
    243         // FIXME: These should step at 50%, but transitions currently blend values that should
    244         // never be transitioned in the first place.
    245         if (isUndefined() || from.isUndefined() || isIntrinsicOrAuto() || from.isIntrinsicOrAuto())
    246             return *this;
    247 
    248         if (progress == 0.0)
    249             return from;
    250 
    251         if (progress == 1.0)
    252             return *this;
    253 
    254         if (from.type() == Calculated || type() == Calculated)
    255             return blendMixedTypes(from, progress, range);
    256 
    257         if (!from.isZero() && !isZero() && from.type() != type())
    258             return blendMixedTypes(from, progress, range);
    259 
    260         if (from.isZero() && isZero())
    261             return *this;
    262 
    263         LengthType resultType = type();
    264         if (isZero())
    265             resultType = from.type();
    266 
    267         float blendedValue = WebCore::blend(from.value(), value(), progress);
    268         if (range == ValueRangeNonNegative)
    269             blendedValue = clampTo<float>(blendedValue, 0);
    270         return Length(blendedValue, resultType);
    271     }
    272 
    273     float getFloatValue() const
    274     {
    275         ASSERT(!isUndefined());
    276         return m_isFloat ? m_floatValue : m_intValue;
    277     }
    278     float nonNanCalculatedValue(int maxValue) const;
    279 
    280     bool isViewportPercentage() const
    281     {
    282         LengthType lengthType = type();
    283         return lengthType >= ViewportPercentageWidth && lengthType <= ViewportPercentageMax;
    284     }
    285     float viewportPercentageLength() const
    286     {
    287         ASSERT(isViewportPercentage());
    288         return getFloatValue();
    289     }
    290 private:
    291     int getIntValue() const
    292     {
    293         ASSERT(!isUndefined());
    294         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
    295     }
    296     void initFromLength(const Length& length)
    297     {
    298         memcpy(this, &length, sizeof(Length));
    299 
    300         if (isCalculated())
    301             incrementCalculatedRef();
    302     }
    303 
    304     Length blendMixedTypes(const Length& from, double progress, ValueRange) const;
    305 
    306     int calculationHandle() const
    307     {
    308         ASSERT(isCalculated());
    309         return getIntValue();
    310     }
    311     void incrementCalculatedRef() const;
    312     void decrementCalculatedRef() const;
    313 
    314     union {
    315         int m_intValue;
    316         float m_floatValue;
    317     };
    318     bool m_quirk;
    319     unsigned char m_type;
    320     bool m_isFloat;
    321 };
    322 
    323 PLATFORM_EXPORT Vector<Length> parseHTMLAreaElementCoords(const String&);
    324 
    325 } // namespace WebCore
    326 
    327 #endif // Length_h
    328