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