1 | /* |
2 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Library General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Library General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Library General Public License |
15 | * along with this library; see the file COPYING.LIB. If not, write to |
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include "config.h" |
21 | #include "SVGTransformDistance.h" |
22 | |
23 | #include "FloatConversion.h" |
24 | #include "FloatPoint.h" |
25 | #include "FloatSize.h" |
26 | #include "SVGTransformValue.h" |
27 | |
28 | #include <math.h> |
29 | |
30 | namespace WebCore { |
31 | |
32 | SVGTransformDistance::SVGTransformDistance() |
33 | : m_type(SVGTransformValue::SVG_TRANSFORM_UNKNOWN) |
34 | , m_angle(0) |
35 | , m_cx(0) |
36 | , m_cy(0) |
37 | { |
38 | } |
39 | |
40 | SVGTransformDistance::SVGTransformDistance(SVGTransformValue::SVGTransformType type, float angle, float cx, float cy, const AffineTransform& transform) |
41 | : m_type(type) |
42 | , m_angle(angle) |
43 | , m_cx(cx) |
44 | , m_cy(cy) |
45 | , m_transform(transform) |
46 | { |
47 | } |
48 | |
49 | SVGTransformDistance::SVGTransformDistance(const SVGTransformValue& fromSVGTransform, const SVGTransformValue& toSVGTransform) |
50 | : m_type(fromSVGTransform.type()) |
51 | , m_angle(0) |
52 | , m_cx(0) |
53 | , m_cy(0) |
54 | { |
55 | ASSERT(m_type == toSVGTransform.type()); |
56 | |
57 | switch (m_type) { |
58 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
59 | ASSERT_NOT_REACHED(); |
60 | #if ASSERT_DISABLED |
61 | FALLTHROUGH; |
62 | #endif |
63 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
64 | break; |
65 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: { |
66 | FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter(); |
67 | m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); |
68 | m_cx = centerDistance.width(); |
69 | m_cy = centerDistance.height(); |
70 | break; |
71 | } |
72 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: { |
73 | FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate(); |
74 | m_transform.translate(translationDistance.width(), translationDistance.height()); |
75 | break; |
76 | } |
77 | case SVGTransformValue::SVG_TRANSFORM_SCALE: { |
78 | float scaleX = toSVGTransform.scale().width() - fromSVGTransform.scale().width(); |
79 | float scaleY = toSVGTransform.scale().height() - fromSVGTransform.scale().height(); |
80 | m_transform.scaleNonUniform(scaleX, scaleY); |
81 | break; |
82 | } |
83 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
84 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
85 | m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); |
86 | break; |
87 | } |
88 | } |
89 | |
90 | SVGTransformDistance SVGTransformDistance::scaledDistance(float scaleFactor) const |
91 | { |
92 | switch (m_type) { |
93 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
94 | ASSERT_NOT_REACHED(); |
95 | #if ASSERT_DISABLED |
96 | FALLTHROUGH; |
97 | #endif |
98 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
99 | return SVGTransformDistance(); |
100 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: |
101 | return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform()); |
102 | case SVGTransformValue::SVG_TRANSFORM_SCALE: |
103 | return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform(m_transform).scale(scaleFactor)); |
104 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: { |
105 | AffineTransform newTransform(m_transform); |
106 | newTransform.setE(m_transform.e() * scaleFactor); |
107 | newTransform.setF(m_transform.f() * scaleFactor); |
108 | return SVGTransformDistance(m_type, 0, 0, 0, newTransform); |
109 | } |
110 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
111 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
112 | return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform()); |
113 | } |
114 | |
115 | ASSERT_NOT_REACHED(); |
116 | return SVGTransformDistance(); |
117 | } |
118 | |
119 | SVGTransformValue SVGTransformDistance::addSVGTransforms(const SVGTransformValue& first, const SVGTransformValue& second, unsigned repeatCount) |
120 | { |
121 | ASSERT(first.type() == second.type()); |
122 | |
123 | SVGTransformValue transform; |
124 | |
125 | switch (first.type()) { |
126 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
127 | ASSERT_NOT_REACHED(); |
128 | #if ASSERT_DISABLED |
129 | FALLTHROUGH; |
130 | #endif |
131 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
132 | return { }; |
133 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: { |
134 | transform.setRotate(first.angle() + second.angle() * repeatCount, first.rotationCenter().x() + second.rotationCenter().x() * repeatCount, first.rotationCenter().y() + second.rotationCenter().y() * repeatCount); |
135 | return transform; |
136 | } |
137 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: { |
138 | float dx = first.translate().x() + second.translate().x() * repeatCount; |
139 | float dy = first.translate().y() + second.translate().y() * repeatCount; |
140 | transform.setTranslate(dx, dy); |
141 | return transform; |
142 | } |
143 | case SVGTransformValue::SVG_TRANSFORM_SCALE: { |
144 | FloatSize scale = second.scale(); |
145 | scale.scale(repeatCount); |
146 | scale += first.scale(); |
147 | transform.setScale(scale.width(), scale.height()); |
148 | return transform; |
149 | } |
150 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
151 | transform.setSkewX(first.angle() + second.angle() * repeatCount); |
152 | return transform; |
153 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
154 | transform.setSkewY(first.angle() + second.angle() * repeatCount); |
155 | return transform; |
156 | } |
157 | ASSERT_NOT_REACHED(); |
158 | return { }; |
159 | } |
160 | |
161 | SVGTransformValue SVGTransformDistance::addToSVGTransform(const SVGTransformValue& transform) const |
162 | { |
163 | ASSERT(m_type == transform.type() || !transform.isValid()); |
164 | |
165 | SVGTransformValue newTransform(transform); |
166 | |
167 | switch (m_type) { |
168 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
169 | ASSERT_NOT_REACHED(); |
170 | #if ASSERT_DISABLED |
171 | FALLTHROUGH; |
172 | #endif |
173 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
174 | return { }; |
175 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: { |
176 | FloatPoint translation = transform.translate(); |
177 | translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f()); |
178 | newTransform.setTranslate(translation.x(), translation.y()); |
179 | return newTransform; |
180 | } |
181 | case SVGTransformValue::SVG_TRANSFORM_SCALE: { |
182 | FloatSize scale = transform.scale(); |
183 | scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d()); |
184 | newTransform.setScale(scale.width(), scale.height()); |
185 | return newTransform; |
186 | } |
187 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: { |
188 | FloatPoint center = transform.rotationCenter(); |
189 | newTransform.setRotate(transform.angle() + m_angle, center.x() + m_cx, center.y() + m_cy); |
190 | return newTransform; |
191 | } |
192 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
193 | newTransform.setSkewX(transform.angle() + m_angle); |
194 | return newTransform; |
195 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
196 | newTransform.setSkewY(transform.angle() + m_angle); |
197 | return newTransform; |
198 | } |
199 | |
200 | ASSERT_NOT_REACHED(); |
201 | return { }; |
202 | } |
203 | |
204 | bool SVGTransformDistance::isZero() const |
205 | { |
206 | return m_transform.isIdentity() && !m_angle; |
207 | } |
208 | |
209 | float SVGTransformDistance::distance() const |
210 | { |
211 | switch (m_type) { |
212 | case SVGTransformValue::SVG_TRANSFORM_MATRIX: |
213 | ASSERT_NOT_REACHED(); |
214 | #if ASSERT_DISABLED |
215 | FALLTHROUGH; |
216 | #endif |
217 | case SVGTransformValue::SVG_TRANSFORM_UNKNOWN: |
218 | return 0; |
219 | case SVGTransformValue::SVG_TRANSFORM_ROTATE: |
220 | return sqrtf(m_angle * m_angle + m_cx * m_cx + m_cy * m_cy); |
221 | case SVGTransformValue::SVG_TRANSFORM_SCALE: |
222 | return static_cast<float>(sqrt(m_transform.a() * m_transform.a() + m_transform.d() * m_transform.d())); |
223 | case SVGTransformValue::SVG_TRANSFORM_TRANSLATE: |
224 | return static_cast<float>(sqrt(m_transform.e() * m_transform.e() + m_transform.f() * m_transform.f())); |
225 | case SVGTransformValue::SVG_TRANSFORM_SKEWX: |
226 | case SVGTransformValue::SVG_TRANSFORM_SKEWY: |
227 | return m_angle; |
228 | } |
229 | ASSERT_NOT_REACHED(); |
230 | return 0; |
231 | } |
232 | |
233 | } |
234 | |