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 // FIXME: This enum makes it hard to tell in general what values may be
     39 // appropriate for any given Length.
     40 enum LengthType {
     41     Auto, Percent, Fixed,
     42     Intrinsic, MinIntrinsic,
     43     MinContent, MaxContent, FillAvailable, FitContent,
     44     Calculated,
     45     ExtendToZoom, DeviceWidth, DeviceHeight,
     46     Undefined
     47 };
     48 
     49 enum ValueRange {
     50     ValueRangeAll,
     51     ValueRangeNonNegative
     52 };
     53 
     54 struct PixelsAndPercent {
     55     PixelsAndPercent(float pixels, float percent)
     56         : pixels(pixels)
     57         , percent(percent)
     58     {
     59     }
     60     float pixels;
     61     float percent;
     62 };
     63 
     64 class CalculationValue;
     65 
     66 class PLATFORM_EXPORT Length {
     67     WTF_MAKE_FAST_ALLOCATED;
     68 public:
     69     Length()
     70         :  m_intValue(0), m_quirk(false), m_type(Auto), m_isFloat(false)
     71     {
     72     }
     73 
     74     Length(LengthType t)
     75         : m_intValue(0), m_quirk(false), m_type(t), m_isFloat(false)
     76     {
     77         ASSERT(t != Calculated);
     78     }
     79 
     80     Length(int v, LengthType t, bool q = false)
     81         : m_intValue(v), m_quirk(q), m_type(t), m_isFloat(false)
     82     {
     83         ASSERT(t != Calculated);
     84     }
     85 
     86     Length(LayoutUnit v, LengthType t, bool q = false)
     87         : m_floatValue(v.toFloat()), m_quirk(q), m_type(t), m_isFloat(true)
     88     {
     89         ASSERT(t != Calculated);
     90     }
     91 
     92     Length(float v, LengthType t, bool q = false)
     93         : m_floatValue(v), m_quirk(q), m_type(t), m_isFloat(true)
     94     {
     95         ASSERT(t != Calculated);
     96     }
     97 
     98     Length(double v, LengthType t, bool q = false)
     99         : m_quirk(q), m_type(t), m_isFloat(true)
    100     {
    101         m_floatValue = static_cast<float>(v);
    102     }
    103 
    104     explicit Length(PassRefPtr<CalculationValue>);
    105 
    106     Length(const Length& length)
    107     {
    108         memcpy(this, &length, sizeof(Length));
    109         if (isCalculated())
    110             incrementCalculatedRef();
    111     }
    112 
    113     Length& operator=(const Length& length)
    114     {
    115         if (length.isCalculated())
    116             length.incrementCalculatedRef();
    117         if (isCalculated())
    118             decrementCalculatedRef();
    119         memcpy(this, &length, sizeof(Length));
    120         return *this;
    121     }
    122 
    123 #if COMPILER_SUPPORTS(CXX_RVALUE_REFERENCES)
    124     Length(Length&& length)
    125     {
    126         memcpy(this, &length, sizeof(Length));
    127 
    128         // Reset |length|'s type to Auto to make sure its destructor
    129         // won't call decrementCalculatedRef() as we don't call
    130         // incrementCalculatedRef() here.
    131         length.m_type = Auto;
    132     }
    133 
    134     Length& operator=(Length&& length)
    135     {
    136         if (this == &length)
    137             return *this;
    138 
    139         if (isCalculated())
    140             decrementCalculatedRef();
    141 
    142         memcpy(this, &length, sizeof(Length));
    143 
    144         // Reset |length|'s type to Auto to make sure its destructor
    145         // won't call decrementCalculatedRef() as we don't call
    146         // incrementCalculatedRef() here.
    147         length.m_type = Auto;
    148 
    149         return *this;
    150     }
    151 #endif
    152 
    153     ~Length()
    154     {
    155         if (isCalculated())
    156             decrementCalculatedRef();
    157     }
    158 
    159     bool operator==(const Length& o) const { return (m_type == o.m_type) && (m_quirk == o.m_quirk) && (isUndefined() || (getFloatValue() == o.getFloatValue()) || isCalculatedEqual(o)); }
    160     bool operator!=(const Length& o) const { return !(*this == o); }
    161 
    162     const Length& operator*=(float v)
    163     {
    164         if (isCalculated()) {
    165             ASSERT_NOT_REACHED();
    166             return *this;
    167         }
    168 
    169         if (m_isFloat)
    170             m_floatValue = static_cast<float>(m_floatValue * v);
    171         else
    172             m_intValue = static_cast<int>(m_intValue * v);
    173 
    174         return *this;
    175     }
    176 
    177     inline float value() const
    178     {
    179         return getFloatValue();
    180     }
    181 
    182     int intValue() const
    183     {
    184         if (isCalculated()) {
    185             ASSERT_NOT_REACHED();
    186             return 0;
    187         }
    188         return getIntValue();
    189     }
    190 
    191     float percent() const
    192     {
    193         ASSERT(type() == Percent);
    194         return getFloatValue();
    195     }
    196     PixelsAndPercent pixelsAndPercent() const;
    197 
    198     CalculationValue& calculationValue() const;
    199 
    200     LengthType type() const { return static_cast<LengthType>(m_type); }
    201     bool quirk() const { return m_quirk; }
    202 
    203     void setQuirk(bool quirk)
    204     {
    205         m_quirk = quirk;
    206     }
    207 
    208     void setValue(LengthType t, int value)
    209     {
    210         m_type = t;
    211         m_intValue = value;
    212         m_isFloat = false;
    213     }
    214 
    215     void setValue(int value)
    216     {
    217         if (isCalculated()) {
    218             ASSERT_NOT_REACHED();
    219             return;
    220         }
    221         setValue(Fixed, value);
    222     }
    223 
    224     void setValue(LengthType t, float value)
    225     {
    226         m_type = t;
    227         m_floatValue = value;
    228         m_isFloat = true;
    229     }
    230 
    231     void setValue(LengthType t, LayoutUnit value)
    232     {
    233         m_type = t;
    234         m_floatValue = value.toFloat();
    235         m_isFloat = true;
    236     }
    237 
    238     void setValue(float value)
    239     {
    240         *this = Length(value, Fixed);
    241     }
    242 
    243     bool isUndefined() const { return type() == Undefined; }
    244 
    245     // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated Length
    246     // always contains a percentage, and without a maxValue passed to these functions
    247     // it's impossible to determine the sign or zero-ness. We assume all calc values
    248     // are positive and non-zero for now.
    249     bool isZero() const
    250     {
    251         ASSERT(!isUndefined());
    252         if (isCalculated())
    253             return false;
    254 
    255         return m_isFloat ? !m_floatValue : !m_intValue;
    256     }
    257     bool isPositive() const
    258     {
    259         if (isUndefined())
    260             return false;
    261         if (isCalculated())
    262             return true;
    263 
    264         return getFloatValue() > 0;
    265     }
    266     bool isNegative() const
    267     {
    268         if (isUndefined() || isCalculated())
    269             return false;
    270 
    271         return getFloatValue() < 0;
    272     }
    273 
    274     bool isAuto() const { return type() == Auto; }
    275     bool isPercent() const { return type() == Percent || type() == Calculated; }
    276     bool isFixed() const { return type() == Fixed; }
    277     bool isIntrinsicOrAuto() const { return type() == Auto || isLegacyIntrinsic() || isIntrinsic(); }
    278     bool isLegacyIntrinsic() const { return type() == Intrinsic || type() == MinIntrinsic; }
    279     bool isIntrinsic() const { return type() == MinContent || type() == MaxContent || type() == FillAvailable || type() == FitContent; }
    280     bool isSpecified() const { return type() == Fixed || type() == Percent || type() == Calculated; }
    281     bool isSpecifiedOrIntrinsic() const { return isSpecified() || isIntrinsic(); }
    282     bool isCalculated() const { return type() == Calculated; }
    283     bool isCalculatedEqual(const Length&) const;
    284     bool isMinContent() const { return type() == MinContent; }
    285     bool isMaxContent() const { return type() == MaxContent; }
    286     bool isFillAvailable() const { return type() == FillAvailable; }
    287     bool isFitContent() const { return type() == FitContent; }
    288 
    289     Length blend(const Length& from, double progress, ValueRange range) const
    290     {
    291         ASSERT(isSpecified() && from.isSpecified());
    292 
    293         if (progress == 0.0)
    294             return from;
    295 
    296         if (progress == 1.0)
    297             return *this;
    298 
    299         if (from.type() == Calculated || type() == Calculated)
    300             return blendMixedTypes(from, progress, range);
    301 
    302         if (!from.isZero() && !isZero() && from.type() != type())
    303             return blendMixedTypes(from, progress, range);
    304 
    305         if (from.isZero() && isZero())
    306             return *this;
    307 
    308         LengthType resultType = type();
    309         if (isZero())
    310             resultType = from.type();
    311 
    312         float blendedValue = WebCore::blend(from.value(), value(), progress);
    313         if (range == ValueRangeNonNegative)
    314             blendedValue = clampTo<float>(blendedValue, 0);
    315         return Length(blendedValue, resultType);
    316     }
    317 
    318     float getFloatValue() const
    319     {
    320         ASSERT(!isUndefined());
    321         return m_isFloat ? m_floatValue : m_intValue;
    322     }
    323     float nonNanCalculatedValue(int maxValue) const;
    324 
    325     Length subtractFromOneHundredPercent() const;
    326 
    327 private:
    328     int getIntValue() const
    329     {
    330         ASSERT(!isUndefined());
    331         return m_isFloat ? static_cast<int>(m_floatValue) : m_intValue;
    332     }
    333 
    334     Length blendMixedTypes(const Length& from, double progress, ValueRange) const;
    335 
    336     int calculationHandle() const
    337     {
    338         ASSERT(isCalculated());
    339         return getIntValue();
    340     }
    341     void incrementCalculatedRef() const;
    342     void decrementCalculatedRef() const;
    343 
    344     union {
    345         int m_intValue;
    346         float m_floatValue;
    347     };
    348     bool m_quirk;
    349     unsigned char m_type;
    350     bool m_isFloat;
    351 };
    352 
    353 PLATFORM_EXPORT Vector<Length> parseHTMLAreaElementCoords(const String&);
    354 
    355 } // namespace WebCore
    356 
    357 #endif // Length_h
    358