void LowLevelGraphicsPostScriptRenderer::drawImage (const Image& sourceImage, const AffineTransform& transform)
{
    const int w = sourceImage.getWidth();
    const int h = sourceImage.getHeight();

    writeClip();

    out << "gsave ";
    writeTransform (transform.translated ((float) stateStack.getLast()->xOffset, (float) stateStack.getLast()->yOffset)
                             .scaled (1.0f, -1.0f));

    RectangleList<int> imageClip;
    sourceImage.createSolidAreaMask (imageClip, 0.5f);

    out << "newpath ";
    int itemsOnLine = 0;

    for (const Rectangle<int>* i = imageClip.begin(), * const e = imageClip.end(); i != e; ++i)
    {
        if (++itemsOnLine == 6)
        {
            out << '\n';
            itemsOnLine = 0;
        }

        out << i->getX() << ' ' << i->getY() << ' ' << i->getWidth() << ' ' << i->getHeight() << " pr ";
    }

    out << " clip newpath\n";

    out << w << ' ' << h << " scale\n";
    out << w << ' ' << h << " 8 [" << w << " 0 0 -" << h << ' ' << (int) 0 << ' ' << h << " ]\n";

    writeImage (sourceImage, 0, 0, w, h);

    out << "false 3 colorimage grestore\n";
    needToClip = true;
}
Exemplo n.º 2
0
TEST(TransparencyWin, DISABLED_TranslateScaleOpaqueCompositeLayer)
{
    OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), 1));

    // The background is white on top with red on bottom.
    Color white(0xFFFFFFFF);
    FloatRect topRect(0, 0, 16, 8);
    src->context()->fillRect(topRect, white);
    Color red(0xFFFF0000);
    FloatRect bottomRect(0, 8, 16, 8);
    src->context()->fillRect(bottomRect, red);

    src->context()->save();

    // Translate left by one pixel.
    AffineTransform left;
    left.translate(-1, 0);

    // Scale by 2x.
    AffineTransform scale;
    scale.scale(2.0);
    src->context()->concatCTM(scale);

    // Then translate up by one pixel (which will actually be 2 due to scaling).
    AffineTransform up;
    up.translate(0, -1);
    src->context()->concatCTM(up);

    // Now draw 50% red square.
    {
        // Create a transparency helper inset one pixel in the buffer. The
        // coordinates are before transforming into this space, and maps to
        // IntRect(1, 1, 14, 14).
        TransparencyWin helper;
        helper.init(src->context(),
                    TransparencyWin::OpaqueCompositeLayer,
                    TransparencyWin::KeepTransform,
                    IntRect(1, -15, 14, 14));

        // Fill with red.
        helper.context()->fillRect(helper.drawRect(), Color(0x7f7f0000));
        clearTopLayerAlphaChannel(helper.context());
        helper.composite();
    }
}
Exemplo n.º 3
0
void drawPatternToCairoContext(cairo_t* cr, cairo_surface_t* image, const IntSize& imageSize, const FloatRect& tileRect,
                               const AffineTransform& patternTransform, const FloatPoint& phase, cairo_operator_t op, const FloatRect& destRect)
{
    // Avoid NaN
    if (!isfinite(phase.x()) || !isfinite(phase.y()))
       return;

    cairo_save(cr);

    RefPtr<cairo_surface_t> clippedImageSurface = 0;
    if (tileRect.size() != imageSize) {
        IntRect imageRect = enclosingIntRect(tileRect);
        clippedImageSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageRect.width(), imageRect.height()));
        RefPtr<cairo_t> clippedImageContext = adoptRef(cairo_create(clippedImageSurface.get()));
        cairo_set_source_surface(clippedImageContext.get(), image, -tileRect.x(), -tileRect.y());
        cairo_paint(clippedImageContext.get());
        image = clippedImageSurface.get();
    }

    cairo_pattern_t* pattern = cairo_pattern_create_for_surface(image);
    cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);

    cairo_matrix_t patternMatrix = cairo_matrix_t(patternTransform);
    cairo_matrix_t phaseMatrix = {1, 0, 0, 1, phase.x() + tileRect.x() * patternTransform.a(), phase.y() + tileRect.y() * patternTransform.d()};
    cairo_matrix_t combined;
    cairo_matrix_multiply(&combined, &patternMatrix, &phaseMatrix);
    cairo_matrix_invert(&combined);
    cairo_pattern_set_matrix(pattern, &combined);

    cairo_set_operator(cr, op);
    cairo_set_source(cr, pattern);
    cairo_pattern_destroy(pattern);
    cairo_rectangle(cr, destRect.x(), destRect.y(), destRect.width(), destRect.height());
    cairo_fill(cr);

    cairo_restore(cr);
}
PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes,
                                                                  const FloatRect& tileBoundaries,
                                                                  const FloatRect& absoluteTileBoundaries,
                                                                  const AffineTransform& tileImageTransform,
                                                                  FloatRect& clampedAbsoluteTileBoundaries) const
{
    clampedAbsoluteTileBoundaries = SVGImageBufferTools::clampedAbsoluteTargetRect(absoluteTileBoundaries);

    OwnPtr<ImageBuffer> tileImage;

    if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB))
        return nullptr;

    GraphicsContext* tileImageContext = tileImage->context();
    ASSERT(tileImageContext);

    // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation).
    tileImageContext->scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(),
                                      clampedAbsoluteTileBoundaries.height() / tileBoundaries.height()));

    // Apply tile image transformations.
    if (!tileImageTransform.isIdentity())
        tileImageContext->concatCTM(tileImageTransform);

    AffineTransform contentTransformation;
    if (attributes.boundingBoxModeContent())
        contentTransformation = tileImageTransform;

    // Draw the content into the ImageBuffer.
    for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
        if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
            continue;
        SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation);
    }

    return tileImage.release();
}
void AffineTransform::blend(const AffineTransform& from, double progress)
{
    DecomposedType srA, srB;

    from.decompose(srA);
    this->decompose(srB);

    // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
    if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 &&  srB.scaleX < 0)) {
        srA.scaleX = -srA.scaleX;
        srA.scaleY = -srA.scaleY;
        srA.angle += srA.angle < 0 ? piDouble : -piDouble;
    }

    // Don't rotate the long way around.
    srA.angle = fmod(srA.angle, 2 * piDouble);
    srB.angle = fmod(srB.angle, 2 * piDouble);

    if (fabs(srA.angle - srB.angle) > piDouble) {
        if (srA.angle > srB.angle)
            srA.angle -= piDouble * 2;
        else
            srB.angle -= piDouble * 2;
    }

    srA.scaleX += progress * (srB.scaleX - srA.scaleX);
    srA.scaleY += progress * (srB.scaleY - srA.scaleY);
    srA.angle += progress * (srB.angle - srA.angle);
    srA.remainderA += progress * (srB.remainderA - srA.remainderA);
    srA.remainderB += progress * (srB.remainderB - srA.remainderB);
    srA.remainderC += progress * (srB.remainderC - srA.remainderC);
    srA.remainderD += progress * (srB.remainderD - srA.remainderD);
    srA.translateX += progress * (srB.translateX - srA.translateX);
    srA.translateY += progress * (srB.translateY - srA.translateY);

    this->recompose(srA);
}
Exemplo n.º 6
0
static bool rotationOfCharacterCallback(QueryData* queryData, const SVGTextFragment& fragment)
{
    RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData);

    int startPosition = data->position;
    int endPosition = startPosition + 1;
    if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition))
        return false;

    if (!fragment.isTransformed()) {
        data->rotation = 0;
    } else {
        AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength);
        fragmentTransform.scale(1 / fragmentTransform.xScale(), 1 / fragmentTransform.yScale());
        data->rotation = narrowPrecisionToFloat(rad2deg(atan2(fragmentTransform.b(), fragmentTransform.a())));
    }
    return true;
}
Exemplo n.º 7
0
std::unique_ptr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries) const
{
    clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries);

    std::unique_ptr<ImageBuffer> tileImage;

    if (!SVGRenderingContext::createImageBufferForPattern(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB, Unaccelerated))
        return nullptr;

    GraphicsContext* tileImageContext = tileImage->context();
    ASSERT(tileImageContext);

    // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation).
    tileImageContext->scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(),
                                      clampedAbsoluteTileBoundaries.height() / tileBoundaries.height()));

    // Apply tile image transformations.
    if (!tileImageTransform.isIdentity())
        tileImageContext->concatCTM(tileImageTransform);

    AffineTransform contentTransformation;
    if (attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
        contentTransformation = tileImageTransform;

    // Draw the content into the ImageBuffer.
    auto children = childrenOfType<SVGElement>(*attributes.patternContentElement());
    for (auto it = children.begin(), end = children.end(); it != end; ++it) {
        const SVGElement& child = *it;
        if (!child.renderer())
            continue;
        if (child.renderer()->needsLayout())
            return nullptr;
        SVGRenderingContext::renderSubtreeToImageBuffer(tileImage.get(), *child.renderer(), contentTransformation);
    }

    return tileImage;
}
    void drawImage (const Image& image, const AffineTransform& transform)
    {
        renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform)));

        D2D1_SIZE_U size;
        size.width = image.getWidth();
        size.height = image.getHeight();

        D2D1_BITMAP_PROPERTIES bp = D2D1::BitmapProperties();

        Image img (image.convertedToFormat (Image::ARGB));
        Image::BitmapData bd (img, Image::BitmapData::readOnly);
        bp.pixelFormat = renderingTarget->GetPixelFormat();
        bp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;

        {
            ComSmartPtr <ID2D1Bitmap> tempBitmap;
            renderingTarget->CreateBitmap (size, bd.data, bd.lineStride, bp, tempBitmap.resetAndGetPointerAddress());
            if (tempBitmap != nullptr)
                renderingTarget->DrawBitmap (tempBitmap);
        }

        renderingTarget->SetTransform (D2D1::IdentityMatrix());
    }
