2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
6 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7 * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11 * Copyright (C) 2012 Google Inc. All rights reserved.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB. If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 #include "core/css/resolver/TransformBuilder.h"
32 #include "core/css/CSSPrimitiveValueMappings.h"
33 #include "core/css/CSSTransformValue.h"
34 #include "core/rendering/style/RenderStyle.h"
35 #include "platform/heap/Handle.h"
36 #include "platform/transforms/Matrix3DTransformOperation.h"
37 #include "platform/transforms/MatrixTransformOperation.h"
38 #include "platform/transforms/PerspectiveTransformOperation.h"
39 #include "platform/transforms/RotateTransformOperation.h"
40 #include "platform/transforms/ScaleTransformOperation.h"
41 #include "platform/transforms/SkewTransformOperation.h"
42 #include "platform/transforms/TransformationMatrix.h"
43 #include "platform/transforms/TranslateTransformOperation.h"
47 static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, const CSSToLengthConversionData& conversionData)
49 ASSERT(primitiveValue);
50 return primitiveValue->convertToLength<FixedConversion | PercentConversion>(conversionData);
53 static TransformOperation::OperationType getTransformOperationType(CSSTransformValue::TransformOperationType type)
56 case CSSTransformValue::ScaleTransformOperation: return TransformOperation::Scale;
57 case CSSTransformValue::ScaleXTransformOperation: return TransformOperation::ScaleX;
58 case CSSTransformValue::ScaleYTransformOperation: return TransformOperation::ScaleY;
59 case CSSTransformValue::ScaleZTransformOperation: return TransformOperation::ScaleZ;
60 case CSSTransformValue::Scale3DTransformOperation: return TransformOperation::Scale3D;
61 case CSSTransformValue::TranslateTransformOperation: return TransformOperation::Translate;
62 case CSSTransformValue::TranslateXTransformOperation: return TransformOperation::TranslateX;
63 case CSSTransformValue::TranslateYTransformOperation: return TransformOperation::TranslateY;
64 case CSSTransformValue::TranslateZTransformOperation: return TransformOperation::TranslateZ;
65 case CSSTransformValue::Translate3DTransformOperation: return TransformOperation::Translate3D;
66 case CSSTransformValue::RotateTransformOperation: return TransformOperation::Rotate;
67 case CSSTransformValue::RotateXTransformOperation: return TransformOperation::RotateX;
68 case CSSTransformValue::RotateYTransformOperation: return TransformOperation::RotateY;
69 case CSSTransformValue::RotateZTransformOperation: return TransformOperation::RotateZ;
70 case CSSTransformValue::Rotate3DTransformOperation: return TransformOperation::Rotate3D;
71 case CSSTransformValue::SkewTransformOperation: return TransformOperation::Skew;
72 case CSSTransformValue::SkewXTransformOperation: return TransformOperation::SkewX;
73 case CSSTransformValue::SkewYTransformOperation: return TransformOperation::SkewY;
74 case CSSTransformValue::MatrixTransformOperation: return TransformOperation::Matrix;
75 case CSSTransformValue::Matrix3DTransformOperation: return TransformOperation::Matrix3D;
76 case CSSTransformValue::PerspectiveTransformOperation: return TransformOperation::Perspective;
77 case CSSTransformValue::UnknownTransformOperation: return TransformOperation::None;
79 return TransformOperation::None;
82 bool TransformBuilder::createTransformOperations(CSSValue* inValue, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations)
84 if (!inValue || !inValue->isValueList()) {
85 outOperations.clear();
89 float zoomFactor = conversionData.zoom();
90 TransformOperations operations;
91 for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
92 CSSValue* currValue = i.value();
94 if (!currValue->isTransformValue())
97 CSSTransformValue* transformValue = toCSSTransformValue(i.value());
98 if (!transformValue->length())
101 bool haveNonPrimitiveValue = false;
102 for (unsigned j = 0; j < transformValue->length(); ++j) {
103 if (!transformValue->item(j)->isPrimitiveValue()) {
104 haveNonPrimitiveValue = true;
108 if (haveNonPrimitiveValue)
111 CSSPrimitiveValue* firstValue = toCSSPrimitiveValue(transformValue->item(0));
113 switch (transformValue->operationType()) {
114 case CSSTransformValue::ScaleTransformOperation:
115 case CSSTransformValue::ScaleXTransformOperation:
116 case CSSTransformValue::ScaleYTransformOperation: {
119 if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation)
120 sy = firstValue->getDoubleValue();
122 sx = firstValue->getDoubleValue();
123 if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) {
124 if (transformValue->length() > 1) {
125 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
126 sy = secondValue->getDoubleValue();
131 operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType())));
134 case CSSTransformValue::ScaleZTransformOperation:
135 case CSSTransformValue::Scale3DTransformOperation: {
139 if (transformValue->operationType() == CSSTransformValue::ScaleZTransformOperation)
140 sz = firstValue->getDoubleValue();
141 else if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation)
142 sy = firstValue->getDoubleValue();
144 sx = firstValue->getDoubleValue();
145 if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) {
146 if (transformValue->length() > 2) {
147 CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2));
148 sz = thirdValue->getDoubleValue();
150 if (transformValue->length() > 1) {
151 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
152 sy = secondValue->getDoubleValue();
157 operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType())));
160 case CSSTransformValue::TranslateTransformOperation:
161 case CSSTransformValue::TranslateXTransformOperation:
162 case CSSTransformValue::TranslateYTransformOperation: {
163 Length tx = Length(0, Fixed);
164 Length ty = Length(0, Fixed);
165 if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation)
166 ty = convertToFloatLength(firstValue, conversionData);
168 tx = convertToFloatLength(firstValue, conversionData);
169 if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) {
170 if (transformValue->length() > 1) {
171 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
172 ty = convertToFloatLength(secondValue, conversionData);
177 operations.operations().append(TranslateTransformOperation::create(tx, ty, 0, getTransformOperationType(transformValue->operationType())));
180 case CSSTransformValue::TranslateZTransformOperation:
181 case CSSTransformValue::Translate3DTransformOperation: {
182 Length tx = Length(0, Fixed);
183 Length ty = Length(0, Fixed);
185 if (transformValue->operationType() == CSSTransformValue::TranslateZTransformOperation)
186 tz = firstValue->computeLength<double>(conversionData);
187 else if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation)
188 ty = convertToFloatLength(firstValue, conversionData);
190 tx = convertToFloatLength(firstValue, conversionData);
191 if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) {
192 if (transformValue->length() > 2) {
193 CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2));
194 tz = thirdValue->computeLength<double>(conversionData);
196 if (transformValue->length() > 1) {
197 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
198 ty = convertToFloatLength(secondValue, conversionData);
203 operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType())));
206 case CSSTransformValue::RotateTransformOperation: {
207 double angle = firstValue->computeDegrees();
208 operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType())));
211 case CSSTransformValue::RotateXTransformOperation:
212 case CSSTransformValue::RotateYTransformOperation:
213 case CSSTransformValue::RotateZTransformOperation: {
217 double angle = firstValue->computeDegrees();
219 if (transformValue->operationType() == CSSTransformValue::RotateXTransformOperation)
221 else if (transformValue->operationType() == CSSTransformValue::RotateYTransformOperation)
225 operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType())));
228 case CSSTransformValue::Rotate3DTransformOperation: {
229 if (transformValue->length() < 4)
231 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
232 CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2));
233 CSSPrimitiveValue* fourthValue = toCSSPrimitiveValue(transformValue->item(3));
234 double x = firstValue->getDoubleValue();
235 double y = secondValue->getDoubleValue();
236 double z = thirdValue->getDoubleValue();
237 double angle = fourthValue->computeDegrees();
238 operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType())));
241 case CSSTransformValue::SkewTransformOperation:
242 case CSSTransformValue::SkewXTransformOperation:
243 case CSSTransformValue::SkewYTransformOperation: {
246 double angle = firstValue->computeDegrees();
247 if (transformValue->operationType() == CSSTransformValue::SkewYTransformOperation)
251 if (transformValue->operationType() == CSSTransformValue::SkewTransformOperation) {
252 if (transformValue->length() > 1) {
253 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
254 angleY = secondValue->computeDegrees();
258 operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType())));
261 case CSSTransformValue::MatrixTransformOperation: {
262 if (transformValue->length() < 6)
264 double a = firstValue->getDoubleValue();
265 double b = toCSSPrimitiveValue(transformValue->item(1))->getDoubleValue();
266 double c = toCSSPrimitiveValue(transformValue->item(2))->getDoubleValue();
267 double d = toCSSPrimitiveValue(transformValue->item(3))->getDoubleValue();
268 double e = zoomFactor * toCSSPrimitiveValue(transformValue->item(4))->getDoubleValue();
269 double f = zoomFactor * toCSSPrimitiveValue(transformValue->item(5))->getDoubleValue();
270 operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f));
273 case CSSTransformValue::Matrix3DTransformOperation: {
274 if (transformValue->length() < 16)
276 TransformationMatrix matrix(toCSSPrimitiveValue(transformValue->item(0))->getDoubleValue(),
277 toCSSPrimitiveValue(transformValue->item(1))->getDoubleValue(),
278 toCSSPrimitiveValue(transformValue->item(2))->getDoubleValue(),
279 toCSSPrimitiveValue(transformValue->item(3))->getDoubleValue(),
280 toCSSPrimitiveValue(transformValue->item(4))->getDoubleValue(),
281 toCSSPrimitiveValue(transformValue->item(5))->getDoubleValue(),
282 toCSSPrimitiveValue(transformValue->item(6))->getDoubleValue(),
283 toCSSPrimitiveValue(transformValue->item(7))->getDoubleValue(),
284 toCSSPrimitiveValue(transformValue->item(8))->getDoubleValue(),
285 toCSSPrimitiveValue(transformValue->item(9))->getDoubleValue(),
286 toCSSPrimitiveValue(transformValue->item(10))->getDoubleValue(),
287 toCSSPrimitiveValue(transformValue->item(11))->getDoubleValue(),
288 zoomFactor * toCSSPrimitiveValue(transformValue->item(12))->getDoubleValue(),
289 zoomFactor * toCSSPrimitiveValue(transformValue->item(13))->getDoubleValue(),
290 toCSSPrimitiveValue(transformValue->item(14))->getDoubleValue(),
291 toCSSPrimitiveValue(transformValue->item(15))->getDoubleValue());
292 operations.operations().append(Matrix3DTransformOperation::create(matrix));
295 case CSSTransformValue::PerspectiveTransformOperation: {
297 if (firstValue->isLength())
298 p = firstValue->computeLength<double>(conversionData);
300 // This is a quirk that should go away when 3d transforms are finalized.
301 double val = firstValue->getDoubleValue();
304 p = clampTo<int>(val, 0);
307 operations.operations().append(PerspectiveTransformOperation::create(p));
310 case CSSTransformValue::UnknownTransformOperation:
311 ASSERT_NOT_REACHED();
316 outOperations = operations;