1 /* 2 Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 4 Copyright (C) 2011 Rik Cabanier (cabanier@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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LENGTH_H_ 24 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LENGTH_H_ 25 26 #include <cstring> 27 28 #include "base/notreached.h" 29 #include "third_party/blink/renderer/platform/geometry/layout_unit.h" 30 #include "third_party/blink/renderer/platform/platform_export.h" 31 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 32 #include "third_party/blink/renderer/platform/wtf/math_extras.h" 33 34 namespace blink { 35 36 enum ValueRange { kValueRangeAll, kValueRangeNonNegative }; 37 38 struct PixelsAndPercent { 39 DISALLOW_NEW(); PixelsAndPercentPixelsAndPercent40 PixelsAndPercent(float pixels, float percent) 41 : pixels(pixels), percent(percent) {} 42 float pixels; 43 float percent; 44 }; 45 46 class CalculationValue; 47 48 class PLATFORM_EXPORT Length { 49 DISALLOW_NEW(); 50 51 public: 52 // FIXME: This enum makes it hard to tell in general what values may be 53 // appropriate for any given Length. 54 enum Type : unsigned char { 55 kAuto, 56 kPercent, 57 kFixed, 58 kMinContent, 59 kMaxContent, 60 kMinIntrinsic, 61 kFillAvailable, 62 kFitContent, 63 kCalculated, 64 kExtendToZoom, 65 kDeviceWidth, 66 kDeviceHeight, 67 kNone 68 }; 69 Length()70 Length() : int_value_(0), quirk_(false), type_(kAuto), is_float_(false) {} 71 Length(Length::Type t)72 explicit Length(Length::Type t) 73 : int_value_(0), quirk_(false), type_(t), is_float_(false) { 74 DCHECK_NE(t, kCalculated); 75 } 76 77 Length(int v, Length::Type t, bool q = false) int_value_(v)78 : int_value_(v), quirk_(q), type_(t), is_float_(false) { 79 DCHECK_NE(t, kCalculated); 80 } 81 82 Length(LayoutUnit v, Length::Type t, bool q = false) 83 : float_value_(v.ToFloat()), quirk_(q), type_(t), is_float_(true) { 84 DCHECK_NE(t, kCalculated); 85 } 86 87 Length(float v, Length::Type t, bool q = false) float_value_(v)88 : float_value_(v), quirk_(q), type_(t), is_float_(true) { 89 DCHECK_NE(t, kCalculated); 90 } 91 92 Length(double v, Length::Type t, bool q = false) quirk_(q)93 : quirk_(q), type_(t), is_float_(true) { 94 float_value_ = clampTo<float>(v); 95 } 96 97 explicit Length(scoped_refptr<CalculationValue>); 98 Length(const Length & length)99 Length(const Length& length) { 100 memcpy(this, &length, sizeof(Length)); 101 if (IsCalculated()) 102 IncrementCalculatedRef(); 103 } 104 105 Length& operator=(const Length& length) { 106 if (length.IsCalculated()) 107 length.IncrementCalculatedRef(); 108 if (IsCalculated()) 109 DecrementCalculatedRef(); 110 memcpy(this, &length, sizeof(Length)); 111 return *this; 112 } 113 ~Length()114 ~Length() { 115 if (IsCalculated()) 116 DecrementCalculatedRef(); 117 } 118 119 bool operator==(const Length& o) const { 120 return (type_ == o.type_) && (quirk_ == o.quirk_) && 121 (IsNone() || (GetFloatValue() == o.GetFloatValue()) || 122 IsCalculatedEqual(o)); 123 } 124 bool operator!=(const Length& o) const { return !(*this == o); } 125 126 const Length& operator*=(float v) { 127 if (IsCalculated()) { 128 NOTREACHED(); 129 return *this; 130 } 131 132 if (is_float_) 133 float_value_ = static_cast<float>(float_value_ * v); 134 else 135 int_value_ = static_cast<int>(int_value_ * v); 136 137 return *this; 138 } 139 140 template <typename NUMBER_TYPE> Fixed(NUMBER_TYPE number)141 static Length Fixed(NUMBER_TYPE number) { 142 return Length(number, kFixed); 143 } Fixed()144 static Length Fixed() { return Length(kFixed); } Auto()145 static Length Auto() { return Length(kAuto); } FillAvailable()146 static Length FillAvailable() { return Length(kFillAvailable); } MinContent()147 static Length MinContent() { return Length(kMinContent); } MaxContent()148 static Length MaxContent() { return Length(kMaxContent); } MinIntrinsic()149 static Length MinIntrinsic() { return Length(kMinIntrinsic); } ExtendToZoom()150 static Length ExtendToZoom() { return Length(kExtendToZoom); } DeviceWidth()151 static Length DeviceWidth() { return Length(kDeviceWidth); } DeviceHeight()152 static Length DeviceHeight() { return Length(kDeviceHeight); } None()153 static Length None() { return Length(kNone); } FitContent()154 static Length FitContent() { return Length(kFitContent); } 155 template <typename NUMBER_TYPE> Percent(NUMBER_TYPE number)156 static Length Percent(NUMBER_TYPE number) { 157 return Length(number, kPercent); 158 } 159 160 // FIXME: Make this private (if possible) or at least rename it 161 // (http://crbug.com/432707). Value()162 inline float Value() const { 163 DCHECK(!IsCalculated()); 164 return GetFloatValue(); 165 } 166 IntValue()167 int IntValue() const { 168 if (IsCalculated()) { 169 NOTREACHED(); 170 return 0; 171 } 172 return GetIntValue(); 173 } 174 Pixels()175 float Pixels() const { 176 DCHECK_EQ(GetType(), kFixed); 177 return GetFloatValue(); 178 } 179 Percent()180 float Percent() const { 181 DCHECK_EQ(GetType(), kPercent); 182 return GetFloatValue(); 183 } 184 185 PixelsAndPercent GetPixelsAndPercent() const; 186 187 CalculationValue& GetCalculationValue() const; 188 189 // If |this| is calculated, returns the underlying |CalculationValue|. If not, 190 // returns a |CalculationValue| constructed from |GetPixelsAndPercent()|. Hits 191 // a DCHECK if |this| is not a specified value (e.g., 'auto'). 192 scoped_refptr<CalculationValue> AsCalculationValue() const; 193 GetType()194 Length::Type GetType() const { return static_cast<Length::Type>(type_); } Quirk()195 bool Quirk() const { return quirk_; } 196 SetQuirk(bool quirk)197 void SetQuirk(bool quirk) { quirk_ = quirk; } 198 IsNone()199 bool IsNone() const { return GetType() == kNone; } 200 201 // FIXME calc: https://bugs.webkit.org/show_bug.cgi?id=80357. A calculated 202 // Length always contains a percentage, and without a maxValue passed to these 203 // functions it's impossible to determine the sign or zero-ness. We assume all 204 // calc values are positive and non-zero for now. IsZero()205 bool IsZero() const { 206 DCHECK(!IsNone()); 207 if (IsCalculated()) 208 return false; 209 210 return is_float_ ? !float_value_ : !int_value_; 211 } IsPositive()212 bool IsPositive() const { 213 if (IsNone()) 214 return false; 215 if (IsCalculated()) 216 return true; 217 218 return GetFloatValue() > 0; 219 } IsNegative()220 bool IsNegative() const { 221 if (IsNone() || IsCalculated()) 222 return false; 223 224 return GetFloatValue() < 0; 225 } 226 227 // For the layout purposes, if this |Length| is a block-axis size, see 228 // |IsAutoOrContentOrIntrinsic()|, it is usually a better choice. IsAuto()229 bool IsAuto() const { return GetType() == kAuto; } IsFixed()230 bool IsFixed() const { return GetType() == kFixed; } 231 232 // For the block axis, intrinsic sizes such as `min-content` behave the same 233 // as `auto`. https://www.w3.org/TR/css-sizing-3/#valdef-width-min-content IsContentOrIntrinsic()234 bool IsContentOrIntrinsic() const { 235 return GetType() == kMinContent || GetType() == kMaxContent || 236 GetType() == kFitContent || GetType() == kMinIntrinsic; 237 } IsAutoOrContentOrIntrinsic()238 bool IsAutoOrContentOrIntrinsic() const { 239 return GetType() == kAuto || IsContentOrIntrinsic(); 240 } 241 242 // NOTE: This shouldn't be use in NG code. IsContentOrIntrinsicOrFillAvailable()243 bool IsContentOrIntrinsicOrFillAvailable() const { 244 return IsContentOrIntrinsic() || GetType() == kFillAvailable; 245 } 246 IsSpecified()247 bool IsSpecified() const { 248 return GetType() == kFixed || GetType() == kPercent || 249 GetType() == kCalculated; 250 } 251 IsCalculated()252 bool IsCalculated() const { return GetType() == kCalculated; } 253 bool IsCalculatedEqual(const Length&) const; IsMinContent()254 bool IsMinContent() const { return GetType() == kMinContent; } IsMaxContent()255 bool IsMaxContent() const { return GetType() == kMaxContent; } IsMinIntrinsic()256 bool IsMinIntrinsic() const { return GetType() == kMinIntrinsic; } IsFillAvailable()257 bool IsFillAvailable() const { return GetType() == kFillAvailable; } IsFitContent()258 bool IsFitContent() const { return GetType() == kFitContent; } IsPercent()259 bool IsPercent() const { return GetType() == kPercent; } IsPercentOrCalc()260 bool IsPercentOrCalc() const { 261 return GetType() == kPercent || GetType() == kCalculated; 262 } IsExtendToZoom()263 bool IsExtendToZoom() const { return GetType() == kExtendToZoom; } IsDeviceWidth()264 bool IsDeviceWidth() const { return GetType() == kDeviceWidth; } IsDeviceHeight()265 bool IsDeviceHeight() const { return GetType() == kDeviceHeight; } 266 Blend(const Length & from,double progress,ValueRange range)267 Length Blend(const Length& from, double progress, ValueRange range) const { 268 DCHECK(IsSpecified()); 269 DCHECK(from.IsSpecified()); 270 271 if (progress == 0.0) 272 return from; 273 274 if (progress == 1.0) 275 return *this; 276 277 if (from.GetType() == kCalculated || GetType() == kCalculated) 278 return BlendMixedTypes(from, progress, range); 279 280 if (!from.IsZero() && !IsZero() && from.GetType() != GetType()) 281 return BlendMixedTypes(from, progress, range); 282 283 if (from.IsZero() && IsZero()) 284 return *this; 285 286 return BlendSameTypes(from, progress, range); 287 } 288 GetFloatValue()289 float GetFloatValue() const { 290 DCHECK(!IsNone()); 291 return is_float_ ? float_value_ : int_value_; 292 } 293 float NonNanCalculatedValue(LayoutUnit max_value) const; 294 295 Length SubtractFromOneHundredPercent() const; 296 297 Length Zoom(double factor) const; 298 299 private: GetIntValue()300 int GetIntValue() const { 301 DCHECK(!IsNone()); 302 return is_float_ ? static_cast<int>(float_value_) : int_value_; 303 } 304 305 Length BlendMixedTypes(const Length& from, double progress, ValueRange) const; 306 307 Length BlendSameTypes(const Length& from, double progress, ValueRange) const; 308 CalculationHandle()309 int CalculationHandle() const { 310 DCHECK(IsCalculated()); 311 return GetIntValue(); 312 } 313 void IncrementCalculatedRef() const; 314 void DecrementCalculatedRef() const; 315 316 union { 317 int int_value_; 318 float float_value_; 319 }; 320 bool quirk_; 321 unsigned char type_; 322 bool is_float_; 323 }; 324 325 } // namespace blink 326 327 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GEOMETRY_LENGTH_H_ 328