void Image::drawPattern(GraphicsContext *gc, const FloatRect& srcRect, const AffineTransform& patternTransform,
                        const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& destRect, BlendMode)
{
    JNIEnv* env = WebCore_GetJavaEnv();

    if (!gc || gc->paintingDisabled() || srcRect.isEmpty()) {
        return;
    }

    NativeImagePtr currFrame = nativeImageForCurrentFrame();
    if (!currFrame) {
        return;
    }

    TransformationMatrix tm = patternTransform.toTransformationMatrix();

    static jmethodID mid = env->GetMethodID(PG_GetGraphicsManagerClass(env),
                "createTransform",
                "(DDDDDD)Lcom/sun/webkit/graphics/WCTransform;");
    ASSERT(mid);
    JLObject transform(env->CallObjectMethod(PL_GetGraphicsManager(env), mid,
                tm.a(), tm.b(), tm.c(), tm.d(), tm.e(), tm.f()));
    ASSERT(transform);
    CheckAndClearException(env);

    gc->platformContext()->rq().freeSpace(13 * 4)
    << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWPATTERN
    << currFrame
    << srcRect.x() << srcRect.y() << srcRect.width() << srcRect.height()
    << RQRef::create(transform)
    << phase.x() << phase.y()
    << destRect.x() << destRect.y() << destRect.width() << destRect.height();

    if (imageObserver())
        imageObserver()->didDraw(this);
}
Exemplo n.º 10
0
SkMatrix affineTransformToSkMatrix(const AffineTransform& source)
{
    SkMatrix result;

    result.setScaleX(WebCoreDoubleToSkScalar(source.a()));
    result.setSkewX(WebCoreDoubleToSkScalar(source.c()));
    result.setTranslateX(WebCoreDoubleToSkScalar(source.e()));

    result.setScaleY(WebCoreDoubleToSkScalar(source.d()));
    result.setSkewY(WebCoreDoubleToSkScalar(source.b()));
    result.setTranslateY(WebCoreDoubleToSkScalar(source.f()));

    // FIXME: Set perspective properly.
    result.setPerspX(0);
    result.setPerspY(0);
    result.set(SkMatrix::kMPersp2, SK_Scalar1);

    return result;
}
Exemplo n.º 11
0
// static
void Shader::affineTo4x4(const AffineTransform& transform, float mat[16])
{
    mat[0] = transform.a();
    mat[1] = transform.b();
    mat[2] = 0.0f;
    mat[3] = 0.0f;
    mat[4] = transform.c();
    mat[5] = transform.d();
    mat[6] = 0.0f;
    mat[7] = 0.0f;
    mat[8] = 0.0f;
    mat[9] = 0.0f;
    mat[10] = 1.0f;
    mat[11] = 0.0f;
    mat[12] = transform.e();
    mat[13] = transform.f();
    mat[14] = 0.0f;
    mat[15] = 1.0f;
}
Exemplo n.º 12
0
AffineTransform SVGSVGElement::localCoordinateSpaceTransform(SVGLocatable::CTMScope mode) const
{
    AffineTransform viewBoxTransform;
    if (attributes()->getAttributeItem(SVGNames::viewBoxAttr))
        viewBoxTransform = viewBoxToViewTransform(width().value(this), height().value(this));

    AffineTransform transform;
    if (!isOutermostSVG())
        transform.translate(x().value(this), y().value(this));
    else if (mode == SVGLocatable::ScreenScope) {
        if (RenderObject* renderer = this->renderer()) {
            // Translate in our CSS parent coordinate space
            // FIXME: This doesn't work correctly with CSS transforms.
            FloatPoint location = renderer->localToAbsolute(FloatPoint(), false, true);

            // Be careful here! localToAbsolute() includes the x/y offset coming from the viewBoxToViewTransform(), because
            // RenderSVGRoot::localToBorderBoxTransform() (called through mapLocalToContainer(), called from localToAbsolute())
            // also takes the viewBoxToViewTransform() into account, so we have to subtract it here (original cause of bug #27183)
            transform.translate(location.x() - viewBoxTransform.e(), location.y() - viewBoxTransform.f());
        }
    }

    return transform.multLeft(viewBoxTransform);
}
Exemplo n.º 13
0
    AffineTransform getTransform()
    {
        const float hw = 0.5f * getWidth();
        const float hh = 0.5f * getHeight();

        AffineTransform t;

        if (controls.animateRotation.getToggleState())
            t = t.rotated (rotation.getValue() * float_Pi * 2.0f);

        if (controls.animateSize.getToggleState())
            t = t.scaled (0.3f + size.getValue() * 2.0f);

        if (controls.animatePosition.getToggleState())
            t = t.translated (hw + hw * (offsetX.getValue() - 0.5f),
                              hh + hh * (offsetY.getValue() - 0.5f));
        else
            t = t.translated (hw, hh);

        if (controls.animateShear.getToggleState())
            t = t.sheared (shear.getValue() * 2.0f - 1.0f, 0.0f);

        return t;
    }
