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