Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / resolver / TransformBuilder.cpp
1 /*
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.
12  *
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.
17  *
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.
22  *
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.
27  */
28
29 #include "config.h"
30 #include "core/css/resolver/TransformBuilder.h"
31
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"
44
45 namespace blink {
46
47 static Length convertToFloatLength(CSSPrimitiveValue* primitiveValue, const CSSToLengthConversionData& conversionData)
48 {
49     ASSERT(primitiveValue);
50     return primitiveValue->convertToLength<FixedConversion | PercentConversion>(conversionData);
51 }
52
53 static TransformOperation::OperationType getTransformOperationType(CSSTransformValue::TransformOperationType type)
54 {
55     switch (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;
78     }
79     return TransformOperation::None;
80 }
81
82 bool TransformBuilder::createTransformOperations(CSSValue* inValue, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations)
83 {
84     if (!inValue || !inValue->isValueList()) {
85         outOperations.clear();
86         return false;
87     }
88
89     float zoomFactor = conversionData.zoom();
90     TransformOperations operations;
91     for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
92         CSSValue* currValue = i.value();
93
94         if (!currValue->isTransformValue())
95             continue;
96
97         CSSTransformValue* transformValue = toCSSTransformValue(i.value());
98         if (!transformValue->length())
99             continue;
100
101         bool haveNonPrimitiveValue = false;
102         for (unsigned j = 0; j < transformValue->length(); ++j) {
103             if (!transformValue->item(j)->isPrimitiveValue()) {
104                 haveNonPrimitiveValue = true;
105                 break;
106             }
107         }
108         if (haveNonPrimitiveValue)
109             continue;
110
111         CSSPrimitiveValue* firstValue = toCSSPrimitiveValue(transformValue->item(0));
112
113         switch (transformValue->operationType()) {
114         case CSSTransformValue::ScaleTransformOperation:
115         case CSSTransformValue::ScaleXTransformOperation:
116         case CSSTransformValue::ScaleYTransformOperation: {
117             double sx = 1.0;
118             double sy = 1.0;
119             if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation)
120                 sy = firstValue->getDoubleValue();
121             else {
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();
127                     } else
128                         sy = sx;
129                 }
130             }
131             operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType())));
132             break;
133         }
134         case CSSTransformValue::ScaleZTransformOperation:
135         case CSSTransformValue::Scale3DTransformOperation: {
136             double sx = 1.0;
137             double sy = 1.0;
138             double sz = 1.0;
139             if (transformValue->operationType() == CSSTransformValue::ScaleZTransformOperation)
140                 sz = firstValue->getDoubleValue();
141             else if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation)
142                 sy = firstValue->getDoubleValue();
143             else {
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();
149                     }
150                     if (transformValue->length() > 1) {
151                         CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
152                         sy = secondValue->getDoubleValue();
153                     } else
154                         sy = sx;
155                 }
156             }
157             operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType())));
158             break;
159         }
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);
167             else {
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);
173                     }
174                 }
175             }
176
177             operations.operations().append(TranslateTransformOperation::create(tx, ty, 0, getTransformOperationType(transformValue->operationType())));
178             break;
179         }
180         case CSSTransformValue::TranslateZTransformOperation:
181         case CSSTransformValue::Translate3DTransformOperation: {
182             Length tx = Length(0, Fixed);
183             Length ty = Length(0, Fixed);
184             double tz = 0;
185             if (transformValue->operationType() == CSSTransformValue::TranslateZTransformOperation)
186                 tz = firstValue->computeLength<double>(conversionData);
187             else if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation)
188                 ty = convertToFloatLength(firstValue, conversionData);
189             else {
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);
195                     }
196                     if (transformValue->length() > 1) {
197                         CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
198                         ty = convertToFloatLength(secondValue, conversionData);
199                     }
200                 }
201             }
202
203             operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType())));
204             break;
205         }
206         case CSSTransformValue::RotateTransformOperation: {
207             double angle = firstValue->computeDegrees();
208             operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType())));
209             break;
210         }
211         case CSSTransformValue::RotateXTransformOperation:
212         case CSSTransformValue::RotateYTransformOperation:
213         case CSSTransformValue::RotateZTransformOperation: {
214             double x = 0;
215             double y = 0;
216             double z = 0;
217             double angle = firstValue->computeDegrees();
218
219             if (transformValue->operationType() == CSSTransformValue::RotateXTransformOperation)
220                 x = 1;
221             else if (transformValue->operationType() == CSSTransformValue::RotateYTransformOperation)
222                 y = 1;
223             else
224                 z = 1;
225             operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType())));
226             break;
227         }
228         case CSSTransformValue::Rotate3DTransformOperation: {
229             if (transformValue->length() < 4)
230                 break;
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())));
239             break;
240         }
241         case CSSTransformValue::SkewTransformOperation:
242         case CSSTransformValue::SkewXTransformOperation:
243         case CSSTransformValue::SkewYTransformOperation: {
244             double angleX = 0;
245             double angleY = 0;
246             double angle = firstValue->computeDegrees();
247             if (transformValue->operationType() == CSSTransformValue::SkewYTransformOperation)
248                 angleY = angle;
249             else {
250                 angleX = angle;
251                 if (transformValue->operationType() == CSSTransformValue::SkewTransformOperation) {
252                     if (transformValue->length() > 1) {
253                         CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1));
254                         angleY = secondValue->computeDegrees();
255                     }
256                 }
257             }
258             operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType())));
259             break;
260         }
261         case CSSTransformValue::MatrixTransformOperation: {
262             if (transformValue->length() < 6)
263                 break;
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));
271             break;
272         }
273         case CSSTransformValue::Matrix3DTransformOperation: {
274             if (transformValue->length() < 16)
275                 break;
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));
293             break;
294         }
295         case CSSTransformValue::PerspectiveTransformOperation: {
296             double p;
297             if (firstValue->isLength())
298                 p = firstValue->computeLength<double>(conversionData);
299             else {
300                 // This is a quirk that should go away when 3d transforms are finalized.
301                 double val = firstValue->getDoubleValue();
302                 if (val < 0)
303                     return false;
304                 p = clampTo<int>(val, 0);
305             }
306
307             operations.operations().append(PerspectiveTransformOperation::create(p));
308             break;
309         }
310         case CSSTransformValue::UnknownTransformOperation:
311             ASSERT_NOT_REACHED();
312             break;
313         }
314     }
315
316     outOperations = operations;
317     return true;
318 }
319
320 } // namespace blink