1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller ( mueller@kde.org )
5  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights
6  * reserved.
7  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "third_party/blink/renderer/platform/geometry/length.h"
27 
28 #include "base/macros.h"
29 #include "third_party/blink/renderer/platform/geometry/blend.h"
30 #include "third_party/blink/renderer/platform/geometry/calculation_value.h"
31 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
32 #include "third_party/blink/renderer/platform/wtf/size_assertions.h"
33 
34 namespace blink {
35 
36 class CalculationValueHandleMap {
37   USING_FAST_MALLOC(CalculationValueHandleMap);
38 
39  public:
CalculationValueHandleMap()40   CalculationValueHandleMap() : index_(1) {}
41 
insert(scoped_refptr<CalculationValue> calc_value)42   int insert(scoped_refptr<CalculationValue> calc_value) {
43     DCHECK(index_);
44     // FIXME calc(): https://bugs.webkit.org/show_bug.cgi?id=80489
45     // This monotonically increasing handle generation scheme is potentially
46     // wasteful of the handle space. Consider reusing empty handles.
47     while (map_.Contains(index_))
48       index_++;
49 
50     map_.Set(index_, std::move(calc_value));
51 
52     return index_;
53   }
54 
Remove(int index)55   void Remove(int index) {
56     DCHECK(map_.Contains(index));
57     map_.erase(index);
58   }
59 
Get(int index)60   CalculationValue& Get(int index) {
61     DCHECK(map_.Contains(index));
62     return *map_.at(index);
63   }
64 
DecrementRef(int index)65   void DecrementRef(int index) {
66     DCHECK(map_.Contains(index));
67     CalculationValue* value = map_.at(index);
68     if (value->HasOneRef()) {
69       // Force the CalculationValue destructor early to avoid a potential
70       // recursive call inside HashMap remove().
71       map_.Set(index, nullptr);
72       map_.erase(index);
73     } else {
74       value->Release();
75     }
76   }
77 
78  private:
79   int index_;
80   HashMap<int, scoped_refptr<CalculationValue>> map_;
81 
82   DISALLOW_COPY_AND_ASSIGN(CalculationValueHandleMap);
83 };
84 
CalcHandles()85 static CalculationValueHandleMap& CalcHandles() {
86   DEFINE_STATIC_LOCAL(CalculationValueHandleMap, handle_map, ());
87   return handle_map;
88 }
89 
Length(scoped_refptr<CalculationValue> calc)90 Length::Length(scoped_refptr<CalculationValue> calc)
91     : quirk_(false), type_(kCalculated), is_float_(false) {
92   int_value_ = CalcHandles().insert(std::move(calc));
93 }
94 
BlendMixedTypes(const Length & from,double progress,ValueRange range) const95 Length Length::BlendMixedTypes(const Length& from,
96                                double progress,
97                                ValueRange range) const {
98   DCHECK(from.IsSpecified());
99   DCHECK(IsSpecified());
100   return Length(
101       AsCalculationValue()->Blend(*from.AsCalculationValue(), progress, range));
102 }
103 
BlendSameTypes(const Length & from,double progress,ValueRange range) const104 Length Length::BlendSameTypes(const Length& from,
105                               double progress,
106                               ValueRange range) const {
107   Length::Type result_type = GetType();
108   if (IsZero())
109     result_type = from.GetType();
110 
111   float blended_value = blink::Blend(from.Value(), Value(), progress);
112   if (range == kValueRangeNonNegative)
113     blended_value = clampTo<float>(blended_value, 0);
114   return Length(blended_value, result_type);
115 }
116 
GetPixelsAndPercent() const117 PixelsAndPercent Length::GetPixelsAndPercent() const {
118   switch (GetType()) {
119     case kFixed:
120       return PixelsAndPercent(Value(), 0);
121     case kPercent:
122       return PixelsAndPercent(0, Value());
123     case kCalculated:
124       return GetCalculationValue().GetPixelsAndPercent();
125     default:
126       NOTREACHED();
127       return PixelsAndPercent(0, 0);
128   }
129 }
130 
AsCalculationValue() const131 scoped_refptr<CalculationValue> Length::AsCalculationValue() const {
132   if (IsCalculated())
133     return &GetCalculationValue();
134   return CalculationValue::Create(GetPixelsAndPercent(), kValueRangeAll);
135 }
136 
SubtractFromOneHundredPercent() const137 Length Length::SubtractFromOneHundredPercent() const {
138   if (IsPercent())
139     return Length::Percent(100 - Value());
140   DCHECK(IsSpecified());
141   scoped_refptr<CalculationValue> result =
142       AsCalculationValue()->SubtractFromOneHundredPercent();
143   if (result->IsExpression() ||
144       (result->Pixels() != 0 && result->Percent() != 0)) {
145     return Length(std::move(result));
146   }
147   if (result->Percent())
148     return Length::Percent(result->Percent());
149   return Length::Fixed(result->Pixels());
150 }
151 
Zoom(double factor) const152 Length Length::Zoom(double factor) const {
153   switch (GetType()) {
154     case kFixed:
155       return Length::Fixed(GetFloatValue() * factor);
156     case kCalculated:
157       return Length(GetCalculationValue().Zoom(factor));
158     default:
159       return *this;
160   }
161 }
162 
GetCalculationValue() const163 CalculationValue& Length::GetCalculationValue() const {
164   DCHECK(IsCalculated());
165   return CalcHandles().Get(CalculationHandle());
166 }
167 
IncrementCalculatedRef() const168 void Length::IncrementCalculatedRef() const {
169   DCHECK(IsCalculated());
170   GetCalculationValue().AddRef();
171 }
172 
DecrementCalculatedRef() const173 void Length::DecrementCalculatedRef() const {
174   DCHECK(IsCalculated());
175   CalcHandles().DecrementRef(CalculationHandle());
176 }
177 
NonNanCalculatedValue(LayoutUnit max_value) const178 float Length::NonNanCalculatedValue(LayoutUnit max_value) const {
179   DCHECK(IsCalculated());
180   float result = GetCalculationValue().Evaluate(max_value.ToFloat());
181   if (std::isnan(result))
182     return 0;
183   return result;
184 }
185 
IsCalculatedEqual(const Length & o) const186 bool Length::IsCalculatedEqual(const Length& o) const {
187   return IsCalculated() &&
188          (&GetCalculationValue() == &o.GetCalculationValue() ||
189           GetCalculationValue() == o.GetCalculationValue());
190 }
191 
192 struct SameSizeAsLength {
193   int32_t value;
194   int32_t meta_data;
195 };
196 ASSERT_SIZE(Length, SameSizeAsLength);
197 
198 }  // namespace blink
199