// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/renderer/platform/geometry/calculation_expression_node.h" #include "base/notreached.h" namespace blink { // ------ CalculationExpressionLeafNode ------ float CalculationExpressionLeafNode::Evaluate(float max_value) const { return value_.pixels + value_.percent / 100 * max_value; } bool CalculationExpressionLeafNode::operator==( const CalculationExpressionNode& other) const { if (!other.IsLeaf()) return false; const auto& other_leaf = To(other); return value_.pixels == other_leaf.value_.pixels && value_.percent == other_leaf.value_.percent; } scoped_refptr CalculationExpressionLeafNode::Zoom(double factor) const { PixelsAndPercent result(value_.pixels * factor, value_.percent); return base::MakeRefCounted(result); } // ------ CalculationExpressionMultiplicationNode ------ // static scoped_refptr CalculationExpressionMultiplicationNode::CreateSimplified( scoped_refptr node, float factor) { if (!node->IsLeaf()) { return base::MakeRefCounted( std::move(node), factor); } const auto& leaf = To(*node); PixelsAndPercent value(leaf.Pixels() * factor, leaf.Percent() * factor); return base::MakeRefCounted(value); } float CalculationExpressionMultiplicationNode::Evaluate(float max_value) const { return child_->Evaluate(max_value) * factor_; } bool CalculationExpressionMultiplicationNode::operator==( const CalculationExpressionNode& other) const { if (!other.IsMultiplication()) return false; const auto& other_multiply = To(other); return factor_ == other_multiply.factor_ && *child_ == *other_multiply.child_; } scoped_refptr CalculationExpressionMultiplicationNode::Zoom(double factor) const { return CreateSimplified(child_->Zoom(factor), factor_); } // ------ CalculationExpressionAdditiveNode ------ // static scoped_refptr CalculationExpressionAdditiveNode::CreateSimplified( scoped_refptr lhs, scoped_refptr rhs, Type type) { if (!lhs->IsLeaf() || !rhs->IsLeaf()) { return base::MakeRefCounted( std::move(lhs), std::move(rhs), type); } const auto& left_leaf = To(*lhs); const auto& right_leaf = To(*rhs); PixelsAndPercent value = left_leaf.GetPixelsAndPercent(); if (type == Type::kAdd) { value.pixels += right_leaf.Pixels(); value.percent += right_leaf.Percent(); } else { value.pixels -= right_leaf.Pixels(); value.percent -= right_leaf.Percent(); } return base::MakeRefCounted(value); } float CalculationExpressionAdditiveNode::Evaluate(float max_value) const { if (IsAdd()) return lhs_->Evaluate(max_value) + rhs_->Evaluate(max_value); if (IsSubtract()) return lhs_->Evaluate(max_value) - rhs_->Evaluate(max_value); NOTREACHED(); return 0; } bool CalculationExpressionAdditiveNode::operator==( const CalculationExpressionNode& other) const { if (!other.IsAdditive()) return false; const auto& other_add_subtract = To(other); // Do we need to consider add as commutative? return type_ == other_add_subtract.type_ && *lhs_ == *other_add_subtract.lhs_ && *rhs_ == *other_add_subtract.rhs_; } scoped_refptr CalculationExpressionAdditiveNode::Zoom(double factor) const { return CreateSimplified(lhs_->Zoom(factor), rhs_->Zoom(factor), type_); } // ------ CalculationExpressionComparisonNode ------ // static scoped_refptr CalculationExpressionComparisonNode::CreateSimplified( Vector>&& operands, Type type) { DCHECK(operands.size()); float simplified_px; bool can_simplify = true; for (wtf_size_t i = 0; i < operands.size(); ++i) { const auto* leaf = DynamicTo(*operands[i]); if (!leaf || leaf->Percent()) { can_simplify = false; break; } if (!i) { simplified_px = leaf->Pixels(); } else { if (type == Type::kMin) simplified_px = std::min(simplified_px, leaf->Pixels()); else simplified_px = std::max(simplified_px, leaf->Pixels()); } } if (can_simplify) { return base::MakeRefCounted( PixelsAndPercent(simplified_px, 0)); } return base::MakeRefCounted( std::move(operands), type); } float CalculationExpressionComparisonNode::Evaluate(float max_value) const { float result = operands_.front()->Evaluate(max_value); if (IsMin()) { for (wtf_size_t i = 1; i < operands_.size(); ++i) result = std::min(result, operands_[i]->Evaluate(max_value)); } else if (IsMax()) { for (wtf_size_t i = 1; i < operands_.size(); ++i) result = std::max(result, operands_[i]->Evaluate(max_value)); } else { NOTREACHED(); } return result; } bool CalculationExpressionComparisonNode::operator==( const CalculationExpressionNode& other) const { if (!other.IsComparison()) return false; const auto& other_comparison = To(other); if (type_ != other_comparison.type_) return false; if (operands_.size() != other_comparison.operands_.size()) return false; // We may consider ignoring operand ordering to allow better memory // optimization. The code complexity might not pay off, though. for (wtf_size_t i = 0; i < operands_.size(); ++i) { if (*operands_[i] != *other_comparison.operands_[i]) return false; } return true; } scoped_refptr CalculationExpressionComparisonNode::Zoom(double factor) const { Vector> cloned_operands; cloned_operands.ReserveCapacity(operands_.size()); for (const auto& operand : operands_) cloned_operands.push_back(operand->Zoom(factor)); return CreateSimplified(std::move(cloned_operands), type_); } } // namespace blink