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 48namespace WebCore { 49 50static 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 79static 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 84bool 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} 330