TEST_F(DisplayItemPropertyTreeBuilderTest, TransformDisplayItemCreatesTransformNode)
{
    // 2D transform display items should create a transform node as well,
    // unless the transform is a 2D translation only.
    AffineTransform rotation;
    rotation.rotate(45);

    processDummyDisplayItem();
    auto transformClient = processBeginTransform(rotation);
    processDummyDisplayItem();
    processEndTransform(transformClient);
    processDummyDisplayItem();
    finishPropertyTrees();

    // There should be two transform nodes.
    ASSERT_EQ(2u, transformTree().nodeCount());
    EXPECT_TRUE(transformTree().nodeAt(0).isRoot());
    EXPECT_EQ(0u, transformTree().nodeAt(1).parentNodeIndex);
    EXPECT_TRANSFORMS_ALMOST_EQ(TransformationMatrix(rotation), transformTree().nodeAt(1).matrix);

    // There should be three range records, the middle one affected by the
    // rotation.
    EXPECT_THAT(rangeRecordsAsStdVector(), ElementsAre(
        AllOf(hasRange(0, 1), hasTransformNode(0)),
        AllOf(hasRange(2, 3), hasTransformNode(1)),
        AllOf(hasRange(4, 5), hasTransformNode(0))));
}
void GraphicsContext::rotate(float radians)
{
    if (paintingDisabled())
        return;

    AffineTransform current;
    platformContext()->getTransform((double*)&current);
    current.rotate(rad2deg(radians));
    platformContext()->setTransform((double*)&current);
}
AffineTransform SVGResourceMarker::markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const
{
    ASSERT(m_renderer);

    AffineTransform transform;
    transform.translate(origin.x(), origin.y());
    transform.rotate(m_angle == -1 ? angle : m_angle);
    transform = m_renderer->markerContentTransformation(transform, m_referencePoint, m_useStrokeWidth ? strokeWidth : -1);
    return transform;
}
示例#4
0
static void affineTransformCompose(AffineTransform& m, const double sr[9])
{
    m.setA(sr[3]);
    m.setB(sr[4]);
    m.setC(sr[5]);
    m.setD(sr[6]);
    m.setE(sr[7]);
    m.setF(sr[8]);
    m.rotate(rad2deg(sr[2]));
    m.scale(sr[0], sr[1]);
}
示例#5
0
AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
{
    float markerAngle = angle();
    bool useStrokeWidth = markerElement().markerUnits() == SVGMarkerUnitsStrokeWidth;

    AffineTransform transform;
    transform.translate(origin.x(), origin.y());
    transform.rotate(markerAngle == -1 ? autoAngle : markerAngle);
    transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1);
    return transform;
}
AffineTransform LayoutSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
{
    SVGMarkerElement* marker = toSVGMarkerElement(element());
    ASSERT(marker);

    float markerAngle = angle();
    bool useStrokeWidth = marker->markerUnits()->currentValue()->enumValue() == SVGMarkerUnitsStrokeWidth;

    AffineTransform transform;
    transform.translate(origin.x(), origin.y());
    transform.rotate(markerAngle == -1 ? autoAngle : markerAngle);
    transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1);
    return transform;
}
示例#7
0
AffineTransform RenderSVGResourceMarker::markerTransformation(const FloatPoint& origin, float autoAngle, float strokeWidth) const
{
    SVGMarkerElement* marker = static_cast<SVGMarkerElement*>(node());
    ASSERT(marker);

    float markerAngle = angle();
    bool useStrokeWidth = (marker->markerUnits() == SVGMarkerElement::SVG_MARKERUNITS_STROKEWIDTH);

    AffineTransform transform;
    transform.translate(origin.x(), origin.y());
    transform.rotate(markerAngle == -1 ? autoAngle : markerAngle);
    transform = markerContentTransformation(transform, referencePoint(), useStrokeWidth ? strokeWidth : -1);
    return transform;
}
示例#8
0
static v8::Handle<v8::Value> rotateCallback(const v8::Arguments& args)
{
    INC_STATS("DOM.SVGMatrix.rotate");
    V8SVGPODTypeWrapper<AffineTransform>* impWrapper = V8SVGPODTypeWrapper<AffineTransform>::toNative(args.Holder());
    AffineTransform impInstance = *impWrapper;
    AffineTransform* imp = &impInstance;
    EXCEPTION_BLOCK(float, angle, static_cast<float>(args[0]->NumberValue()));
    AffineTransform result = *imp;
    result.rotate(angle);
    RefPtr<V8SVGPODTypeWrapper<AffineTransform> > wrapper = V8SVGStaticPODTypeWrapper<AffineTransform>::create(result);
    SVGElement* context = V8Proxy::svgContext(impWrapper);
    V8Proxy::setSVGContext(wrapper.get(), context);
    impWrapper->commitChange(impInstance, context);
    return toV8(wrapper.release());
}
AffineTransform LayoutSVGResourceMarker::markerTransformation(
    const FloatPoint& origin,
    float autoAngle,
    float strokeWidth) const {
  // Apply scaling according to markerUnits ('strokeWidth' or 'userSpaceOnUse'.)
  float markerScale =
      markerUnits() == SVGMarkerUnitsStrokeWidth ? strokeWidth : 1;

  AffineTransform transform;
  transform.translate(origin.x(), origin.y());
  transform.rotate(orientType() == SVGMarkerOrientAngle ? angle() : autoAngle);
  transform.scale(markerScale);

  // The 'origin' coordinate maps to SVGs refX/refY, given in coordinates
  // relative to the viewport established by the marker.
  FloatPoint mappedReferencePoint =
      viewportTransform().mapPoint(referencePoint());
  transform.translate(-mappedReferencePoint.x(), -mappedReferencePoint.y());
  return transform;
}
void SVGAnimateMotionElement::applyAnimatedValueToElement()
{
    if (!targetElement()->isStyledTransformable())
        return;
    
    SVGStyledTransformableElement* transformableElement = static_cast<SVGStyledTransformableElement*>(targetElement());
    RefPtr<SVGTransformList> transformList = transformableElement->transform();
    if (!transformList)
        return;
    
    ExceptionCode ec;
    if (!isAdditive())
        transformList->clear(ec);
    
    AffineTransform transform;
    transform.rotate(m_animatedAngle);
    transform.translate(m_animatedTranslation.width(), m_animatedTranslation.height());
    if (!transform.isIdentity()) {
        transformList->appendItem(SVGTransform(transform), ec);
        transformableElement->updateLocalTransform(transformList.get());
    }
}
void CanvasRenderingContext2D::rotate(float angleInRadians)
{
    GraphicsContext* c = drawingContext();
    if (!c)
        return;
    if (!state().m_invertibleCTM)
        return;

    if (!isfinite(angleInRadians))
        return;

    AffineTransform newTransform = state().m_transform;
    newTransform.rotate(angleInRadians / piDouble * 180.0);
    if (!newTransform.isInvertible()) {
        state().m_invertibleCTM = false;
        return;
    }

    state().m_transform = newTransform;
    c->rotate(angleInRadians);
    m_path.transform(AffineTransform().rotate(-angleInRadians / piDouble * 180.0));
}
void SVGAnimateMotionElement::calculateAnimatedValue(float percentage, unsigned, SVGSMILElement*)
{
    SVGElement* targetElement = this->targetElement();
    if (!targetElement)
        return;
    AffineTransform* transform = targetElement->supplementalTransform();
    if (!transform)
        return;

    if (RenderObject* targetRenderer = targetElement->renderer())
        targetRenderer->setNeedsTransformUpdate();

    if (!isAdditive())
        transform->makeIdentity();
    
    // FIXME: Implement accumulate.
    
    if (animationMode() == PathAnimation) {
        ASSERT(!animationPath().isEmpty());
        Path path = animationPath();
        float positionOnPath = path.length() * percentage;
        bool ok;
        FloatPoint position = path.pointAtLength(positionOnPath, ok);
        if (ok) {
            transform->translate(position.x(), position.y());
            RotateMode rotateMode = this->rotateMode();
            if (rotateMode == RotateAuto || rotateMode == RotateAutoReverse) {
                float angle = path.normalAngleAtLength(positionOnPath, ok);
                if (rotateMode == RotateAutoReverse)
                    angle += 180;
                transform->rotate(angle);
            }
        }
        return;
    }
    FloatSize diff = m_toPoint - m_fromPoint;
    transform->translate(diff.width() * percentage + m_fromPoint.x(), diff.height() * percentage + m_fromPoint.y());
}
示例#13
0
// This works by converting the SVG arc to "simple" beziers.
// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
// See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
bool SVGPathParser::decomposeArcToCubic(float angle, float rx, float ry, FloatPoint& point1, FloatPoint& point2, bool largeArcFlag, bool sweepFlag)
{
    FloatSize midPointDistance = point1 - point2;
    midPointDistance.scale(0.5f);

    AffineTransform pointTransform;
    pointTransform.rotate(-angle);

    FloatPoint transformedMidPoint = pointTransform.mapPoint(FloatPoint(midPointDistance.width(), midPointDistance.height()));
    float squareRx = rx * rx;
    float squareRy = ry * ry;
    float squareX = transformedMidPoint.x() * transformedMidPoint.x();
    float squareY = transformedMidPoint.y() * transformedMidPoint.y();

    // Check if the radii are big enough to draw the arc, scale radii if not.
    // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
    float radiiScale = squareX / squareRx + squareY / squareRy;
    if (radiiScale > 1) {
        rx *= sqrtf(radiiScale);
        ry *= sqrtf(radiiScale);
    }

    pointTransform.makeIdentity();
    pointTransform.scale(1 / rx, 1 / ry);
    pointTransform.rotate(-angle);

    point1 = pointTransform.mapPoint(point1);
    point2 = pointTransform.mapPoint(point2);
    FloatSize delta = point2 - point1;

    float d = delta.width() * delta.width() + delta.height() * delta.height();
    float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f);

    float scaleFactor = sqrtf(scaleFactorSquared);
    if (sweepFlag == largeArcFlag)
        scaleFactor = -scaleFactor;

    delta.scale(scaleFactor);
    FloatPoint centerPoint = point1 + point2;
    centerPoint.scale(0.5f);
    centerPoint.move(-delta.height(), delta.width());

    float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians();
    float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians();

    float thetaArc = theta2 - theta1;
    if (thetaArc < 0 && sweepFlag)
        thetaArc += 2 * piFloat;
    else if (thetaArc > 0 && !sweepFlag)
        thetaArc -= 2 * piFloat;

    pointTransform.makeIdentity();
    pointTransform.rotate(angle);
    pointTransform.scale(rx, ry);

    // Some results of atan2 on some platform implementations are not exact enough. So that we get more
    // cubic curves than expected here. Adding 0.001f reduces the count of sgements to the correct count.
    int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f)));
    for (int i = 0; i < segments; ++i) {
        float startTheta = theta1 + i * thetaArc / segments;
        float endTheta = theta1 + (i + 1) * thetaArc / segments;

        float t = (8 / 6.f) * tanf(0.25f * (endTheta - startTheta));
        if (!std::isfinite(t))
            return false;
        float sinStartTheta = sinf(startTheta);
        float cosStartTheta = cosf(startTheta);
        float sinEndTheta = sinf(endTheta);
        float cosEndTheta = cosf(endTheta);

        point1 = FloatPoint(cosStartTheta - t * sinStartTheta, sinStartTheta + t * cosStartTheta);
        point1.move(centerPoint.x(), centerPoint.y());
        FloatPoint targetPoint = FloatPoint(cosEndTheta, sinEndTheta);
        targetPoint.move(centerPoint.x(), centerPoint.y());
        point2 = targetPoint;
        point2.move(t * sinEndTheta, -t * cosEndTheta);

        m_consumer.curveToCubic(pointTransform.mapPoint(point1), pointTransform.mapPoint(point2),
                                 pointTransform.mapPoint(targetPoint), AbsoluteCoordinates);
    }
    return true;
}
示例#14
0
// This works by converting the SVG arc to "simple" beziers.
// Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
// See also SVG implementation notes:
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
bool SVGPathNormalizer::decomposeArcToCubic(const FloatPoint& currentPoint,
                                            const PathSegmentData& arcSegment) {
  // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a
  // "lineto") joining the endpoints.
  // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
  float rx = fabsf(arcSegment.arcRadii().x());
  float ry = fabsf(arcSegment.arcRadii().y());
  if (!rx || !ry)
    return false;

  // If the current point and target point for the arc are identical, it should
  // be treated as a zero length path. This ensures continuity in animations.
  if (arcSegment.targetPoint == currentPoint)
    return false;

  float angle = arcSegment.arcAngle();

  FloatSize midPointDistance = currentPoint - arcSegment.targetPoint;
  midPointDistance.scale(0.5f);

  AffineTransform pointTransform;
  pointTransform.rotate(-angle);

  FloatPoint transformedMidPoint = pointTransform.mapPoint(
      FloatPoint(midPointDistance.width(), midPointDistance.height()));
  float squareRx = rx * rx;
  float squareRy = ry * ry;
  float squareX = transformedMidPoint.x() * transformedMidPoint.x();
  float squareY = transformedMidPoint.y() * transformedMidPoint.y();

  // Check if the radii are big enough to draw the arc, scale radii if not.
  // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
  float radiiScale = squareX / squareRx + squareY / squareRy;
  if (radiiScale > 1) {
    rx *= sqrtf(radiiScale);
    ry *= sqrtf(radiiScale);
  }

  pointTransform.makeIdentity();
  pointTransform.scale(1 / rx, 1 / ry);
  pointTransform.rotate(-angle);

  FloatPoint point1 = pointTransform.mapPoint(currentPoint);
  FloatPoint point2 = pointTransform.mapPoint(arcSegment.targetPoint);
  FloatSize delta = point2 - point1;

  float d = delta.width() * delta.width() + delta.height() * delta.height();
  float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f);

  float scaleFactor = sqrtf(scaleFactorSquared);
  if (arcSegment.arcSweep == arcSegment.arcLarge)
    scaleFactor = -scaleFactor;

  delta.scale(scaleFactor);
  FloatPoint centerPoint = point1 + point2;
  centerPoint.scale(0.5f, 0.5f);
  centerPoint.move(-delta.height(), delta.width());

  float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians();
  float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians();

  float thetaArc = theta2 - theta1;
  if (thetaArc < 0 && arcSegment.arcSweep)
    thetaArc += twoPiFloat;
  else if (thetaArc > 0 && !arcSegment.arcSweep)
    thetaArc -= twoPiFloat;

  pointTransform.makeIdentity();
  pointTransform.rotate(angle);
  pointTransform.scale(rx, ry);

  // Some results of atan2 on some platform implementations are not exact
  // enough. So that we get more cubic curves than expected here. Adding 0.001f
  // reduces the count of sgements to the correct count.
  int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f)));
  for (int i = 0; i < segments; ++i) {
    float startTheta = theta1 + i * thetaArc / segments;
    float endTheta = theta1 + (i + 1) * thetaArc / segments;

    float t = (8 / 6.f) * tanf(0.25f * (endTheta - startTheta));
    if (!std::isfinite(t))
      return false;
    float sinStartTheta = sinf(startTheta);
    float cosStartTheta = cosf(startTheta);
    float sinEndTheta = sinf(endTheta);
    float cosEndTheta = cosf(endTheta);

    point1 = FloatPoint(cosStartTheta - t * sinStartTheta,
                        sinStartTheta + t * cosStartTheta);
    point1.move(centerPoint.x(), centerPoint.y());
    FloatPoint targetPoint = FloatPoint(cosEndTheta, sinEndTheta);
    targetPoint.move(centerPoint.x(), centerPoint.y());
    point2 = targetPoint;
    point2.move(t * sinEndTheta, -t * cosEndTheta);

    PathSegmentData cubicSegment;
    cubicSegment.command = PathSegCurveToCubicAbs;
    cubicSegment.point1 = pointTransform.mapPoint(point1);
    cubicSegment.point2 = pointTransform.mapPoint(point2);
    cubicSegment.targetPoint = pointTransform.mapPoint(targetPoint);

    m_consumer->emitSegment(cubicSegment);
  }
  return true;
}