void WebKitCSSMatrix::setMatrixValue(const String& string, ExceptionCode& ec)
{
    CSSParser p(useStrictParsing());
    RefPtr<CSSMutableStyleDeclaration> styleDeclaration = CSSMutableStyleDeclaration::create();
    if (p.parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true)) {
        // Convert to TransformOperations. This can fail if a property
        // requires style (i.e., param uses 'ems' or 'exs')
        PassRefPtr<CSSValue> val =  styleDeclaration->getPropertyCSSValue(CSSPropertyWebkitTransform);
        TransformOperations operations;
        if (!CSSStyleSelector::createTransformOperations(val.get(), 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 if (!string.isEmpty()) // There is something there but parsing failed
        ec = SYNTAX_ERR;
}
Beispiel #2
0
void WebKitCSSMatrix::setMatrixValue(const String& string, ExceptionCode& ec)
{
    RefPtr<CSSMutableStyleDeclaration> styleDeclaration = CSSMutableStyleDeclaration::create();
    if (CSSParser::parseValue(styleDeclaration.get(), CSSPropertyWebkitTransform, string, true, true)) {
        // 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 (!CSSStyleSelector::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 if (!string.isEmpty()) // There is something there but parsing failed
        ec = SYNTAX_ERR;
}
 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;
 }
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);
}
Beispiel #7
0
ExceptionOr<void> WebKitCSSMatrix::setMatrixValue(const String& string)
{
    if (string.isEmpty())
        return { };

    auto styleDeclaration = MutableStyleProperties::create();
    if (CSSParser::parseValue(styleDeclaration, CSSPropertyTransform, string, true, HTMLStandardMode) == CSSParser::ParseResult::Error)
        return Exception { SYNTAX_ERR };

    // Convert to TransformOperations. This can fail if a property requires style (i.e., param uses 'ems' or 'exs')
    auto value = styleDeclaration->getPropertyCSSValue(CSSPropertyTransform);

    // Check for a "none" or empty transform. In these cases we can use the default identity matrix.
    if (!value || (is<CSSPrimitiveValue>(*value) && downcast<CSSPrimitiveValue>(*value).valueID() == CSSValueNone))
        return { };

    TransformOperations operations;
    if (!transformsForValue(*value, CSSToLengthConversionData(), operations))
        return Exception { SYNTAX_ERR };

    // Convert transform operations to a TransformationMatrix. This can fail if a parameter has a percentage ('%').
    TransformationMatrix matrix;
    for (auto& operation : operations.operations()) {
        if (operation->apply(matrix, IntSize(0, 0)))
            return Exception { SYNTAX_ERR };
    }
    m_matrix = matrix;
    return { };
}
Beispiel #8
0
static PassRefPtr<AnimatableValue> createFromTransformProperties(
    PassRefPtr<TransformOperation> transform,
    double zoom,
    PassRefPtr<TransformOperation> initialTransform) {
  TransformOperations operation;
  operation.operations().push_back(transform ? transform : initialTransform);
  return AnimatableTransform::create(operation, transform ? zoom : 1);
}
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()));
}
  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;
}
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;
}
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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());
}