1/*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#include "config.h"
23#include "TransformOperations.h"
24
25#include "IdentityTransformOperation.h"
26#include "Matrix3DTransformOperation.h"
27#include <algorithm>
28#include <wtf/text/TextStream.h>
29
30namespace WebCore {
31
32TransformOperations::TransformOperations(bool makeIdentity)
33{
34 if (makeIdentity)
35 m_operations.append(IdentityTransformOperation::create());
36}
37
38bool TransformOperations::operator==(const TransformOperations& o) const
39{
40 if (m_operations.size() != o.m_operations.size())
41 return false;
42
43 unsigned s = m_operations.size();
44 for (unsigned i = 0; i < s; i++) {
45 if (*m_operations[i] != *o.m_operations[i])
46 return false;
47 }
48
49 return true;
50}
51
52bool TransformOperations::operationsMatch(const TransformOperations& other) const
53{
54 size_t numOperations = operations().size();
55 // If the sizes of the function lists don't match, the lists don't match
56 if (numOperations != other.operations().size())
57 return false;
58
59 // If the types of each function are not the same, the lists don't match
60 for (size_t i = 0; i < numOperations; ++i) {
61 if (!operations()[i]->isSameType(*other.operations()[i]))
62 return false;
63 }
64 return true;
65}
66
67bool TransformOperations::affectedByTransformOrigin() const
68{
69 for (const auto& operation : m_operations) {
70 if (operation->isAffectedByTransformOrigin())
71 return true;
72 }
73 return false;
74}
75
76TransformOperations TransformOperations::blendByMatchingOperations(const TransformOperations& from, const double& progress) const
77{
78 TransformOperations result;
79
80 unsigned fromSize = from.operations().size();
81 unsigned toSize = operations().size();
82 unsigned size = std::max(fromSize, toSize);
83 for (unsigned i = 0; i < size; i++) {
84 RefPtr<TransformOperation> fromOperation = (i < fromSize) ? from.operations()[i].get() : nullptr;
85 RefPtr<TransformOperation> toOperation = (i < toSize) ? operations()[i].get() : nullptr;
86 RefPtr<TransformOperation> blendedOperation = toOperation ? toOperation->blend(fromOperation.get(), progress) : (fromOperation ? RefPtr<TransformOperation>(fromOperation->blend(nullptr, progress, true)) : nullptr);
87 if (blendedOperation)
88 result.operations().append(blendedOperation);
89 else {
90 auto identityOperation = IdentityTransformOperation::create();
91 if (progress > 0.5)
92 result.operations().append(toOperation ? toOperation : WTFMove(identityOperation));
93 else
94 result.operations().append(fromOperation ? fromOperation : WTFMove(identityOperation));
95 }
96 }
97
98 return result;
99}
100
101TransformOperations TransformOperations::blendByUsingMatrixInterpolation(const TransformOperations& from, double progress, const LayoutSize& size) const
102{
103 TransformOperations result;
104
105 // Convert the TransformOperations into matrices
106 TransformationMatrix fromTransform;
107 TransformationMatrix toTransform;
108 from.apply(size, fromTransform);
109 apply(size, toTransform);
110
111 toTransform.blend(fromTransform, progress);
112
113 // Append the result
114 result.operations().append(Matrix3DTransformOperation::create(toTransform));
115
116 return result;
117}
118
119TransformOperations TransformOperations::blend(const TransformOperations& from, double progress, const LayoutSize& size) const
120{
121 if (from == *this)
122 return *this;
123
124 if (from.size() && from.operationsMatch(*this))
125 return blendByMatchingOperations(from, progress);
126
127 return blendByUsingMatrixInterpolation(from, progress, size);
128}
129
130TextStream& operator<<(TextStream& ts, const TransformOperations& ops)
131{
132 for (const auto& operation : ops.operations())
133 ts << *operation;
134 return ts;
135}
136
137} // namespace WebCore
138