void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const TextRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
{
    SVGFontElement* fontElement = 0;
    SVGFontFaceElement* fontFaceElement = 0;

    const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
    if (!fontElement || !fontFaceElement)
        return;

    // We can only paint SVGFonts if a context is available.
    RenderSVGResource* activePaintingResource = activePaintingResourceFromRun(run);
    RenderObject* renderObject = renderObjectFromRun(run);
    RenderObject* parentRenderObject = firstParentRendererForNonTextNode(renderObject);
    RenderStyle* parentRenderObjectStyle = 0;

    ASSERT(renderObject);
    if (!activePaintingResource) {
        // TODO: We're only supporting simple filled HTML text so far.
        RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource();
        solidPaintingResource->setColor(context->fillColor());
        activePaintingResource = solidPaintingResource;
    }
 
    bool isVerticalText = false;
    if (parentRenderObject) {
        parentRenderObjectStyle = parentRenderObject->style();
        ASSERT(parentRenderObjectStyle);
        isVerticalText = parentRenderObjectStyle->svgStyle()->isVerticalWritingMode();
    }

    float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());
    ASSERT(activePaintingResource);

    FloatPoint glyphOrigin;
    glyphOrigin.setX(svgFontData->horizontalOriginX() * scale);
    glyphOrigin.setY(svgFontData->horizontalOriginY() * scale);

    FloatPoint currentPoint = point;
    RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;
    for (int i = 0; i < numGlyphs; ++i) {
        Glyph glyph = glyphBuffer.glyphAt(from + i);
        if (!glyph)
            continue;

        float advance = glyphBuffer.advanceAt(from + i);
        SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
        ASSERT(!svgGlyph.isPartOfLigature);
        ASSERT(svgGlyph.tableEntry == glyph);

        SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData);

        // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
        if (svgGlyph.pathData.isEmpty()) {
            if (isVerticalText)
                currentPoint.move(0, advance);
            else
                currentPoint.move(advance, 0);
            continue;
         }

        context->save();

        if (isVerticalText) {
            glyphOrigin.setX(svgGlyph.verticalOriginX * scale);
            glyphOrigin.setY(svgGlyph.verticalOriginY * scale);
         }

        AffineTransform glyphPathTransform;
        glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
        glyphPathTransform.scale(scale, -scale);

        Path glyphPath = svgGlyph.pathData;
        glyphPath.transform(glyphPathTransform);

        if (activePaintingResource->applyResource(parentRenderObject, parentRenderObjectStyle, context, resourceMode)) {
            if (renderObject && renderObject->isSVGInlineText()) {
                const RenderSVGInlineText* textRenderer = toRenderSVGInlineText(renderObject);
                context->setStrokeThickness(context->strokeThickness() * textRenderer->scalingFactor());
            }
            activePaintingResource->postApplyResource(parentRenderObject, context, resourceMode, &glyphPath, 0);
         }
 
        context->restore();

        if (isVerticalText)
            currentPoint.move(0, advance);
        else
            currentPoint.move(advance, 0);
    }
}
void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object)
{
    FloatRect objectBoundingBox = object->objectBoundingBox();

    // Mask rect clipped with clippingBoundingBox and filterBoundingBox as long as they are present.
    maskerData->maskRect = object->repaintRectInLocalCoordinates();
    if (maskerData->maskRect.isEmpty()) {
        maskerData->emptyMask = true;
        return;
    }
    
    if (m_maskBoundaries.isEmpty())
        calculateMaskContentRepaintRect();

    FloatRect repaintRect = m_maskBoundaries;
    AffineTransform contextTransform;
    // We need to scale repaintRect for objectBoundingBox to get the drawing area.
    if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contextTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
        FloatPoint contextAdjustment = repaintRect.location();
        repaintRect = contextTransform.mapRect(repaintRect);
        repaintRect.move(objectBoundingBox.x(), objectBoundingBox.y());
        contextTransform.translate(-contextAdjustment.x(), -contextAdjustment.y());
    }
    repaintRect.intersect(maskerData->maskRect);
    maskerData->maskRect = repaintRect;
    IntRect maskImageRect = enclosingIntRect(maskerData->maskRect);

    maskImageRect.setLocation(IntPoint());

    // Don't create ImageBuffers with image size of 0
    if (maskImageRect.isEmpty()) {
        maskerData->emptyMask = true;
        return;
    }

    // FIXME: This changes color space to linearRGB, the default color space
    // for masking operations in SVG. We need a switch for the other color-space
    // attribute values sRGB, inherit and auto.
    maskerData->maskImage = ImageBuffer::create(maskImageRect.size(), LinearRGB);
    if (!maskerData->maskImage)
        return;

    GraphicsContext* maskImageContext = maskerData->maskImage->context();
    ASSERT(maskImageContext);

    maskImageContext->save();

    if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
        maskImageContext->translate(-maskerData->maskRect.x(), -maskerData->maskRect.y());
    maskImageContext->concatCTM(contextTransform);

    // draw the content into the ImageBuffer
    for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
        RenderObject* renderer = node->renderer();
        if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer)
            continue;
        RenderStyle* style = renderer->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;
        renderSubtreeToImage(maskerData->maskImage.get(), renderer);
    }

    maskImageContext->restore();

    // create the luminance mask
    RefPtr<ImageData> imageData(maskerData->maskImage->getUnmultipliedImageData(maskImageRect));
    CanvasPixelArray* srcPixelArray(imageData->data());

    for (unsigned pixelOffset = 0; pixelOffset < srcPixelArray->length(); pixelOffset += 4) {
        unsigned char a = srcPixelArray->get(pixelOffset + 3);
        if (!a)
            continue;
        unsigned char r = srcPixelArray->get(pixelOffset);
        unsigned char g = srcPixelArray->get(pixelOffset + 1);
        unsigned char b = srcPixelArray->get(pixelOffset + 2);

        double luma = (r * 0.2125 + g * 0.7154 + b * 0.0721) * ((double)a / 255.0);
        srcPixelArray->set(pixelOffset + 3, luma);
    }

    maskerData->maskImage->putUnmultipliedImageData(imageData.get(), maskImageRect, IntPoint());
}
Exemplo n.º 16
0
float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObject& renderer)
{
    AffineTransform ctm = calculateTransformationToOutermostCoordinateSystem(renderer);
    return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2));
}
Exemplo n.º 17
0
// DragTo
void
DragSideState::DragTo(BPoint current, uint32 modifiers)
{
	BRect oldBox = fParent->Box();
	if (oldBox.Width() == 0.0 || oldBox.Height() == 0.0)
		return;

	// TODO: some of this can be combined into less steps
	BRect newBox = oldBox;

	fOldTransform.InverseTransform(&current);
	
	switch (fSide) {
		case LEFT_SIDE:
			newBox.left = current.x - fOffsetFromSide;
			break;
		case RIGHT_SIDE:
			newBox.right = current.x - fOffsetFromSide;
			break;
		case TOP_SIDE:
			newBox.top = current.y - fOffsetFromSide;
			break;
		case BOTTOM_SIDE:
			newBox.bottom = current.y - fOffsetFromSide;
			break;
	}

	if (!(modifiers & B_SHIFT_KEY)) {
		// keep the x and y scale the same
		double xScale = newBox.Width() / oldBox.Width();
		double yScale = newBox.Height() / oldBox.Height();

		if (modifiers & B_COMMAND_KEY) {
			xScale = snap_scale(xScale);
			yScale = snap_scale(yScale);
		}

		if (fSide == LEFT_SIDE || fSide == RIGHT_SIDE)
			yScale = yScale > 0.0 ? fabs(xScale) : -fabs(xScale);
		else
			xScale = xScale > 0.0 ? fabs(yScale) : -fabs(yScale);

		switch (fSide) {
			case LEFT_SIDE: {
				newBox.left = oldBox.right - oldBox.Width() * xScale;
				float middle = (oldBox.top + oldBox.bottom) / 2.0;
				float newHeight = oldBox.Height() * yScale;
				newBox.top = middle - newHeight / 2.0;
				newBox.bottom = middle + newHeight / 2.0;
				break;
			}

			case RIGHT_SIDE: {
				newBox.right = oldBox.left + oldBox.Width() * xScale;
				float middle = (oldBox.top + oldBox.bottom) / 2.0;
				float newHeight = oldBox.Height() * yScale;
				newBox.top = middle - newHeight / 2.0;
				newBox.bottom = middle + newHeight / 2.0;
				break;
			}

			case TOP_SIDE: {
				newBox.top = oldBox.bottom - oldBox.Height() * yScale;
				float middle = (oldBox.left + oldBox.right) / 2.0;
				float newWidth = oldBox.Width() * xScale;
				newBox.left = middle - newWidth / 2.0;
				newBox.right = middle + newWidth / 2.0;
				break;
			}

			case BOTTOM_SIDE: {
				newBox.bottom = oldBox.top + oldBox.Height() * yScale;
				float middle = (oldBox.left + oldBox.right) / 2.0;
				float newWidth = oldBox.Width() * xScale;
				newBox.left = middle - newWidth / 2.0;
				newBox.right = middle + newWidth / 2.0;
				break;
			}
		}
	}

	// build a matrix that performs just the
	// distortion of the box with the opposite
	// corner of the one being dragged staying fixed
	AffineTransform s;
	s.rect_to_rect(oldBox.left, oldBox.top, oldBox.right, oldBox.bottom,
				   newBox.left, newBox.top, newBox.right, newBox.bottom);

	// construct a transformation that
	// * excludes the effect of the fParant->Pivot()
	// * includes the effect of the changed scaling and translation
	// (see DragCornerState::DragTo() for explaination)
	AffineTransform t;
	BPoint pivot(fParent->Pivot());
	t.TranslateBy(pivot.x, pivot.y);
	t.Multiply(s);
	t.Multiply(fOldTransform);
	t.TranslateBy(-pivot.x, -pivot.y);

	// get the translation
	double translationX;
	double translationY;
	t.translation(&translationX, &translationY);

	// get the scale
	double newScaleX;
	double newScaleY;
	t.scaling(&newScaleX, &newScaleY);

	// operating on just the affine parameters is much more precise
	fParent->SetTranslationAndScale(BPoint(translationX, translationY),
		newScaleX, newScaleY);
}
Exemplo n.º 18
0
// DragTo
void
DragCornerState::DragTo(BPoint current, uint32 modifiers)
{
	BRect oldBox = fParent->Box();
	if (oldBox.Width() == 0.0 || oldBox.Height() == 0.0)
		return;

	// TODO: some of this can be combined into less steps
	BRect newBox = oldBox;

	fOldTransform.InverseTransform(&current);
	
	switch (fCorner) {
		case LEFT_TOP_CORNER:
			newBox.left = current.x - fOffsetFromCorner.x;
			newBox.top = current.y - fOffsetFromCorner.y;
			break;
		case RIGHT_TOP_CORNER:
			newBox.right = current.x - fOffsetFromCorner.x;
			newBox.top = current.y - fOffsetFromCorner.y;
			break;
		case LEFT_BOTTOM_CORNER:
			newBox.left = current.x - fOffsetFromCorner.x;
			newBox.bottom = current.y - fOffsetFromCorner.y;
			break;
		case RIGHT_BOTTOM_CORNER:
			newBox.right = current.x - fOffsetFromCorner.x;
			newBox.bottom = current.y - fOffsetFromCorner.y;
			break;
	}

	if (!(modifiers & B_SHIFT_KEY)) {
		// keep the x and y scale the same
		double xScale = newBox.Width() / oldBox.Width();
		double yScale = newBox.Height() / oldBox.Height();
	
		if (modifiers & B_COMMAND_KEY) {
			xScale = snap_scale(xScale);
			yScale = snap_scale(yScale);
		}

		if (fabs(xScale) > fabs(yScale))
			yScale = yScale > 0.0 ? fabs(xScale) : -fabs(xScale);
		else
			xScale = xScale > 0.0 ? fabs(yScale) : -fabs(yScale);

		switch (fCorner) {
			case LEFT_TOP_CORNER:
				newBox.left = oldBox.right - oldBox.Width() * xScale;
				newBox.top = oldBox.bottom - oldBox.Height() * yScale;
				break;
			case RIGHT_TOP_CORNER:
				newBox.right = oldBox.left + oldBox.Width() * xScale;
				newBox.top = oldBox.bottom - oldBox.Height() * yScale;
				break;
			case LEFT_BOTTOM_CORNER:
				newBox.left = oldBox.right - oldBox.Width() * xScale;
				newBox.bottom = oldBox.top + oldBox.Height() * yScale;
				break;
			case RIGHT_BOTTOM_CORNER:
				newBox.right = oldBox.left + oldBox.Width() * xScale;
				newBox.bottom = oldBox.top + oldBox.Height() * yScale;
				break;
		}
	}

	// build a matrix that performs just the
	// distortion of the box with the opposite
	// corner of the one being dragged staying fixed
	AffineTransform s;
	s.rect_to_rect(oldBox.left, oldBox.top, oldBox.right, oldBox.bottom,
				   newBox.left, newBox.top, newBox.right, newBox.bottom);

	// construct a transformation that
	// * excludes the effect of the fParant->Pivot()
	// * includes the effect of the changed scaling and translation
	AffineTransform t;
	BPoint pivot(fParent->Pivot());
	t.TranslateBy(pivot.x, pivot.y);
	t.Multiply(s);
		// at this point, the matrix is
		// similar/compatible to the original
		// matrix (fOldTransform), and also
		// contains the pivot
	t.Multiply(fOldTransform);
		// here both matrices are "merged"
		// -> in effect this means that the
		// scale and the translation to
		// keep the object fixed at the corner
		// opposite to the one being dragged
		// were transfered to the parent matrix
	t.TranslateBy(-pivot.x, -pivot.y);
		// and now the pivot is removed
		// (see AdvancedTransform::_UpdateMatrix()
		// for how the pivot is applied)

	// get the translation
	double translationX;
	double translationY;
	t.translation(&translationX, &translationY);

	// get the scale
	double newScaleX;
	double newScaleY;
	t.scaling(&newScaleX, &newScaleY);

	// operating on just the affine parameters is much more precise
	fParent->SetTranslationAndScale(BPoint(translationX, translationY),
		newScaleX, newScaleY);
}
void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit)
{
    ASSERT(paintInfo.shouldPaintWithinRoot(renderer()));
    ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection);
    ASSERT(truncation() == cNoTruncation);

    if (renderer()->style()->visibility() != VISIBLE)
        return;

    // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox.
    // If we ever need that for SVG, it's very easy to refactor and reuse the code.

    RenderObject* parentRenderer = parent()->renderer();
    ASSERT(parentRenderer);

    bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection;
    bool hasSelection = !parentRenderer->document().printing() && selectionState() != RenderObject::SelectionNone;
    if (!hasSelection && paintSelectedTextOnly)
        return;

    RenderSVGInlineText* textRenderer = toRenderSVGInlineText(this->textRenderer());
    ASSERT(textRenderer);
    if (!textShouldBePainted(textRenderer))
        return;

    RenderStyle* style = parentRenderer->style();
    ASSERT(style);

    paintDocumentMarkers(paintInfo.context, paintOffset, style, textRenderer->scaledFont(), true);

    const SVGRenderStyle* svgStyle = style->svgStyle();
    ASSERT(svgStyle);

    bool hasFill = svgStyle->hasFill();
    bool hasVisibleStroke = svgStyle->hasVisibleStroke();

    RenderStyle* selectionStyle = style;
    if (hasSelection) {
        selectionStyle = parentRenderer->getCachedPseudoStyle(SELECTION);
        if (selectionStyle) {
            const SVGRenderStyle* svgSelectionStyle = selectionStyle->svgStyle();
            ASSERT(svgSelectionStyle);

            if (!hasFill)
                hasFill = svgSelectionStyle->hasFill();
            if (!hasVisibleStroke)
                hasVisibleStroke = svgSelectionStyle->hasVisibleStroke();
        } else
            selectionStyle = style;
    }

    if (textRenderer->frame() && textRenderer->frame()->view() && textRenderer->frame()->view()->paintBehavior() & PaintBehaviorRenderingSVGMask) {
        hasFill = true;
        hasVisibleStroke = false;
    }

    AffineTransform fragmentTransform;
    unsigned textFragmentsSize = m_textFragments.size();
    for (unsigned i = 0; i < textFragmentsSize; ++i) {
        SVGTextFragment& fragment = m_textFragments.at(i);
        ASSERT(!m_paintingResource);

        GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
        fragment.buildFragmentTransform(fragmentTransform);
        if (!fragmentTransform.isIdentity()) {
            stateSaver.save();
            paintInfo.context->concatCTM(fragmentTransform);
        }

        // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations.
        unsigned decorations = style->textDecorationsInEffect();
        if (decorations & TextDecorationUnderline)
            paintDecoration(paintInfo.context, TextDecorationUnderline, fragment);
        if (decorations & TextDecorationOverline)
            paintDecoration(paintInfo.context, TextDecorationOverline, fragment);

        for (int i = 0; i < 3; i++) {
            switch (svgStyle->paintOrderType(i)) {
            case PT_FILL:
                // Fill text
                if (hasFill) {
                    m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode;
                    paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
                }
                break;
            case PT_STROKE:
                // Stroke text
                if (hasVisibleStroke) {
                    m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode;
                    paintText(paintInfo.context, style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly);
                }
                break;
            case PT_MARKERS:
                // Markers don't apply to text
                break;
            default:
                ASSERT_NOT_REACHED();
                break;
            }
        }

        // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text.
        if (decorations & TextDecorationLineThrough)
            paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment);

        m_paintingResourceMode = ApplyToDefaultMode;
    }

    ASSERT(!m_paintingResource);
}
Exemplo n.º 20
0
static inline void normalizeTransform(AffineTransform& transform)
{
    // Obtain consistent numerical results for the AffineTransform on both 32/64bit platforms.
    // Tested with SnowLeopard on Core Duo vs. Core 2 Duo.
    static const float s_floatEpsilon = std::numeric_limits<float>::epsilon();

    if (fabs(transform.a() - 1) <= s_floatEpsilon)
        transform.setA(1);
    else if (fabs(transform.a() + 1) <= s_floatEpsilon)
        transform.setA(-1);

    if (fabs(transform.d() - 1) <= s_floatEpsilon)
        transform.setD(1);
    else if (fabs(transform.d() + 1) <= s_floatEpsilon)
        transform.setD(-1);

    if (fabs(transform.e()) <= s_floatEpsilon)
        transform.setE(0);

    if (fabs(transform.f()) <= s_floatEpsilon)
        transform.setF(0);
}
Exemplo n.º 21
0
PatternData* RenderSVGResourcePattern::buildPattern(RenderElement& renderer, unsigned short resourceMode, GraphicsContext& context)
{
    PatternData* currentData = m_patternMap.get(&renderer);
    if (currentData && currentData->pattern)
        return currentData;

    if (m_shouldCollectPatternAttributes) {
        patternElement().synchronizeAnimatedSVGAttribute(anyQName());

        m_attributes = PatternAttributes();
        patternElement().collectPatternAttributes(m_attributes);
        m_shouldCollectPatternAttributes = false;
    }

    // If we couldn't determine the pattern content element root, stop here.
    if (!m_attributes.patternContentElement())
        return nullptr;

    // An empty viewBox disables rendering.
    if (m_attributes.hasViewBox() && m_attributes.viewBox().isEmpty())
        return nullptr;

    // Compute all necessary transformations to build the tile image & the pattern.
    FloatRect tileBoundaries;
    AffineTransform tileImageTransform;
    if (!buildTileImageTransform(renderer, m_attributes, patternElement(), tileBoundaries, tileImageTransform))
        return nullptr;

    AffineTransform absoluteTransformIgnoringRotation = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer);

    // Ignore 2D rotation, as it doesn't affect the size of the tile.
    SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
    FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries);
    FloatRect clampedAbsoluteTileBoundaries;

    // Scale the tile size to match the scale level of the patternTransform.
    absoluteTileBoundaries.scale(static_cast<float>(m_attributes.patternTransform().xScale()),
        static_cast<float>(m_attributes.patternTransform().yScale()));

    // Build tile image.
    auto tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries, context.isAcceleratedContext() ? Accelerated : Unaccelerated);
    if (!tileImage)
        return nullptr;

    RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore);
    if (!copiedImage)
        return nullptr;

    // Build pattern.
    auto patternData = std::make_unique<PatternData>();
    patternData->pattern = Pattern::create(copiedImage, true, true);

    // Compute pattern space transformation.
    const IntSize tileImageSize = tileImage->logicalSize();
    patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
    patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height());

    AffineTransform patternTransform = m_attributes.patternTransform();
    if (!patternTransform.isIdentity())
        patternData->transform = patternTransform * patternData->transform;

    // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows.
    if (resourceMode & ApplyToTextMode) {
        AffineTransform additionalTextTransformation;
        if (shouldTransformOnTextPainting(renderer, additionalTextTransformation))
            patternData->transform *= additionalTextTransformation;
    }
    patternData->pattern->setPatternSpaceTransform(patternData->transform);

    // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation
    // failures in the SVG image cache for example). To avoid having our PatternData deleted by
    // removeAllClientsFromCache(), we only make it visible in the cache at the very end.
    return m_patternMap.set(&renderer, WTF::move(patternData)).iterator->value.get();
}
PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(PatternData* patternData,
                                                                  const SVGPatternElement* patternElement,
                                                                  RenderObject* object) const
{
    PatternAttributes attributes = patternElement->collectPatternProperties();

    // If we couldn't determine the pattern content element root, stop here.
    if (!attributes.patternContentElement())
        return 0;

    FloatRect objectBoundingBox = object->objectBoundingBox();    
    FloatRect patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); 
    AffineTransform patternTransform = attributes.patternTransform();

    AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(patternElement->viewBox(),
                                                                        patternElement->preserveAspectRatio(),
                                                                        patternBoundaries.width(),
                                                                        patternBoundaries.height());

    FloatRect patternBoundariesIncludingOverflow = calculatePatternBoundariesIncludingOverflow(attributes,
                                                                                               objectBoundingBox,
                                                                                               viewBoxCTM,
                                                                                               patternBoundaries);

    IntSize imageSize(lroundf(patternBoundariesIncludingOverflow.width()), lroundf(patternBoundariesIncludingOverflow.height()));

    // FIXME: We should be able to clip this more, needs investigation
    clampImageBufferSizeToViewport(object->document()->view(), imageSize);

    // Don't create ImageBuffers with image size of 0
    if (imageSize.isEmpty())
        return 0;

    OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(imageSize);

    GraphicsContext* context = tileImage->context();
    ASSERT(context);

    context->save();

    // Translate to pattern start origin
    if (patternBoundariesIncludingOverflow.location() != patternBoundaries.location()) {
        context->translate(patternBoundaries.x() - patternBoundariesIncludingOverflow.x(),
                           patternBoundaries.y() - patternBoundariesIncludingOverflow.y());

        patternBoundaries.setLocation(patternBoundariesIncludingOverflow.location());
    }

    // Process viewBox or boundingBoxModeContent correction
    if (!viewBoxCTM.isIdentity())
        context->concatCTM(viewBoxCTM);
    else if (attributes.boundingBoxModeContent()) {
        context->translate(objectBoundingBox.x(), objectBoundingBox.y());
        context->scale(FloatSize(objectBoundingBox.width(), objectBoundingBox.height()));
    }

    // Render subtree into ImageBuffer
    for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
        if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
            continue;
        renderSubtreeToImage(tileImage.get(), node->renderer());
    }

    patternData->boundaries = patternBoundaries;

    // Compute pattern transformation
    patternData->transform.translate(patternBoundaries.x(), patternBoundaries.y());
    patternData->transform.multiply(patternTransform);

    context->restore();
    return tileImage.release();
}
Exemplo n.º 23
0
bool SVGClipPainter::prepareEffect(const LayoutObject& target, const FloatRect& targetBoundingBox,
    const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState)
{
    ASSERT(context);
    ASSERT(clipperState == ClipperNotApplied);
    ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout());

    m_clip.clearInvalidationMask();

    if (paintInvalidationRect.isEmpty() || m_clip.hasCycle())
        return false;

    SVGClipExpansionCycleHelper inClipExpansionChange(m_clip);

    AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element())->calculateAnimatedLocalTransform();
    // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor.
    // In this case, we need to apply the zoom scale explicitly - but only for clips with
    // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths).
    if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
        ASSERT(m_clip.style());
        animatedLocalTransform.scale(m_clip.style()->effectiveZoom());
    }

    // First, try to apply the clip as a clipPath.
    Path clipPath;
    if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) {
        clipperState = ClipperAppliedPath;
        ASSERT(context->displayItemList());
        context->displayItemList()->createAndAppend<BeginClipPathDisplayItem>(target, clipPath);
        return true;
    }

    // Fall back to masking.
    clipperState = ClipperAppliedMask;

    // Begin compositing the clip mask.
    CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcOver_Mode, 1, &paintInvalidationRect);
    {
        TransformRecorder recorder(*context, target, animatedLocalTransform);

        // clipPath can also be clipped by another clipPath.
        SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_clip);
        LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0;
        ClipperState clipPathClipperState = ClipperNotApplied;
        if (clipPathClipper && !SVGClipPainter(*clipPathClipper).prepareEffect(m_clip, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) {
            // End the clip mask's compositor.
            CompositingRecorder::endCompositing(*context, target);
            return false;
        }

        drawClipMaskContent(context, target, targetBoundingBox, paintInvalidationRect);

        if (clipPathClipper)
            SVGClipPainter(*clipPathClipper).finishEffect(m_clip, context, clipPathClipperState);
    }

    // Masked content layer start.
    CompositingRecorder::beginCompositing(*context, target, SkXfermode::kSrcIn_Mode, 1, &paintInvalidationRect);

    return true;
}
void CanvasRenderingContext2DState::setTransform(const AffineTransform& transform)
{
    m_isTransformInvertible = transform.isInvertible();
    m_transform = transform;
}
Exemplo n.º 25
0
void SimilarityTransform::applyToImage(const IplImage * sourceIm, IplImage * destIm) const
{
    AffineTransform * pAT = getAffineTransform();
    pAT->applyToImage(sourceIm, destIm);
    delete pAT;
}
Exemplo n.º 26
0
FloatPoint FloatPoint::matrixTransform(const AffineTransform& transform) const
{
    double newX, newY;
    transform.map(static_cast<double>(m_x), static_cast<double>(m_y), newX, newY);
    return narrowPrecision(newX, newY);
}
Exemplo n.º 27
0
void SimilarityTransform::applyToPoints(const CvMat * positions, CvMat * newPositions) const
{
    AffineTransform * pAT = getAffineTransform();
    pAT->applyToPoints(positions, newPositions);
    delete pAT;
}
PassRefPtr<const SkPicture> LayoutSVGResourceClipper::createContentPicture(AffineTransform& contentTransformation, const FloatRect& targetBoundingBox,
    GraphicsContext& context)
{
    ASSERT(frame());

    if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
        contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
        contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
    }

    if (m_clipContentPicture)
        return m_clipContentPicture;

    SubtreeContentTransformScope contentTransformScope(contentTransformation);

    // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection
    // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and
    // userSpaceOnUse units (http://crbug.com/294900).
    FloatRect bounds = strokeBoundingBox();

    SkPictureBuilder pictureBuilder(bounds, nullptr, &context);

    for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
        LayoutObject* layoutObject = childElement->layoutObject();
        if (!layoutObject)
            continue;

        const ComputedStyle* style = layoutObject->style();
        if (!style || style->display() == NONE || style->visibility() != VISIBLE)
            continue;

        bool isUseElement = isSVGUseElement(*childElement);
        if (isUseElement) {
            const SVGGraphicsElement* clippingElement = toSVGUseElement(*childElement).targetGraphicsElementForClipping();
            if (!clippingElement)
                continue;

            layoutObject = clippingElement->layoutObject();
            if (!layoutObject)
                continue;
        }

        // Only shapes, paths and texts are allowed for clipping.
        if (!layoutObject->isSVGShape() && !layoutObject->isSVGText())
            continue;

        if (isUseElement)
            layoutObject = childElement->layoutObject();

        // Switch to a paint behavior where all children of this <clipPath> will be laid out using special constraints:
        // - fill-opacity/stroke-opacity/opacity set to 1
        // - masker/filter not applied when laying out the children
        // - fill is set to the initial fill paint server (solid, black)
        // - stroke is set to the initial stroke paint server (none)
        PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, GlobalPaintNormalPhase, PaintLayerPaintingRenderingClipPathAsMask);
        layoutObject->paint(info, IntPoint());
    }

    m_clipContentPicture = pictureBuilder.endRecording();
    return m_clipContentPicture;
}
Exemplo n.º 29
0
bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepaintRect, const AffineTransform& localTransform, const PaintInfo& paintInfo)
{
    return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect);
}
AffineTransform SVGPreserveAspectRatio::getCTM(float logicalX, float logicalY, float logicalWidth, float logicalHeight, float physicalWidth, float physicalHeight) const
{
    AffineTransform transform;
    if (m_align == SVG_PRESERVEASPECTRATIO_UNKNOWN)
        return transform;

    double extendedLogicalX = logicalX;
    double extendedLogicalY = logicalY;
    double extendedLogicalWidth = logicalWidth;
    double extendedLogicalHeight = logicalHeight;
    double extendedPhysicalWidth = physicalWidth;
    double extendedPhysicalHeight = physicalHeight;
    double logicalRatio = extendedLogicalWidth / extendedLogicalHeight;
    double physicalRatio = extendedPhysicalWidth / extendedPhysicalHeight;

    if (m_align == SVG_PRESERVEASPECTRATIO_NONE) {
        transform.scaleNonUniform(extendedPhysicalWidth / extendedLogicalWidth, extendedPhysicalHeight / extendedLogicalHeight);
        transform.translate(-extendedLogicalX, -extendedLogicalY);
        return transform;
    }

    if ((logicalRatio < physicalRatio && (m_meetOrSlice == SVG_MEETORSLICE_MEET)) || (logicalRatio >= physicalRatio && (m_meetOrSlice == SVG_MEETORSLICE_SLICE))) {
        transform.scaleNonUniform(extendedPhysicalHeight / extendedLogicalHeight, extendedPhysicalHeight / extendedLogicalHeight);

        if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMINYMID || m_align == SVG_PRESERVEASPECTRATIO_XMINYMAX)
            transform.translate(-extendedLogicalX, -extendedLogicalY);
        else if (m_align == SVG_PRESERVEASPECTRATIO_XMIDYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMID || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMAX)
            transform.translate(-extendedLogicalX - (extendedLogicalWidth - extendedPhysicalWidth * extendedLogicalHeight / extendedPhysicalHeight) / 2, -extendedLogicalY);
        else
            transform.translate(-extendedLogicalX - (extendedLogicalWidth - extendedPhysicalWidth * extendedLogicalHeight / extendedPhysicalHeight), -extendedLogicalY);

        return transform;
    }

    transform.scaleNonUniform(extendedPhysicalWidth / extendedLogicalWidth, extendedPhysicalWidth / extendedLogicalWidth);

    if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMAXYMIN)
        transform.translate(-extendedLogicalX, -extendedLogicalY);
    else if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMID || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMID || m_align == SVG_PRESERVEASPECTRATIO_XMAXYMID)
        transform.translate(-extendedLogicalX, -extendedLogicalY - (extendedLogicalHeight - extendedPhysicalHeight * extendedLogicalWidth / extendedPhysicalWidth) / 2);
    else
        transform.translate(-extendedLogicalX, -extendedLogicalY - (extendedLogicalHeight - extendedPhysicalHeight * extendedLogicalWidth / extendedPhysicalWidth));

    return transform;
}