1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h"
6 
7 #include "base/notreached.h"
8 
9 namespace blink {
10 
11 // ------ CalculationExpressionLeafNode ------
12 
Evaluate(float max_value) const13 float CalculationExpressionLeafNode::Evaluate(float max_value) const {
14   return value_.pixels + value_.percent / 100 * max_value;
15 }
16 
operator ==(const CalculationExpressionNode & other) const17 bool CalculationExpressionLeafNode::operator==(
18     const CalculationExpressionNode& other) const {
19   if (!other.IsLeaf())
20     return false;
21   const auto& other_leaf = To<CalculationExpressionLeafNode>(other);
22   return value_.pixels == other_leaf.value_.pixels &&
23          value_.percent == other_leaf.value_.percent;
24 }
25 
26 scoped_refptr<const CalculationExpressionNode>
Zoom(double factor) const27 CalculationExpressionLeafNode::Zoom(double factor) const {
28   PixelsAndPercent result(value_.pixels * factor, value_.percent);
29   return base::MakeRefCounted<CalculationExpressionLeafNode>(result);
30 }
31 
32 // ------ CalculationExpressionMultiplicationNode ------
33 
34 // static
35 scoped_refptr<const CalculationExpressionNode>
CreateSimplified(scoped_refptr<const CalculationExpressionNode> node,float factor)36 CalculationExpressionMultiplicationNode::CreateSimplified(
37     scoped_refptr<const CalculationExpressionNode> node,
38     float factor) {
39   if (!node->IsLeaf()) {
40     return base::MakeRefCounted<CalculationExpressionMultiplicationNode>(
41         std::move(node), factor);
42   }
43   const auto& leaf = To<CalculationExpressionLeafNode>(*node);
44   PixelsAndPercent value(leaf.Pixels() * factor, leaf.Percent() * factor);
45   return base::MakeRefCounted<CalculationExpressionLeafNode>(value);
46 }
47 
Evaluate(float max_value) const48 float CalculationExpressionMultiplicationNode::Evaluate(float max_value) const {
49   return child_->Evaluate(max_value) * factor_;
50 }
51 
operator ==(const CalculationExpressionNode & other) const52 bool CalculationExpressionMultiplicationNode::operator==(
53     const CalculationExpressionNode& other) const {
54   if (!other.IsMultiplication())
55     return false;
56   const auto& other_multiply =
57       To<CalculationExpressionMultiplicationNode>(other);
58   return factor_ == other_multiply.factor_ && *child_ == *other_multiply.child_;
59 }
60 
61 scoped_refptr<const CalculationExpressionNode>
Zoom(double factor) const62 CalculationExpressionMultiplicationNode::Zoom(double factor) const {
63   return CreateSimplified(child_->Zoom(factor), factor_);
64 }
65 
66 // ------ CalculationExpressionAdditiveNode ------
67 
68 // static
69 scoped_refptr<const CalculationExpressionNode>
CreateSimplified(scoped_refptr<const CalculationExpressionNode> lhs,scoped_refptr<const CalculationExpressionNode> rhs,Type type)70 CalculationExpressionAdditiveNode::CreateSimplified(
71     scoped_refptr<const CalculationExpressionNode> lhs,
72     scoped_refptr<const CalculationExpressionNode> rhs,
73     Type type) {
74   if (!lhs->IsLeaf() || !rhs->IsLeaf()) {
75     return base::MakeRefCounted<CalculationExpressionAdditiveNode>(
76         std::move(lhs), std::move(rhs), type);
77   }
78   const auto& left_leaf = To<CalculationExpressionLeafNode>(*lhs);
79   const auto& right_leaf = To<CalculationExpressionLeafNode>(*rhs);
80   PixelsAndPercent value = left_leaf.GetPixelsAndPercent();
81   if (type == Type::kAdd) {
82     value.pixels += right_leaf.Pixels();
83     value.percent += right_leaf.Percent();
84   } else {
85     value.pixels -= right_leaf.Pixels();
86     value.percent -= right_leaf.Percent();
87   }
88   return base::MakeRefCounted<CalculationExpressionLeafNode>(value);
89 }
90 
Evaluate(float max_value) const91 float CalculationExpressionAdditiveNode::Evaluate(float max_value) const {
92   if (IsAdd())
93     return lhs_->Evaluate(max_value) + rhs_->Evaluate(max_value);
94   if (IsSubtract())
95     return lhs_->Evaluate(max_value) - rhs_->Evaluate(max_value);
96   NOTREACHED();
97   return 0;
98 }
99 
operator ==(const CalculationExpressionNode & other) const100 bool CalculationExpressionAdditiveNode::operator==(
101     const CalculationExpressionNode& other) const {
102   if (!other.IsAdditive())
103     return false;
104   const auto& other_add_subtract = To<CalculationExpressionAdditiveNode>(other);
105   // Do we need to consider add as commutative?
106   return type_ == other_add_subtract.type_ &&
107          *lhs_ == *other_add_subtract.lhs_ && *rhs_ == *other_add_subtract.rhs_;
108 }
109 
110 scoped_refptr<const CalculationExpressionNode>
Zoom(double factor) const111 CalculationExpressionAdditiveNode::Zoom(double factor) const {
112   return CreateSimplified(lhs_->Zoom(factor), rhs_->Zoom(factor), type_);
113 }
114 
115 // ------ CalculationExpressionComparisonNode ------
116 
117 // static
118 scoped_refptr<const CalculationExpressionNode>
CreateSimplified(Vector<scoped_refptr<const CalculationExpressionNode>> && operands,Type type)119 CalculationExpressionComparisonNode::CreateSimplified(
120     Vector<scoped_refptr<const CalculationExpressionNode>>&& operands,
121     Type type) {
122   DCHECK(operands.size());
123   float simplified_px;
124   bool can_simplify = true;
125   for (wtf_size_t i = 0; i < operands.size(); ++i) {
126     const auto* leaf = DynamicTo<CalculationExpressionLeafNode>(*operands[i]);
127     if (!leaf || leaf->Percent()) {
128       can_simplify = false;
129       break;
130     }
131     if (!i) {
132       simplified_px = leaf->Pixels();
133     } else {
134       if (type == Type::kMin)
135         simplified_px = std::min(simplified_px, leaf->Pixels());
136       else
137         simplified_px = std::max(simplified_px, leaf->Pixels());
138     }
139   }
140   if (can_simplify) {
141     return base::MakeRefCounted<CalculationExpressionLeafNode>(
142         PixelsAndPercent(simplified_px, 0));
143   }
144   return base::MakeRefCounted<CalculationExpressionComparisonNode>(
145       std::move(operands), type);
146 }
147 
Evaluate(float max_value) const148 float CalculationExpressionComparisonNode::Evaluate(float max_value) const {
149   float result = operands_.front()->Evaluate(max_value);
150   if (IsMin()) {
151     for (wtf_size_t i = 1; i < operands_.size(); ++i)
152       result = std::min(result, operands_[i]->Evaluate(max_value));
153   } else if (IsMax()) {
154     for (wtf_size_t i = 1; i < operands_.size(); ++i)
155       result = std::max(result, operands_[i]->Evaluate(max_value));
156   } else {
157     NOTREACHED();
158   }
159   return result;
160 }
161 
operator ==(const CalculationExpressionNode & other) const162 bool CalculationExpressionComparisonNode::operator==(
163     const CalculationExpressionNode& other) const {
164   if (!other.IsComparison())
165     return false;
166   const auto& other_comparison = To<CalculationExpressionComparisonNode>(other);
167   if (type_ != other_comparison.type_)
168     return false;
169   if (operands_.size() != other_comparison.operands_.size())
170     return false;
171   // We may consider ignoring operand ordering to allow better memory
172   // optimization. The code complexity might not pay off, though.
173   for (wtf_size_t i = 0; i < operands_.size(); ++i) {
174     if (*operands_[i] != *other_comparison.operands_[i])
175       return false;
176   }
177   return true;
178 }
179 
180 scoped_refptr<const CalculationExpressionNode>
Zoom(double factor) const181 CalculationExpressionComparisonNode::Zoom(double factor) const {
182   Vector<scoped_refptr<const CalculationExpressionNode>> cloned_operands;
183   cloned_operands.ReserveCapacity(operands_.size());
184   for (const auto& operand : operands_)
185     cloned_operands.push_back(operand->Zoom(factor));
186   return CreateSimplified(std::move(cloned_operands), type_);
187 }
188 
189 }  // namespace blink
190