Vector<RefPtr<TransformOperation>> concat(const TransformOperations& a, const TransformOperations& b) { Vector<RefPtr<TransformOperation>> result; result.reserveCapacity(a.size() + b.size()); result.appendVector(a.operations()); result.appendVector(b.operations()); return result; }
void ArgumentCoder<TransformOperations>::encode(ArgumentEncoder& encoder, const TransformOperations& transformOperations) { encoder << static_cast<uint32_t>(transformOperations.size()); for (size_t i = 0; i < transformOperations.size(); ++i) { const TransformOperation* operation = transformOperations.at(i); encoder.encodeEnum(operation->getOperationType()); switch (operation->getOperationType()) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: encoder << static_cast<const ScaleTransformOperation*>(operation)->x(); encoder << static_cast<const ScaleTransformOperation*>(operation)->y(); encoder << static_cast<const ScaleTransformOperation*>(operation)->z(); break; case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: ArgumentCoder<Length>::encode(encoder, static_cast<const TranslateTransformOperation*>(operation)->x()); ArgumentCoder<Length>::encode(encoder, static_cast<const TranslateTransformOperation*>(operation)->y()); ArgumentCoder<Length>::encode(encoder, static_cast<const TranslateTransformOperation*>(operation)->z()); break; case TransformOperation::ROTATE: case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: encoder << static_cast<const RotateTransformOperation*>(operation)->x(); encoder << static_cast<const RotateTransformOperation*>(operation)->y(); encoder << static_cast<const RotateTransformOperation*>(operation)->z(); encoder << static_cast<const RotateTransformOperation*>(operation)->angle(); break; case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: encoder << static_cast<const SkewTransformOperation*>(operation)->angleX(); encoder << static_cast<const SkewTransformOperation*>(operation)->angleY(); break; case TransformOperation::MATRIX: ArgumentCoder<TransformationMatrix>::encode(encoder, static_cast<const MatrixTransformOperation*>(operation)->matrix()); break; case TransformOperation::MATRIX_3D: ArgumentCoder<TransformationMatrix>::encode(encoder, static_cast<const Matrix3DTransformOperation*>(operation)->matrix()); break; case TransformOperation::PERSPECTIVE: ArgumentCoder<Length>::encode(encoder, static_cast<const PerspectiveTransformOperation*>(operation)->perspective()); break; case TransformOperation::IDENTITY: break; case TransformOperation::NONE: ASSERT_NOT_REACHED(); break; } } }
TransformOperations TransformOperations::blend(const TransformOperations& from, double progress, const LayoutSize& size) const { if (from == *this) return *this; if (from.size() && from.operationsMatch(*this)) return blendByMatchingOperations(from, progress); return blendByUsingMatrixInterpolation(from, progress, size); }
bool TransformOperations::operationsMatch(const TransformOperations& other) const { size_t numOperations = operations().size(); // If the sizes of the function lists don't match, the lists don't match if (numOperations != other.operations().size()) return false; // If the types of each function are not the same, the lists don't match for (size_t i = 0; i < numOperations; ++i) { if (!operations()[i]->isSameType(*other.operations()[i])) return false; } return true; }
PassRefPtr<TransformOperation> InterpolatedTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) { if (from && !from->isSameType(*this)) return this; TransformOperations thisOperations; thisOperations.operations().append(this); TransformOperations fromOperations; if (blendToIdentity) fromOperations.operations().append(IdentityTransformOperation::create()); else fromOperations.operations().append(const_cast<TransformOperation*>(from)); return InterpolatedTransformOperation::create(thisOperations, fromOperations, progress); }
TEST(AnimationTranslationUtilTest, transformsWork) { TransformOperations ops; WebTransformOperationsMock outOps; EXPECT_CALL(outOps, appendTranslate(2, 0, 0)); EXPECT_CALL(outOps, appendRotate(0.1, 0.2, 0.3, 200000.4)); EXPECT_CALL(outOps, appendScale(50.2, 100, -4)); ops.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(0, Fixed), TransformOperation::TranslateX)); ops.operations().append(RotateTransformOperation::create(0.1, 0.2, 0.3, 200000.4, TransformOperation::Rotate3D)); ops.operations().append(ScaleTransformOperation::create(50.2, 100, -4, TransformOperation::Scale3D)); toWebTransformOperations(ops, &outOps); }
void PrintTo(const AnimatableTransform& animTransform, ::std::ostream* os) { TransformOperations ops = animTransform.transformOperations(); *os << "AnimatableTransform("; // FIXME: TransformOperations should really have it's own pretty-printer // then we could just call that. // FIXME: Output useful names not just the raw matrixes. for (unsigned i = 0; i < ops.size(); i++) { const TransformOperation* op = ops.at(i); TransformationMatrix matrix; op->apply(matrix, FloatSize(1.0, 1.0)); *os << "["; if (matrix.isAffine()) { *os << matrix.a(); *os << " " << matrix.b(); *os << " " << matrix.c(); *os << " " << matrix.d(); *os << " " << matrix.e(); *os << " " << matrix.f(); } else { *os << matrix.m11(); *os << " " << matrix.m12(); *os << " " << matrix.m13(); *os << " " << matrix.m14(); *os << " "; *os << " " << matrix.m21(); *os << " " << matrix.m22(); *os << " " << matrix.m23(); *os << " " << matrix.m24(); *os << " "; *os << " " << matrix.m31(); *os << " " << matrix.m32(); *os << " " << matrix.m33(); *os << " " << matrix.m34(); *os << " "; *os << " " << matrix.m41(); *os << " " << matrix.m42(); *os << " " << matrix.m43(); *os << " " << matrix.m44(); } *os << "]"; if (i < ops.size() - 1) *os << ", "; } *os << ")"; }
TransformOperations TransformOperations::blendByUsingMatrixInterpolation(const TransformOperations& from, double progress, const LayoutSize& size) const { TransformOperations result; // Convert the TransformOperations into matrices TransformationMatrix fromTransform; TransformationMatrix toTransform; from.apply(size, fromTransform); apply(size, toTransform); toTransform.blend(fromTransform, progress); // Append the result result.operations().append(Matrix3DTransformOperation::create(toTransform)); return result; }
TEST_F(AnimationCompositorAnimationsTest, isNotCandidateForCompositorAnimationTransformDependsOnBoxSize) { TransformOperations ops; ops.operations().append(TranslateTransformOperation::create(Length(2, Fixed), Length(2, Fixed), TransformOperation::TranslateX)); RefPtr<AnimatableValueKeyframe> goodKeyframe = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops).get()); EXPECT_TRUE(duplicateSingleKeyframeAndTestIsCandidateOnResult(goodKeyframe.get())); ops.operations().append(TranslateTransformOperation::create(Length(50, Percent), Length(2, Fixed), TransformOperation::TranslateX)); RefPtr<AnimatableValueKeyframe> badKeyframe = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops).get()); EXPECT_FALSE(duplicateSingleKeyframeAndTestIsCandidateOnResult(badKeyframe.get())); TransformOperations ops2; Length calcLength = Length(100, Percent).blend(Length(100, Fixed), 0.5, ValueRangeAll); ops2.operations().append(TranslateTransformOperation::create(calcLength, Length(0, Fixed), TransformOperation::TranslateX)); RefPtr<AnimatableValueKeyframe> badKeyframe2 = createReplaceOpKeyframe(CSSPropertyTransform, AnimatableTransform::create(ops2).get()); EXPECT_FALSE(duplicateSingleKeyframeAndTestIsCandidateOnResult(badKeyframe2.get())); }
static TransformationMatrix applyTransformAnimation(const TransformOperations& from, const TransformOperations& to, double progress, const FloatSize& boxSize, bool listsMatch) { TransformationMatrix matrix; // First frame of an animation. if (!progress) { from.apply(boxSize, matrix); return matrix; } // Last frame of an animation. if (progress == 1) { to.apply(boxSize, matrix); return matrix; } // If we have incompatible operation lists, we blend the resulting matrices. if (!listsMatch) { TransformationMatrix fromMatrix; to.apply(boxSize, matrix); from.apply(boxSize, fromMatrix); matrix.blend(fromMatrix, progress); return matrix; } // Animation to "-webkit-transform: none". if (!to.size()) { TransformOperations blended(from); for (auto& operation : blended.operations()) operation->blend(nullptr, progress, true)->apply(matrix, boxSize); return matrix; } // Animation from "-webkit-transform: none". if (!from.size()) { TransformOperations blended(to); for (auto& operation : blended.operations()) operation->blend(nullptr, 1 - progress, true)->apply(matrix, boxSize); return matrix; } // Normal animation with a matching operation list. TransformOperations blended(to); for (size_t i = 0; i < blended.operations().size(); ++i) blended.operations()[i]->blend(from.at(i), progress, !from.at(i))->apply(matrix, boxSize); return matrix; }
void WebKitCSSMatrix::setMatrixValue(const String& string, ExceptionCode& ec) { if (string.isEmpty()) return; RefPtr<StylePropertySet> styleDeclaration = StylePropertySet::create(); if (CSSParser::parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true, CSSStrictMode, 0)) { // Convert to TransformOperations. This can fail if a property // requires style (i.e., param uses 'ems' or 'exs') RefPtr<CSSValue> value = styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform); // Check for a "none" or empty transform. In these cases we can use the default identity matrix. if (!value || (value->isPrimitiveValue() && (static_cast<CSSPrimitiveValue*>(value.get()))->getIdent() == CSSValueNone)) return; TransformOperations operations; if (!StyleResolver::createTransformOperations(value.get(), 0, 0, operations)) { ec = SYNTAX_ERR; return; } // Convert transform operations to a TransformationMatrix. This can fail // if a param has a percentage ('%') TransformationMatrix t; for (unsigned i = 0; i < operations.operations().size(); ++i) { if (operations.operations()[i].get()->apply(t, IntSize(0, 0))) { ec = SYNTAX_ERR; return; } } // set the matrix m_matrix = t; } else // There is something there but parsing failed. ec = SYNTAX_ERR; }
void CSSMatrix::setMatrixValue(const String& string, ExceptionState& exceptionState) { if (string.isEmpty()) return; // FIXME: crbug.com/154722 - should this continue to use legacy style parsing? RefPtrWillBeRawPtr<MutableStylePropertySet> styleDeclaration = MutableStylePropertySet::create(); if (BisonCSSParser::parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true, HTMLStandardMode, 0)) { // Convert to TransformOperations. This can fail if a property // requires style (i.e., param uses 'ems' or 'exs') RefPtrWillBeRawPtr<CSSValue> value = styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform); // Check for a "none" or empty transform. In these cases we can use the default identity matrix. if (!value || (value->isPrimitiveValue() && (toCSSPrimitiveValue(value.get()))->getValueID() == CSSValueNone)) return; DEFINE_STATIC_REF(RenderStyle, defaultStyle, RenderStyle::createDefaultStyle()); TransformOperations operations; if (!TransformBuilder::createTransformOperations(value.get(), CSSToLengthConversionData(defaultStyle, defaultStyle, 0, 0, 1.0f), operations)) { exceptionState.throwDOMException(SyntaxError, "Failed to interpret '" + string + "' as a transformation operation."); return; } // Convert transform operations to a TransformationMatrix. This can fail // if a param has a percentage ('%') if (operations.dependsOnBoxSize()) exceptionState.throwDOMException(SyntaxError, "The transformation depends on the box size, which is not supported."); TransformationMatrix t; operations.apply(FloatSize(0, 0), t); // set the matrix m_matrix = t; } else { // There is something there but parsing failed. exceptionState.throwDOMException(SyntaxError, "Failed to parse '" + string + "'."); } }
void CSSMatrix::setMatrixValue(const String& string, ExceptionState& exceptionState) { if (string.isEmpty()) return; if (RefPtrWillBeRawPtr<CSSValue> value = CSSParser::parseSingleValue(CSSPropertyTransform, string)) { // Check for a "none" transform. In these cases we can use the default identity matrix. if (value->isPrimitiveValue() && (toCSSPrimitiveValue(value.get()))->getValueID() == CSSValueNone) return; DEFINE_STATIC_REF(ComputedStyle, initialStyle, createInitialStyle()); TransformOperations operations; TransformBuilder::createTransformOperations(*value, CSSToLengthConversionData(initialStyle, initialStyle, nullptr, 1.0f), operations); // Convert transform operations to a TransformationMatrix. This can fail // if a param has a percentage ('%') if (operations.dependsOnBoxSize()) exceptionState.throwDOMException(SyntaxError, "The transformation depends on the box size, which is not supported."); m_matrix = adoptPtr(new TransformationMatrix); operations.apply(FloatSize(0, 0), *m_matrix); } else { // There is something there but parsing failed. exceptionState.throwDOMException(SyntaxError, "Failed to parse '" + string + "'."); } }
PassRefPtr<CSSTransformNonInterpolableValue> composite( const CSSTransformNonInterpolableValue& other, double otherProgress) { DCHECK(!isAdditive()); if (other.m_isSingle) { DCHECK_EQ(otherProgress, 0); DCHECK(other.isAdditive()); TransformOperations result; result.operations() = concat(transform(), other.transform()); return create(std::move(result)); } DCHECK(other.m_isStartAdditive || other.m_isEndAdditive); TransformOperations start; start.operations() = other.m_isStartAdditive ? concat(transform(), other.m_start) : other.m_start.operations(); TransformOperations end; end.operations() = other.m_isEndAdditive ? concat(transform(), other.m_end) : other.m_end.operations(); return create(end.blend(start, otherProgress)); }
TransformOperations TransformOperations::blendByMatchingOperations(const TransformOperations& from, const double& progress) const { TransformOperations result; unsigned fromSize = from.operations().size(); unsigned toSize = operations().size(); unsigned size = max(fromSize, toSize); for (unsigned i = 0; i < size; i++) { RefPtr<TransformOperation> fromOperation = (i < fromSize) ? from.operations()[i].get() : 0; RefPtr<TransformOperation> toOperation = (i < toSize) ? operations()[i].get() : 0; RefPtr<TransformOperation> blendedOperation = toOperation ? toOperation->blend(fromOperation.get(), progress) : (fromOperation ? fromOperation->blend(0, progress, true) : 0); if (blendedOperation) result.operations().append(blendedOperation); else { RefPtr<TransformOperation> identityOperation = IdentityTransformOperation::create(); if (progress > 0.5) result.operations().append(toOperation ? toOperation : identityOperation); else result.operations().append(fromOperation ? fromOperation : identityOperation); } } return result; }
bool ArgumentCoder<TransformOperations>::decode(ArgumentDecoder* decoder, TransformOperations& transformOperations) { uint32_t operationsSize; if (!decoder->decodeUInt32(operationsSize)) return false; for (size_t i = 0; i < operationsSize; ++i) { TransformOperation::OperationType operationType; if (!decoder->decodeEnum(operationType)) return false; switch (operationType) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: { double x, y, z; if (!decoder->decode(x)) return false; if (!decoder->decode(y)) return false; if (!decoder->decode(z)) return false; transformOperations.operations().append(ScaleTransformOperation::create(x, y, z, operationType)); break; } case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: { Length x, y, z; if (!ArgumentCoder<Length>::decode(decoder, x)) return false; if (!ArgumentCoder<Length>::decode(decoder, y)) return false; if (!ArgumentCoder<Length>::decode(decoder, z)) return false; transformOperations.operations().append(TranslateTransformOperation::create(x, y, z, operationType)); break; } case TransformOperation::ROTATE: case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: { double x, y, z, angle; if (!decoder->decode(x)) return false; if (!decoder->decode(y)) return false; if (!decoder->decode(z)) return false; if (!decoder->decode(angle)) return false; transformOperations.operations().append(RotateTransformOperation::create(x, y, z, angle, operationType)); break; } case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: { double angleX, angleY; if (!decoder->decode(angleX)) return false; if (!decoder->decode(angleY)) return false; transformOperations.operations().append(SkewTransformOperation::create(angleX, angleY, operationType)); break; } case TransformOperation::MATRIX: { TransformationMatrix matrix; if (!ArgumentCoder<TransformationMatrix>::decode(decoder, matrix)) return false; transformOperations.operations().append(MatrixTransformOperation::create(matrix)); break; } case TransformOperation::MATRIX_3D: { TransformationMatrix matrix; if (!ArgumentCoder<TransformationMatrix>::decode(decoder, matrix)) return false; transformOperations.operations().append(Matrix3DTransformOperation::create(matrix)); break; } case TransformOperation::PERSPECTIVE: { Length perspective; if (!ArgumentCoder<Length>::decode(decoder, perspective)) return false; transformOperations.operations().append(PerspectiveTransformOperation::create(perspective)); break; } case TransformOperation::IDENTITY: transformOperations.operations().append(IdentityTransformOperation::create()); break; case TransformOperation::NONE: ASSERT_NOT_REACHED(); break; } } return true; }
bool TransformBuilder::createTransformOperations(CSSValue* inValue, const CSSToLengthConversionData& conversionData, TransformOperations& outOperations) { if (!inValue || !inValue->isValueList()) { outOperations.clear(); return false; } TransformOperations operations; for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { CSSValue* currValue = i.value(); if (!currValue->isTransformValue()) continue; CSSTransformValue* transformValue = toCSSTransformValue(i.value()); if (!transformValue->length()) continue; bool haveNonPrimitiveValue = false; for (unsigned j = 0; j < transformValue->length(); ++j) { if (!transformValue->item(j)->isPrimitiveValue()) { haveNonPrimitiveValue = true; break; } } if (haveNonPrimitiveValue) continue; CSSPrimitiveValue* firstValue = toCSSPrimitiveValue(transformValue->item(0)); switch (transformValue->operationType()) { case CSSTransformValue::ScaleTransformOperation: case CSSTransformValue::ScaleXTransformOperation: case CSSTransformValue::ScaleYTransformOperation: { double sx = 1.0; double sy = 1.0; if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation) sy = firstValue->getDoubleValue(); else { sx = firstValue->getDoubleValue(); if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); sy = secondValue->getDoubleValue(); } else sy = sx; } } operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::ScaleZTransformOperation: case CSSTransformValue::Scale3DTransformOperation: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transformValue->operationType() == CSSTransformValue::ScaleZTransformOperation) sz = firstValue->getDoubleValue(); else if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation) sy = firstValue->getDoubleValue(); else { sx = firstValue->getDoubleValue(); if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) { if (transformValue->length() > 2) { CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2)); sz = thirdValue->getDoubleValue(); } if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); sy = secondValue->getDoubleValue(); } else sy = sx; } } operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::TranslateTransformOperation: case CSSTransformValue::TranslateXTransformOperation: case CSSTransformValue::TranslateYTransformOperation: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation) ty = convertToFloatLength(firstValue, conversionData); else { tx = convertToFloatLength(firstValue, conversionData); if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); ty = convertToFloatLength(secondValue, conversionData); } } } operations.operations().append(TranslateTransformOperation::create(tx, ty, 0, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::TranslateZTransformOperation: case CSSTransformValue::Translate3DTransformOperation: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); double tz = 0; if (transformValue->operationType() == CSSTransformValue::TranslateZTransformOperation) tz = firstValue->computeLength<double>(conversionData); else if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation) ty = convertToFloatLength(firstValue, conversionData); else { tx = convertToFloatLength(firstValue, conversionData); if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) { if (transformValue->length() > 2) { CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2)); tz = thirdValue->computeLength<double>(conversionData); } if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); ty = convertToFloatLength(secondValue, conversionData); } } } operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::RotateTransformOperation: { double angle = firstValue->computeDegrees(); operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::RotateXTransformOperation: case CSSTransformValue::RotateYTransformOperation: case CSSTransformValue::RotateZTransformOperation: { double x = 0; double y = 0; double z = 0; double angle = firstValue->computeDegrees(); if (transformValue->operationType() == CSSTransformValue::RotateXTransformOperation) x = 1; else if (transformValue->operationType() == CSSTransformValue::RotateYTransformOperation) y = 1; else z = 1; operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::Rotate3DTransformOperation: { if (transformValue->length() < 4) break; CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->item(2)); CSSPrimitiveValue* fourthValue = toCSSPrimitiveValue(transformValue->item(3)); double x = firstValue->getDoubleValue(); double y = secondValue->getDoubleValue(); double z = thirdValue->getDoubleValue(); double angle = fourthValue->computeDegrees(); operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::SkewTransformOperation: case CSSTransformValue::SkewXTransformOperation: case CSSTransformValue::SkewYTransformOperation: { double angleX = 0; double angleY = 0; double angle = firstValue->computeDegrees(); if (transformValue->operationType() == CSSTransformValue::SkewYTransformOperation) angleY = angle; else { angleX = angle; if (transformValue->operationType() == CSSTransformValue::SkewTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->item(1)); angleY = secondValue->computeDegrees(); } } } operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::MatrixTransformOperation: { if (transformValue->length() < 6) break; double a = firstValue->getDoubleValue(); double b = toCSSPrimitiveValue(transformValue->item(1))->getDoubleValue(); double c = toCSSPrimitiveValue(transformValue->item(2))->getDoubleValue(); double d = toCSSPrimitiveValue(transformValue->item(3))->getDoubleValue(); double e = toCSSPrimitiveValue(transformValue->item(4))->getDoubleValue(); double f = toCSSPrimitiveValue(transformValue->item(5))->getDoubleValue(); operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f)); break; } case CSSTransformValue::Matrix3DTransformOperation: { if (transformValue->length() < 16) break; TransformationMatrix matrix(toCSSPrimitiveValue(transformValue->item(0))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(1))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(2))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(3))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(4))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(5))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(6))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(7))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(8))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(9))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(10))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(11))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(12))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(13))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(14))->getDoubleValue(), toCSSPrimitiveValue(transformValue->item(15))->getDoubleValue()); operations.operations().append(Matrix3DTransformOperation::create(matrix)); break; } case CSSTransformValue::PerspectiveTransformOperation: { double p; if (firstValue->isLength()) p = firstValue->computeLength<double>(conversionData); else { // This is a quirk that should go away when 3d transforms are finalized. double val = firstValue->getDoubleValue(); if (val < 0) return false; p = clampToPositiveInteger(val); } operations.operations().append(PerspectiveTransformOperation::create(p)); break; } case CSSTransformValue::UnknownTransformOperation: ASSERT_NOT_REACHED(); break; } } outOperations = operations; return true; }
WebTransformOperations toWebTransformOperations(const TransformOperations& transformOperations, const FloatSize& boxSize) { // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects. WebTransformOperations webTransformOperations; for (size_t j = 0; j < transformOperations.size(); ++j) { TransformOperation::OperationType operationType = transformOperations.operations()[j]->getOperationType(); switch (operationType) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: case TransformOperation::SCALE: { ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations.appendScale(transform->x(), transform->y(), transform->z()); break; } case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: case TransformOperation::TRANSLATE: { TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations.appendTranslate(floatValueForLength(transform->x(), boxSize.width()), floatValueForLength(transform->y(), boxSize.height()), floatValueForLength(transform->z(), 1)); break; } case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: case TransformOperation::ROTATE: { RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations.appendRotate(transform->x(), transform->y(), transform->z(), transform->angle()); break; } case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: { SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations.appendSkew(transform->angleX(), transform->angleY()); break; } case TransformOperation::MATRIX: { MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations.appendMatrix(WebTransformationMatrix(m)); break; } case TransformOperation::MATRIX_3D: { Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations.appendMatrix(WebTransformationMatrix(m)); break; } case TransformOperation::PERSPECTIVE: { PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations.appendPerspective(floatValueForLength(transform->perspective(), 0)); break; } case TransformOperation::IDENTITY: case TransformOperation::NONE: // Do nothing. break; } // switch } // for each operation return webTransformOperations; }
static PassRefPtr<AnimatableValue> createFromTransformProperties(PassRefPtr<TransformOperation> transform, double zoom, PassRefPtr<TransformOperation> initialTransform) { TransformOperations operation; operation.operations().append(transform ? transform : initialTransform); return AnimatableTransform::create(operation, transform ? zoom : 1); }
TransformOperations TransformBuilder::createTransformOperations( const CSSValue& inValue, const CSSToLengthConversionData& conversionData) { TransformOperations operations; if (!inValue.isValueList()) { DCHECK_EQ(toCSSIdentifierValue(inValue).getValueID(), CSSValueNone); return operations; } float zoomFactor = conversionData.zoom(); for (auto& value : toCSSValueList(inValue)) { const CSSFunctionValue* transformValue = toCSSFunctionValue(value.get()); TransformOperation::OperationType transformType = getTransformOperationType(transformValue->functionType()); const CSSPrimitiveValue& firstValue = toCSSPrimitiveValue(transformValue->item(0)); switch (transformType) { case TransformOperation::Scale: case TransformOperation::ScaleX: case TransformOperation::ScaleY: { double sx = 1.0; double sy = 1.0; if (transformType == TransformOperation::ScaleY) { sy = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); if (transformType != TransformOperation::ScaleX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); sy = secondValue.getDoubleValue(); } else { sy = sx; } } } operations.operations().append( ScaleTransformOperation::create(sx, sy, 1.0, transformType)); break; } case TransformOperation::ScaleZ: case TransformOperation::Scale3D: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transformType == TransformOperation::ScaleZ) { sz = firstValue.getDoubleValue(); } else { sx = firstValue.getDoubleValue(); sy = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); sz = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); } operations.operations().append( ScaleTransformOperation::create(sx, sy, sz, transformType)); break; } case TransformOperation::Translate: case TransformOperation::TranslateX: case TransformOperation::TranslateY: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); if (transformType == TransformOperation::TranslateY) ty = convertToFloatLength(firstValue, conversionData); else { tx = convertToFloatLength(firstValue, conversionData); if (transformType != TransformOperation::TranslateX) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); ty = convertToFloatLength(secondValue, conversionData); } } } operations.operations().append( TranslateTransformOperation::create(tx, ty, 0, transformType)); break; } case TransformOperation::TranslateZ: case TransformOperation::Translate3D: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); double tz = 0; if (transformType == TransformOperation::TranslateZ) { tz = firstValue.computeLength<double>(conversionData); } else { tx = convertToFloatLength(firstValue, conversionData); ty = convertToFloatLength( toCSSPrimitiveValue(transformValue->item(1)), conversionData); tz = toCSSPrimitiveValue(transformValue->item(2)) .computeLength<double>(conversionData); } operations.operations().append( TranslateTransformOperation::create(tx, ty, tz, transformType)); break; } case TransformOperation::RotateX: case TransformOperation::RotateY: case TransformOperation::RotateZ: { double angle = firstValue.computeDegrees(); if (transformValue->length() == 1) { double x = transformType == TransformOperation::RotateX; double y = transformType == TransformOperation::RotateY; double z = transformType == TransformOperation::RotateZ; operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); } else { // For SVG 'transform' attributes we generate 3-argument rotate() // functions. DCHECK_EQ(transformValue->length(), 3u); const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); operations.operations().append( RotateAroundOriginTransformOperation::create( angle, secondValue.computeLength<double>(conversionData), thirdValue.computeLength<double>(conversionData))); } break; } case TransformOperation::Rotate3D: { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); const CSSPrimitiveValue& thirdValue = toCSSPrimitiveValue(transformValue->item(2)); const CSSPrimitiveValue& fourthValue = toCSSPrimitiveValue(transformValue->item(3)); double x = firstValue.getDoubleValue(); double y = secondValue.getDoubleValue(); double z = thirdValue.getDoubleValue(); double angle = fourthValue.computeDegrees(); operations.operations().append( RotateTransformOperation::create(x, y, z, angle, transformType)); break; } case TransformOperation::Skew: case TransformOperation::SkewX: case TransformOperation::SkewY: { double angleX = 0; double angleY = 0; double angle = firstValue.computeDegrees(); if (transformType == TransformOperation::SkewY) angleY = angle; else { angleX = angle; if (transformType == TransformOperation::Skew) { if (transformValue->length() > 1) { const CSSPrimitiveValue& secondValue = toCSSPrimitiveValue(transformValue->item(1)); angleY = secondValue.computeDegrees(); } } } operations.operations().append( SkewTransformOperation::create(angleX, angleY, transformType)); break; } case TransformOperation::Matrix: { double a = firstValue.getDoubleValue(); double b = toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(); double c = toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(); double d = toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(); double e = zoomFactor * toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(); double f = zoomFactor * toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(); operations.operations().append( MatrixTransformOperation::create(a, b, c, d, e, f)); break; } case TransformOperation::Matrix3D: { TransformationMatrix matrix( toCSSPrimitiveValue(transformValue->item(0)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(1)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(2)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(3)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(4)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(5)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(6)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(7)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(8)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(9)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(10)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(11)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(12)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(13)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(14)).getDoubleValue(), toCSSPrimitiveValue(transformValue->item(15)).getDoubleValue()); matrix.zoom(zoomFactor); operations.operations().append( Matrix3DTransformOperation::create(matrix)); break; } case TransformOperation::Perspective: { double p = firstValue.computeLength<double>(conversionData); ASSERT(p >= 0); operations.operations().append( PerspectiveTransformOperation::create(p)); break; } default: ASSERT_NOT_REACHED(); break; } } return operations; }
bool TransformBuilder::createTransformOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, TransformOperations& outOperations) { if (!inValue || !inValue->isValueList()) { outOperations.clear(); return false; } float zoomFactor = style ? style->effectiveZoom() : 1; TransformOperations operations; for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) { CSSValue* currValue = i.value(); if (!currValue->isCSSTransformValue()) continue; CSSTransformValue* transformValue = static_cast<CSSTransformValue*>(i.value()); if (!transformValue->length()) continue; bool haveNonPrimitiveValue = false; for (unsigned j = 0; j < transformValue->length(); ++j) { if (!transformValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) { haveNonPrimitiveValue = true; break; } } if (haveNonPrimitiveValue) continue; CSSPrimitiveValue* firstValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(0)); switch (transformValue->operationType()) { case CSSTransformValue::ScaleTransformOperation: case CSSTransformValue::ScaleXTransformOperation: case CSSTransformValue::ScaleYTransformOperation: { double sx = 1.0; double sy = 1.0; if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation) sy = firstValue->getDoubleValue(); else { sx = firstValue->getDoubleValue(); if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); sy = secondValue->getDoubleValue(); } else sy = sx; } } operations.operations().append(ScaleTransformOperation::create(sx, sy, 1.0, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::ScaleZTransformOperation: case CSSTransformValue::Scale3DTransformOperation: { double sx = 1.0; double sy = 1.0; double sz = 1.0; if (transformValue->operationType() == CSSTransformValue::ScaleZTransformOperation) sz = firstValue->getDoubleValue(); else if (transformValue->operationType() == CSSTransformValue::ScaleYTransformOperation) sy = firstValue->getDoubleValue(); else { sx = firstValue->getDoubleValue(); if (transformValue->operationType() != CSSTransformValue::ScaleXTransformOperation) { if (transformValue->length() > 2) { CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2)); sz = thirdValue->getDoubleValue(); } if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); sy = secondValue->getDoubleValue(); } else sy = sx; } } operations.operations().append(ScaleTransformOperation::create(sx, sy, sz, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::TranslateTransformOperation: case CSSTransformValue::TranslateXTransformOperation: case CSSTransformValue::TranslateYTransformOperation: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation) ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); else { tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor); } } } if (tx.isUndefined() || ty.isUndefined()) return false; operations.operations().append(TranslateTransformOperation::create(tx, ty, Length(0, Fixed), getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::TranslateZTransformOperation: case CSSTransformValue::Translate3DTransformOperation: { Length tx = Length(0, Fixed); Length ty = Length(0, Fixed); Length tz = Length(0, Fixed); if (transformValue->operationType() == CSSTransformValue::TranslateZTransformOperation) tz = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); else if (transformValue->operationType() == CSSTransformValue::TranslateYTransformOperation) ty = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); else { tx = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); if (transformValue->operationType() != CSSTransformValue::TranslateXTransformOperation) { if (transformValue->length() > 2) { CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2)); tz = convertToFloatLength(thirdValue, style, rootStyle, zoomFactor); } if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); ty = convertToFloatLength(secondValue, style, rootStyle, zoomFactor); } } } if (tx.isUndefined() || ty.isUndefined() || tz.isUndefined()) return false; operations.operations().append(TranslateTransformOperation::create(tx, ty, tz, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::RotateTransformOperation: { double angle = firstValue->computeDegrees(); operations.operations().append(RotateTransformOperation::create(0, 0, 1, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::RotateXTransformOperation: case CSSTransformValue::RotateYTransformOperation: case CSSTransformValue::RotateZTransformOperation: { double x = 0; double y = 0; double z = 0; double angle = firstValue->computeDegrees(); if (transformValue->operationType() == CSSTransformValue::RotateXTransformOperation) x = 1; else if (transformValue->operationType() == CSSTransformValue::RotateYTransformOperation) y = 1; else z = 1; operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::Rotate3DTransformOperation: { if (transformValue->length() < 4) break; CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); CSSPrimitiveValue* thirdValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2)); CSSPrimitiveValue* fourthValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(3)); double x = firstValue->getDoubleValue(); double y = secondValue->getDoubleValue(); double z = thirdValue->getDoubleValue(); double angle = fourthValue->computeDegrees(); operations.operations().append(RotateTransformOperation::create(x, y, z, angle, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::SkewTransformOperation: case CSSTransformValue::SkewXTransformOperation: case CSSTransformValue::SkewYTransformOperation: { double angleX = 0; double angleY = 0; double angle = firstValue->computeDegrees(); if (transformValue->operationType() == CSSTransformValue::SkewYTransformOperation) angleY = angle; else { angleX = angle; if (transformValue->operationType() == CSSTransformValue::SkewTransformOperation) { if (transformValue->length() > 1) { CSSPrimitiveValue* secondValue = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1)); angleY = secondValue->computeDegrees(); } } } operations.operations().append(SkewTransformOperation::create(angleX, angleY, getTransformOperationType(transformValue->operationType()))); break; } case CSSTransformValue::MatrixTransformOperation: { if (transformValue->length() < 6) break; double a = firstValue->getDoubleValue(); double b = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(); double c = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(); double d = toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(); double e = zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(); double f = zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(); operations.operations().append(MatrixTransformOperation::create(a, b, c, d, e, f)); break; } case CSSTransformValue::Matrix3DTransformOperation: { if (transformValue->length() < 16) break; TransformationMatrix matrix(toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(0))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(1))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(2))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(3))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(4))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(5))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(6))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(7))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(8))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(9))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(10))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(11))->getDoubleValue(), zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(12))->getDoubleValue(), zoomFactor * toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(13))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(14))->getDoubleValue(), toCSSPrimitiveValue(transformValue->itemWithoutBoundsCheck(15))->getDoubleValue()); operations.operations().append(Matrix3DTransformOperation::create(matrix)); break; } case CSSTransformValue::PerspectiveTransformOperation: { Length p = Length(0, Fixed); if (firstValue->isLength()) p = convertToFloatLength(firstValue, style, rootStyle, zoomFactor); else { // This is a quirk that should go away when 3d transforms are finalized. double val = firstValue->getDoubleValue(); p = val >= 0 ? Length(clampToPositiveInteger(val), Fixed) : Length(Undefined); } if (p.isUndefined()) return false; operations.operations().append(PerspectiveTransformOperation::create(p)); break; } case CSSTransformValue::UnknownTransformOperation: ASSERT_NOT_REACHED(); break; } } outOperations = operations; return true; }
void ArgumentCoder<TransformOperations>::encode(ArgumentEncoder& encoder, const TransformOperations& transformOperations) { encoder << static_cast<uint32_t>(transformOperations.size()); for (const auto& operation : transformOperations.operations()) { encoder.encodeEnum(operation->type()); switch (operation->type()) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: { const auto& scaleOperation = downcast<ScaleTransformOperation>(*operation); encoder << scaleOperation.x(); encoder << scaleOperation.y(); encoder << scaleOperation.z(); break; } case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: { const auto& translateOperation = downcast<TranslateTransformOperation>(*operation); ArgumentCoder<Length>::encode(encoder, translateOperation.x()); ArgumentCoder<Length>::encode(encoder, translateOperation.y()); ArgumentCoder<Length>::encode(encoder, translateOperation.z()); break; } case TransformOperation::ROTATE: case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: { const auto& rotateOperation = downcast<RotateTransformOperation>(*operation); encoder << rotateOperation.x(); encoder << rotateOperation.y(); encoder << rotateOperation.z(); encoder << rotateOperation.angle(); break; } case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: { const auto& skewOperation = downcast<SkewTransformOperation>(*operation); encoder << skewOperation.angleX(); encoder << skewOperation.angleY(); break; } case TransformOperation::MATRIX: ArgumentCoder<TransformationMatrix>::encode(encoder, downcast<MatrixTransformOperation>(*operation).matrix()); break; case TransformOperation::MATRIX_3D: ArgumentCoder<TransformationMatrix>::encode(encoder, downcast<Matrix3DTransformOperation>(*operation).matrix()); break; case TransformOperation::PERSPECTIVE: ArgumentCoder<Length>::encode(encoder, downcast<PerspectiveTransformOperation>(*operation).perspective()); break; case TransformOperation::IDENTITY: break; case TransformOperation::NONE: ASSERT_NOT_REACHED(); break; } } }
// FIXME: It's cleaner to only call updateFromElement when an attribute has changed. The body of // this method should probably be moved to a private stretchHeightChanged or checkStretchHeight // method. Probably at the same time, addChild/removeChild methods should be made to work for // dynamic DOM changes. void RenderMathMLOperator::updateFromElement() { RenderObject* savedRenderer = node()->renderer(); // Destroy our current children children()->destroyLeftoverChildren(); // Since we share a node with our children, destroying our children may set our node's // renderer to 0, so we need to restore it. node()->setRenderer(savedRenderer); int index = stretchyCharacterIndex(); bool isStretchy = index >= 0; // We only stack glyphs if the stretch height is larger than a minimum size. bool shouldStack = isStretchy && m_stretchHeight > style()->fontSize(); struct StretchyCharacter* partsData = 0; float topGlyphHeight = 0; float extensionGlyphHeight = 0; float bottomGlyphHeight = 0; float middleGlyphHeight = 0; if (isStretchy) { partsData = &stretchyCharacters[index]; FontCachePurgePreventer fontCachePurgePreventer; topGlyphHeight = glyphHeightForCharacter(partsData->topGlyph); extensionGlyphHeight = glyphHeightForCharacter(partsData->extensionGlyph) - 1; bottomGlyphHeight = glyphHeightForCharacter(partsData->bottomGlyph); if (partsData->middleGlyph) middleGlyphHeight = glyphHeightForCharacter(partsData->middleGlyph) - 1; shouldStack = m_stretchHeight >= topGlyphHeight + middleGlyphHeight + bottomGlyphHeight && extensionGlyphHeight > 0; } bool stretchDisabled = stretchDisabledByMarkup(); // Either stretch is disabled or we don't have a stretchable character over the minimum height if (stretchDisabled || !shouldStack) { RenderBlock* container = new (renderArena()) RenderMathMLBlock(toElement(node())); toRenderMathMLBlock(container)->setIgnoreInAccessibilityTree(true); RefPtr<RenderStyle> newStyle = RenderStyle::create(); newStyle->inheritFrom(style()); newStyle->setDisplay(FLEX); newStyle->setJustifyContent(JustifyCenter); UChar firstCharacter = firstTextCharacter(); m_isStretched = firstCharacter && isStretchy && m_stretchHeight > style()->fontMetrics().floatHeight(); if (m_isStretched) newStyle->setHeight(Length(m_stretchHeight, Fixed)); container->setStyle(newStyle.release()); addChild(container); if (m_isStretched) { float scaleY = m_stretchHeight / glyphHeightForCharacter(firstCharacter); TransformOperations transform; transform.operations().append(ScaleTransformOperation::create(1.0, scaleY, ScaleTransformOperation::SCALE_X)); RefPtr<RenderStyle> innerStyle = RenderStyle::create(); innerStyle->inheritFrom(style()); innerStyle->setTransform(transform); innerStyle->setTransformOriginY(Length(0, Fixed)); RenderBlock* innerContainer = new (renderArena()) RenderMathMLBlock(toElement(node())); toRenderMathMLBlock(innerContainer)->setIgnoreInAccessibilityTree(true); innerContainer->setStyle(innerStyle); container->addChild(innerContainer); container = innerContainer; } // Build the text of the operator. RenderText* text = 0; if (m_operator) text = new (renderArena()) RenderText(node(), StringImpl::create(&m_operator, 1)); else if (node()->isElementNode()) if (Element* mo = static_cast<Element*>(node())) text = new (renderArena()) RenderText(node(), mo->textContent().replace(hyphenMinus, minusSign).impl()); // If we can't figure out the text, leave it blank. if (text) { RefPtr<RenderStyle> textStyle = RenderStyle::create(); textStyle->inheritFrom(container->style()); text->setStyle(textStyle.release()); container->addChild(text); } } else { // Build stretchable characters as a stack of glyphs. m_isStretched = true; // To avoid gaps, we position glyphs after the top glyph upward by 1px. We also truncate // glyph heights to ints, and then reduce all but the top & bottom such heights by 1px. int remaining = m_stretchHeight - topGlyphHeight - bottomGlyphHeight; createGlyph(partsData->topGlyph, topGlyphHeight, 0); if (partsData->middleGlyph) { // We have a middle glyph (e.g. a curly bracket) that requires special processing. remaining -= middleGlyphHeight; int half = (remaining + 1) / 2; remaining -= half; while (remaining > 0) { int height = std::min<int>(remaining, extensionGlyphHeight); createGlyph(partsData->extensionGlyph, height, -1); remaining -= height; } // The middle glyph in the stack. createGlyph(partsData->middleGlyph, middleGlyphHeight, -1); remaining = half; while (remaining > 0) { int height = std::min<int>(remaining, extensionGlyphHeight); createGlyph(partsData->extensionGlyph, height, -1); remaining -= height; } } else { // We do not have a middle glyph and so we just extend from the top to the bottom glyph. while (remaining > 0) { int height = std::min<int>(remaining, extensionGlyphHeight); createGlyph(partsData->extensionGlyph, height, -1); remaining -= height; } } createGlyph(partsData->bottomGlyph, bottomGlyphHeight, -1); } setNeedsLayoutAndPrefWidthsRecalc(); }
PassOwnPtr<CCTransformKeyframe> CCTransformKeyframe::clone() const { // We need to do a deep copy the m_value may contain ref pointers to TransformOperation objects. TransformOperations operations; for (size_t j = 0; j < m_value.size(); ++j) { TransformOperation::OperationType operationType = m_value.operations()[j]->getOperationType(); switch (operationType) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: case TransformOperation::SCALE: { ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(ScaleTransformOperation::create(transform->x(), transform->y(), transform->z(), operationType)); break; } case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: case TransformOperation::TRANSLATE: { TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(TranslateTransformOperation::create(transform->x(), transform->y(), transform->z(), operationType)); break; } case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: case TransformOperation::ROTATE: { RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(RotateTransformOperation::create(transform->x(), transform->y(), transform->z(), transform->angle(), operationType)); break; } case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: { SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(SkewTransformOperation::create(transform->angleX(), transform->angleY(), operationType)); break; } case TransformOperation::MATRIX: { MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(m_value.operations()[j].get()); TransformationMatrix m = transform->matrix(); operations.operations().append(MatrixTransformOperation::create(m.a(), m.b(), m.c(), m.d(), m.e(), m.f())); break; } case TransformOperation::MATRIX_3D: { Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(Matrix3DTransformOperation::create(transform->matrix())); break; } case TransformOperation::PERSPECTIVE: { PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(m_value.operations()[j].get()); operations.operations().append(PerspectiveTransformOperation::create(transform->perspective())); break; } case TransformOperation::IDENTITY: { operations.operations().append(IdentityTransformOperation::create()); break; } case TransformOperation::NONE: // Do nothing. break; } // switch } // for each operation return CCTransformKeyframe::create(time(), operations, timingFunction() ? cloneTimingFunction(timingFunction()) : nullptr); }
void toWebTransformOperations(const TransformOperations& transformOperations, WebTransformOperations* webTransformOperations) { // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects. for (size_t j = 0; j < transformOperations.size(); ++j) { switch (transformOperations.operations()[j]->type()) { case TransformOperation::ScaleX: case TransformOperation::ScaleY: case TransformOperation::ScaleZ: case TransformOperation::Scale3D: case TransformOperation::Scale: { ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendScale(transform->x(), transform->y(), transform->z()); break; } case TransformOperation::TranslateX: case TransformOperation::TranslateY: case TransformOperation::TranslateZ: case TransformOperation::Translate3D: case TransformOperation::Translate: { TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get()); ASSERT(transform->x().isFixed() && transform->y().isFixed()); webTransformOperations->appendTranslate(transform->x().value(), transform->y().value(), transform->z()); break; } case TransformOperation::RotateX: case TransformOperation::RotateY: case TransformOperation::Rotate3D: case TransformOperation::Rotate: { RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendRotate(transform->x(), transform->y(), transform->z(), transform->angle()); break; } case TransformOperation::SkewX: case TransformOperation::SkewY: case TransformOperation::Skew: { SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendSkew(transform->angleX(), transform->angleY()); break; } case TransformOperation::Matrix: { MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Matrix3D: { Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Perspective: { PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendPerspective(transform->perspective()); break; } case TransformOperation::Interpolated: { TransformationMatrix m; transformOperations.operations()[j]->apply(m, FloatSize()); webTransformOperations->appendMatrix(TransformationMatrix::toSkMatrix44(m)); break; } case TransformOperation::Identity: webTransformOperations->appendIdentity(); break; case TransformOperation::None: // Do nothing. break; } // switch } // for each operation }
PassOwnPtr<WebTransformOperations> toWebTransformOperations(const TransformOperations& transformOperations, const FloatSize& boxSize) { // We need to do a deep copy the transformOperations may contain ref pointers to TransformOperation objects. OwnPtr<WebTransformOperations> webTransformOperations = adoptPtr(Platform::current()->compositorSupport()->createTransformOperations()); if (!webTransformOperations) return nullptr; for (size_t j = 0; j < transformOperations.size(); ++j) { TransformOperation::OperationType operationType = transformOperations.operations()[j]->getOperationType(); switch (operationType) { case TransformOperation::SCALE_X: case TransformOperation::SCALE_Y: case TransformOperation::SCALE_Z: case TransformOperation::SCALE_3D: case TransformOperation::SCALE: { ScaleTransformOperation* transform = static_cast<ScaleTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendScale(transform->x(), transform->y(), transform->z()); break; } case TransformOperation::TRANSLATE_X: case TransformOperation::TRANSLATE_Y: case TransformOperation::TRANSLATE_Z: case TransformOperation::TRANSLATE_3D: case TransformOperation::TRANSLATE: { TranslateTransformOperation* transform = static_cast<TranslateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendTranslate(floatValueForLength(transform->x(), boxSize.width()), floatValueForLength(transform->y(), boxSize.height()), floatValueForLength(transform->z(), 1)); break; } case TransformOperation::ROTATE_X: case TransformOperation::ROTATE_Y: case TransformOperation::ROTATE_3D: case TransformOperation::ROTATE: { RotateTransformOperation* transform = static_cast<RotateTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendRotate(transform->x(), transform->y(), transform->z(), transform->angle()); break; } case TransformOperation::SKEW_X: case TransformOperation::SKEW_Y: case TransformOperation::SKEW: { SkewTransformOperation* transform = static_cast<SkewTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendSkew(transform->angleX(), transform->angleY()); break; } case TransformOperation::MATRIX: { MatrixTransformOperation* transform = static_cast<MatrixTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformSkMatrix44Conversions::convert(m)); break; } case TransformOperation::MATRIX_3D: { Matrix3DTransformOperation* transform = static_cast<Matrix3DTransformOperation*>(transformOperations.operations()[j].get()); TransformationMatrix m = transform->matrix(); webTransformOperations->appendMatrix(TransformSkMatrix44Conversions::convert(m)); break; } case TransformOperation::PERSPECTIVE: { PerspectiveTransformOperation* transform = static_cast<PerspectiveTransformOperation*>(transformOperations.operations()[j].get()); webTransformOperations->appendPerspective(floatValueForLength(transform->perspective(), 0)); break; } case TransformOperation::IDENTITY: webTransformOperations->appendIdentity(); break; case TransformOperation::NONE: // Do nothing. break; } // switch } // for each operation return webTransformOperations.release(); }
void PaintLayerReflectionInfo::updateAfterStyleChange(const ComputedStyle* oldStyle) { RefPtr<ComputedStyle> newStyle = ComputedStyle::create(); newStyle->inheritFrom(box().styleRef()); // Map in our transform. TransformOperations transform; switch (box().style()->boxReflect()->direction()) { case ReflectionBelow: transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), box().style()->boxReflect()->offset(), TransformOperation::Translate)); transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::Scale)); break; case ReflectionAbove: transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::Scale)); transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), box().style()->boxReflect()->offset(), TransformOperation::Translate)); break; case ReflectionRight: transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create( box().style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::Scale)); break; case ReflectionLeft: transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::Scale)); transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::Translate)); transform.operations().append(TranslateTransformOperation::create( box().style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::Translate)); break; } newStyle->setTransform(transform); // Map in our mask. newStyle->setMaskBoxImage(box().style()->boxReflect()->mask()); m_reflection->setStyle(newStyle.release()); }