1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) 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 (at) webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric (at) 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 WebCore { 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->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { 104 haveNonPrimitiveValue = true; 105 break; 106 } 107 } 108 if (haveNonPrimitiveValue) 109 continue; 110 111 CSSPrimitiveValue* firstValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(2)); 148 sz = thirdValue->getDoubleValue(); 149 } 150 if (transformValue->length() > 1) { 151 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(2)); 194 tz = thirdValue->computeLength<double>(conversionData); 195 } 196 if (transformValue->length() > 1) { 197 CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(1)); 232 CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2)); 233 CSSPrimitiveValue* fourthValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(1))->getDoubleValue(); 266 double c = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(); 267 double d = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(); 268 double e = zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(); 269 double f = zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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->itemWithoutBoundsCheck(0))->getDoubleValue(), 277 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(), 278 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(), 279 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(), 280 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(), 281 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(), 282 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(6))->getDoubleValue(), 283 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(7))->getDoubleValue(), 284 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(8))->getDoubleValue(), 285 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(9))->getDoubleValue(), 286 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(10))->getDoubleValue(), 287 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(11))->getDoubleValue(), 288 zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(12))->getDoubleValue(), 289 zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(13))->getDoubleValue(), 290 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(14))->getDoubleValue(), 291 toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(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 = clampToPositiveInteger(val); 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 WebCore 321