[CSS Parser] Remove WebkitCSSTransformValue
[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 "CSSFunctionValue.h"
36 #include "CSSPrimitiveValueMappings.h"
37 #include "CSSValueList.h"
38 #include "CSSValuePool.h"
39 #include "Matrix3DTransformOperation.h"
40 #include "MatrixTransformOperation.h"
41 #include "PerspectiveTransformOperation.h"
42 #include "RotateTransformOperation.h"
43 #include "ScaleTransformOperation.h"
44 #include "SkewTransformOperation.h"
45 #include "TranslateTransformOperation.h"
46
47 namespace WebCore {
48
49 static TransformOperation::OperationType transformOperationType(CSSValueID type)
50 {
51     switch (type) {
52     case CSSValueScale:
53         return TransformOperation::SCALE;
54     case CSSValueScalex:
55         return TransformOperation::SCALE_X;
56     case CSSValueScaley:
57         return TransformOperation::SCALE_Y;
58     case CSSValueScalez:
59         return TransformOperation::SCALE_Z;
60     case CSSValueScale3d:
61         return TransformOperation::SCALE_3D;
62     case CSSValueTranslate:
63         return TransformOperation::TRANSLATE;
64     case CSSValueTranslatex:
65         return TransformOperation::TRANSLATE_X;
66     case CSSValueTranslatey:
67         return TransformOperation::TRANSLATE_Y;
68     case CSSValueTranslatez:
69         return TransformOperation::TRANSLATE_Z;
70     case CSSValueTranslate3d:
71         return TransformOperation::TRANSLATE_3D;
72     case CSSValueRotate:
73         return TransformOperation::ROTATE;
74     case CSSValueRotatex:
75         return TransformOperation::ROTATE_X;
76     case CSSValueRotatey:
77         return TransformOperation::ROTATE_Y;
78     case CSSValueRotatez:
79         return TransformOperation::ROTATE_Z;
80     case CSSValueRotate3d:
81         return TransformOperation::ROTATE_3D;
82     case CSSValueSkew:
83         return TransformOperation::SKEW;
84     case CSSValueSkewx:
85         return TransformOperation::SKEW_X;
86     case CSSValueSkewy:
87         return TransformOperation::SKEW_Y;
88     case CSSValueMatrix:
89         return TransformOperation::MATRIX;
90     case CSSValueMatrix3d:
91         return TransformOperation::MATRIX_3D;
92     case CSSValuePerspective:
93         return TransformOperation::PERSPECTIVE;
94     default:
95         break;
96     }
97     return TransformOperation::NONE;
98 }
99
100 Length convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const CSSToLengthConversionData& conversionData)
101 {
102     return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion>(conversionData) : Length(Undefined);
103 }
104
105 bool transformsForValue(const CSSValue& value, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations)
106 {
107     if (!is<CSSValueList>(value)) {
108         outOperations.clear();
109         return false;
110     }
111
112     TransformOperations operations;
113     for (auto& currentValue : downcast<CSSValueList>(value)) {
114         if (!is<CSSFunctionValue>(currentValue.get()))
115             continue;
116
117         auto& transformValue = downcast<CSSFunctionValue>(currentValue.get());
118         if (!transformValue.length())
119             continue;
120
121         bool haveNonPrimitiveValue = false;
122         for (unsigned j = 0; j < transformValue.length(); ++j) {
123             if (!is<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(j))) {
124                 haveNonPrimitiveValue = true;
125                 break;
126             }
127         }
128         if (haveNonPrimitiveValue)
129             continue;
130
131         auto& firstValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(0));
132
133         switch (transformValue.name()) {
134         case CSSValueScale:
135         case CSSValueScalex:
136         case CSSValueScaley: {
137             double sx = 1.0;
138             double sy = 1.0;
139             if (transformValue.name() == CSSValueScaley)
140                 sy = firstValue.doubleValue();
141             else {
142                 sx = firstValue.doubleValue();
143                 if (transformValue.name() != CSSValueScalex) {
144                     if (transformValue.length() > 1) {
145                         auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
146                         sy = secondValue.doubleValue();
147                     } else
148                         sy = sx;
149                 }
150             }
151             operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, transformOperationType(transformValue.name())));
152             break;
153         }
154         case CSSValueScalez:
155         case CSSValueScale3d: {
156             double sx = 1.0;
157             double sy = 1.0;
158             double sz = 1.0;
159             if (transformValue.name() == CSSValueScalez)
160                 sz = firstValue.doubleValue();
161             else if (transformValue.name() == CSSValueScaley)
162                 sy = firstValue.doubleValue();
163             else {
164                 sx = firstValue.doubleValue();
165                 if (transformValue.name() != CSSValueScalex) {
166                     if (transformValue.length() > 2) {
167                         auto& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
168                         sz = thirdValue.doubleValue();
169                     }
170                     if (transformValue.length() > 1) {
171                         auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
172                         sy = secondValue.doubleValue();
173                     } else
174                         sy = sx;
175                 }
176             }
177             operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, transformOperationType(transformValue.name())));
178             break;
179         }
180         case CSSValueTranslate:
181         case CSSValueTranslatex:
182         case CSSValueTranslatey: {
183             Length tx = Length(0, Fixed);
184             Length ty = Length(0, Fixed);
185             if (transformValue.name() == CSSValueTranslatey)
186                 ty = convertToFloatLength(&firstValue, conversionData);
187             else {
188                 tx = convertToFloatLength(&firstValue, conversionData);
189                 if (transformValue.name() != CSSValueTranslatex) {
190                     if (transformValue.length() > 1) {
191                         auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
192                         ty = convertToFloatLength(&secondValue, conversionData);
193                     }
194                 }
195             }
196
197             if (tx.isUndefined() || ty.isUndefined())
198                 return false;
199
200             operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), transformOperationType(transformValue.name())));
201             break;
202         }
203         case CSSValueTranslatez:
204         case CSSValueTranslate3d: {
205             Length tx = Length(0, Fixed);
206             Length ty = Length(0, Fixed);
207             Length tz = Length(0, Fixed);
208             if (transformValue.name() == CSSValueTranslatez)
209                 tz = convertToFloatLength(&firstValue, conversionData);
210             else if (transformValue.name() == CSSValueTranslatey)
211                 ty = convertToFloatLength(&firstValue, conversionData);
212             else {
213                 tx = convertToFloatLength(&firstValue, conversionData);
214                 if (transformValue.name() != CSSValueTranslatex) {
215                     if (transformValue.length() > 2) {
216                         auto& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
217                         tz = convertToFloatLength(&thirdValue, conversionData);
218                     }
219                     if (transformValue.length() > 1) {
220                         auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
221                         ty = convertToFloatLength(&secondValue, conversionData);
222                     }
223                 }
224             }
225
226             if (tx.isUndefined() || ty.isUndefined() || tz.isUndefined())
227                 return false;
228
229             operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, transformOperationType(transformValue.name())));
230             break;
231         }
232         case CSSValueRotate: {
233             double angle = firstValue.computeDegrees();
234             operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, transformOperationType(transformValue.name())));
235             break;
236         }
237         case CSSValueRotatex:
238         case CSSValueRotatey:
239         case CSSValueRotatez: {
240             double x = 0;
241             double y = 0;
242             double z = 0;
243             double angle = firstValue.computeDegrees();
244
245             if (transformValue.name() == CSSValueRotatex)
246                 x = 1;
247             else if (transformValue.name() == CSSValueRotatey)
248                 y = 1;
249             else
250                 z = 1;
251             operations.operations().append(RotateTransformOperation::create(x, y, z, angle, transformOperationType(transformValue.name())));
252             break;
253         }
254         case CSSValueRotate3d: {
255             if (transformValue.length() < 4)
256                 break;
257             auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
258             auto& thirdValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2));
259             auto& fourthValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(3));
260             double x = firstValue.doubleValue();
261             double y = secondValue.doubleValue();
262             double z = thirdValue.doubleValue();
263             double angle = fourthValue.computeDegrees();
264             operations.operations().append(RotateTransformOperation::create(x, y, z, angle, transformOperationType(transformValue.name())));
265             break;
266         }
267         case CSSValueSkew:
268         case CSSValueSkewx:
269         case CSSValueSkewy: {
270             double angleX = 0;
271             double angleY = 0;
272             double angle = firstValue.computeDegrees();
273             if (transformValue.name() == CSSValueSkewy)
274                 angleY = angle;
275             else {
276                 angleX = angle;
277                 if (transformValue.name() == CSSValueSkew) {
278                     if (transformValue.length() > 1) {
279                         auto& secondValue = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1));
280                         angleY = secondValue.computeDegrees();
281                     }
282                 }
283             }
284             operations.operations().append(SkewTransformOperation::create(angleX, angleY, transformOperationType(transformValue.name())));
285             break;
286         }
287         case CSSValueMatrix: {
288             if (transformValue.length() < 6)
289                 break;
290             double a = firstValue.doubleValue();
291             double b = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1)).doubleValue();
292             double c = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2)).doubleValue();
293             double d = downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(3)).doubleValue();
294             double e = conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(4)).doubleValue();
295             double f = conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(5)).doubleValue();
296             operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f));
297             break;
298         }
299         case CSSValueMatrix3d: {
300             if (transformValue.length() < 16)
301                 break;
302             TransformationMatrix matrix(downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(0)).doubleValue(),
303                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(1)).doubleValue(),
304                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(2)).doubleValue(),
305                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(3)).doubleValue(),
306                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(4)).doubleValue(),
307                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(5)).doubleValue(),
308                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(6)).doubleValue(),
309                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(7)).doubleValue(),
310                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(8)).doubleValue(),
311                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(9)).doubleValue(),
312                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(10)).doubleValue(),
313                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(11)).doubleValue(),
314                 conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(12)).doubleValue(),
315                 conversionData.zoom() * downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(13)).doubleValue(),
316                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(14)).doubleValue(),
317                 downcast<CSSPrimitiveValue>(*transformValue.itemWithoutBoundsCheck(15)).doubleValue());
318             operations.operations().append(Matrix3DTransformOperation::create(matrix));
319             break;
320         }
321         case CSSValuePerspective: {
322             Length p = Length(0, Fixed);
323             if (firstValue.isLength())
324                 p = convertToFloatLength(&firstValue, conversionData);
325             else {
326                 // This is a quirk that should go away when 3d transforms are finalized.
327                 double val = firstValue.doubleValue();
328                 p = val >= 0 ? Length(clampToPositiveInteger(val), Fixed) : Length(Undefined);
329             }
330
331             if (p.isUndefined())
332                 return false;
333
334             operations.operations().append(PerspectiveTransformOperation::create(p));
335             break;
336         }
337         default:
338             ASSERT_NOT_REACHED();
339             break;
340         }
341     }
342
343     outOperations = operations;
344     return true;
345 }
346
347 }