Unreviewed, rolling out r156253.
[WebKit-https.git] / Source / WebCore / css / TransformFunctions.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above
11  *    copyright notice, this list of conditions and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials
16  *    provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "TransformFunctions.h"
34
35 #include "CSSPrimitiveValueMappings.h"
36 #include "CSSValueList.h"
37 #include "CSSValuePool.h"
38 #include "Matrix3DTransformOperation.h"
39 #include "MatrixTransformOperation.h"
40 #include "PerspectiveTransformOperation.h"
41 #include "RenderStyle.h"
42 #include "RotateTransformOperation.h"
43 #include "ScaleTransformOperation.h"
44 #include "SkewTransformOperation.h"
45 #include "TranslateTransformOperation.h"
46 #include "WebKitCSSTransformValue.h"
47
48 namespace WebCore {
49
50 static TransformOperation::OperationType transformOperationType(WebKitCSSTransformValue::TransformOperationType type)
51 {
52     switch (type) {
53     case WebKitCSSTransformValue::ScaleTransformOperation: return TransformOperation::SCALE;
54     case WebKitCSSTransformValue::ScaleXTransformOperation: return TransformOperation::SCALE_X;
55     case WebKitCSSTransformValue::ScaleYTransformOperation: return TransformOperation::SCALE_Y;
56     case WebKitCSSTransformValue::ScaleZTransformOperation: return TransformOperation::SCALE_Z;
57     case WebKitCSSTransformValue::Scale3DTransformOperation: return TransformOperation::SCALE_3D;
58     case WebKitCSSTransformValue::TranslateTransformOperation: return TransformOperation::TRANSLATE;
59     case WebKitCSSTransformValue::TranslateXTransformOperation: return TransformOperation::TRANSLATE_X;
60     case WebKitCSSTransformValue::TranslateYTransformOperation: return TransformOperation::TRANSLATE_Y;
61     case WebKitCSSTransformValue::TranslateZTransformOperation: return TransformOperation::TRANSLATE_Z;
62     case WebKitCSSTransformValue::Translate3DTransformOperation: return TransformOperation::TRANSLATE_3D;
63     case WebKitCSSTransformValue::RotateTransformOperation: return TransformOperation::ROTATE;
64     case WebKitCSSTransformValue::RotateXTransformOperation: return TransformOperation::ROTATE_X;
65     case WebKitCSSTransformValue::RotateYTransformOperation: return TransformOperation::ROTATE_Y;
66     case WebKitCSSTransformValue::RotateZTransformOperation: return TransformOperation::ROTATE_Z;
67     case WebKitCSSTransformValue::Rotate3DTransformOperation: return TransformOperation::ROTATE_3D;
68     case WebKitCSSTransformValue::SkewTransformOperation: return TransformOperation::SKEW;
69     case WebKitCSSTransformValue::SkewXTransformOperation: return TransformOperation::SKEW_X;
70     case WebKitCSSTransformValue::SkewYTransformOperation: return TransformOperation::SKEW_Y;
71     case WebKitCSSTransformValue::MatrixTransformOperation: return TransformOperation::MATRIX;
72     case WebKitCSSTransformValue::Matrix3DTransformOperation: return TransformOperation::MATRIX_3D;
73     case WebKitCSSTransformValue::PerspectiveTransformOperation: return TransformOperation::PERSPECTIVE;
74     case WebKitCSSTransformValue::UnknownTransformOperation: return TransformOperation::NONE;
75     }
76     return TransformOperation::NONE;
77 }
78
79 static Length convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier)
80 {
81     return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
82 }
83
84 bool transformsForValue(const RenderStyle* style, const RenderStyle* rootStyle, CSSValue* value, TransformOperations& outOperations)
85 {
86     if (!value || !value->isValueList()) {
87         outOperations.clear();
88         return false;
89     }
90
91     float zoomFactor = style ? style->effectiveZoom() : 1;
92     TransformOperations operations;
93     for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
94         CSSValue* currValue = i.value();
95
96         if (!currValue->isWebKitCSSTransformValue())
97             continue;
98
99         WebKitCSSTransformValue* transformValue = static_cast<WebKitCSSTransformValue*>(i.value());
100         if (!transformValue->length())
101             continue;
102
103         bool haveNonPrimitiveValue = false;
104         for (unsigned j = 0; j < transformValue->length(); ++j) {
105             if (!transformValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) {
106                 haveNonPrimitiveValue = true;
107                 break;
108             }
109         }
110         if (haveNonPrimitiveValue)
111             continue;
112
113         CSSPrimitiveValue* firstValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0));
114
115         switch (transformValue->operationType()) {
116         case WebKitCSSTransformValue::ScaleTransformOperation:
117         case WebKitCSSTransformValue::ScaleXTransformOperation:
118         case WebKitCSSTransformValue::ScaleYTransformOperation: {
119             double sx = 1.0;
120             double sy = 1.0;
121             if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
122                 sy = firstValue->getDoubleValue();
123             else {
124                 sx = firstValue->getDoubleValue();
125                 if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
126                     if (transformValue->length() > 1) {
127                         CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
128                         sy = secondValue->getDoubleValue();
129                     } else
130                         sy = sx;
131                 }
132             }
133             operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, transformOperationType(transformValue->operationType())));
134             break;
135         }
136         case WebKitCSSTransformValue::ScaleZTransformOperation:
137         case WebKitCSSTransformValue::Scale3DTransformOperation: {
138             double sx = 1.0;
139             double sy = 1.0;
140             double sz = 1.0;
141             if (transformValue->operationType() == WebKitCSSTransformValue::ScaleZTransformOperation)
142                 sz = firstValue->getDoubleValue();
143             else if (transformValue->operationType() == WebKitCSSTransformValue::ScaleYTransformOperation)
144                 sy = firstValue->getDoubleValue();
145             else {
146                 sx = firstValue->getDoubleValue();
147                 if (transformValue->operationType() != WebKitCSSTransformValue::ScaleXTransformOperation) {
148                     if (transformValue->length() > 2) {
149                         CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
150                         sz = thirdValue->getDoubleValue();
151                     }
152                     if (transformValue->length() > 1) {
153                         CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
154                         sy = secondValue->getDoubleValue();
155                     } else
156                         sy = sx;
157                 }
158             }
159             operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, transformOperationType(transformValue->operationType())));
160             break;
161         }
162         case WebKitCSSTransformValue::TranslateTransformOperation:
163         case WebKitCSSTransformValue::TranslateXTransformOperation:
164         case WebKitCSSTransformValue::TranslateYTransformOperation: {
165             Length tx = Length(0, Fixed);
166             Length ty = Length(0, Fixed);
167             if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
168                 ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
169             else {
170                 tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
171                 if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
172                     if (transformValue->length() > 1) {
173                         CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
174                         ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor);
175                     }
176                 }
177             }
178
179             if (tx.isUndefined() || ty.isUndefined())
180                 return false;
181
182             operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), transformOperationType(transformValue->operationType())));
183             break;
184         }
185         case WebKitCSSTransformValue::TranslateZTransformOperation:
186         case WebKitCSSTransformValue::Translate3DTransformOperation: {
187             Length tx = Length(0, Fixed);
188             Length ty = Length(0, Fixed);
189             Length tz = Length(0, Fixed);
190             if (transformValue->operationType() == WebKitCSSTransformValue::TranslateZTransformOperation)
191                 tz = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
192             else if (transformValue->operationType() == WebKitCSSTransformValue::TranslateYTransformOperation)
193                 ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
194             else {
195                 tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
196                 if (transformValue->operationType() != WebKitCSSTransformValue::TranslateXTransformOperation) {
197                     if (transformValue->length() > 2) {
198                         CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
199                         tz = convertToFloatLength(thirdValue, style, rootStyle, zoomFactor);
200                     }
201                     if (transformValue->length() > 1) {
202                         CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
203                         ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor);
204                     }
205                 }
206             }
207
208             if (tx.isUndefined() || ty.isUndefined() || tz.isUndefined())
209                 return false;
210
211             operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, transformOperationType(transformValue->operationType())));
212             break;
213         }
214         case WebKitCSSTransformValue::RotateTransformOperation: {
215             double angle = firstValue->computeDegrees();
216             operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, transformOperationType(transformValue->operationType())));
217             break;
218         }
219         case WebKitCSSTransformValue::RotateXTransformOperation:
220         case WebKitCSSTransformValue::RotateYTransformOperation:
221         case WebKitCSSTransformValue::RotateZTransformOperation: {
222             double x = 0;
223             double y = 0;
224             double z = 0;
225             double angle = firstValue->computeDegrees();
226
227             if (transformValue->operationType() == WebKitCSSTransformValue::RotateXTransformOperation)
228                 x = 1;
229             else if (transformValue->operationType() == WebKitCSSTransformValue::RotateYTransformOperation)
230                 y = 1;
231             else
232                 z = 1;
233             operations.operations().append(RotateTransformOperation::create(x, y, z, angle, transformOperationType(transformValue->operationType())));
234             break;
235         }
236         case WebKitCSSTransformValue::Rotate3DTransformOperation: {
237             if (transformValue->length() < 4)
238                 break;
239             CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
240             CSSPrimitiveValue* thirdValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2));
241             CSSPrimitiveValue* fourthValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3));
242             double x = firstValue->getDoubleValue();
243             double y = secondValue->getDoubleValue();
244             double z = thirdValue->getDoubleValue();
245             double angle = fourthValue->computeDegrees();
246             operations.operations().append(RotateTransformOperation::create(x, y, z, angle, transformOperationType(transformValue->operationType())));
247             break;
248         }
249         case WebKitCSSTransformValue::SkewTransformOperation:
250         case WebKitCSSTransformValue::SkewXTransformOperation:
251         case WebKitCSSTransformValue::SkewYTransformOperation: {
252             double angleX = 0;
253             double angleY = 0;
254             double angle = firstValue->computeDegrees();
255             if (transformValue->operationType() == WebKitCSSTransformValue::SkewYTransformOperation)
256                 angleY = angle;
257             else {
258                 angleX = angle;
259                 if (transformValue->operationType() == WebKitCSSTransformValue::SkewTransformOperation) {
260                     if (transformValue->length() > 1) {
261                         CSSPrimitiveValue* secondValue = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1));
262                         angleY = secondValue->computeDegrees();
263                     }
264                 }
265             }
266             operations.operations().append(SkewTransformOperation::create(angleX, angleY, transformOperationType(transformValue->operationType())));
267             break;
268         }
269         case WebKitCSSTransformValue::MatrixTransformOperation: {
270             if (transformValue->length() < 6)
271                 break;
272             double a = firstValue->getDoubleValue();
273             double b = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue();
274             double c = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue();
275             double d = static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue();
276             double e = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue();
277             double f = zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue();
278             operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f));
279             break;
280         }
281         case WebKitCSSTransformValue::Matrix3DTransformOperation: {
282             if (transformValue->length() < 16)
283                 break;
284             TransformationMatrix matrix(static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(0))->getDoubleValue(),
285                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(),
286                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(),
287                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(),
288                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(),
289                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(),
290                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(6))->getDoubleValue(),
291                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(7))->getDoubleValue(),
292                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(8))->getDoubleValue(),
293                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(9))->getDoubleValue(),
294                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(10))->getDoubleValue(),
295                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(11))->getDoubleValue(),
296                                 zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(12))->getDoubleValue(),
297                                 zoomFactor * static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(13))->getDoubleValue(),
298                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(14))->getDoubleValue(),
299                                 static_cast<CSSPrimitiveValue*>(transformValue->itemWithoutBoundsCheck(15))->getDoubleValue());
300             operations.operations().append(Matrix3DTransformOperation::create(matrix));
301             break;
302         }
303         case WebKitCSSTransformValue::PerspectiveTransformOperation: {
304             Length p = Length(0, Fixed);
305             if (firstValue->isLength())
306                 p = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
307             else {
308                 // This is a quirk that should go away when 3d transforms are finalized.
309                 double val = firstValue->getDoubleValue();
310                 p = val >= 0 ? Length(clampToPositiveInteger(val), Fixed) : Length(Undefined);
311             }
312
313             if (p.isUndefined())
314                 return false;
315
316             operations.operations().append(PerspectiveTransformOperation::create(p));
317             break;
318         }
319         case WebKitCSSTransformValue::UnknownTransformOperation:
320             ASSERT_NOT_REACHED();
321             break;
322         }
323     }
324
325     outOperations = operations;
326     return true;
327 }
328
329 }