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