void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
                                      const FloatRect& dstRect,
                                      const FloatRect& srcRect,
                                      ColorSpace styleColorSpace,
                                      CompositeOperator compositeOp)
{
    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

    if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
        drawBitmapGLES2(ctxt, &m_nativeImage, srcRect, dstRect, styleColorSpace, compositeOp);
        return;
    }

    ctxt->platformContext()->prepareForSoftwareDraw();

    paintSkBitmap(ctxt->platformContext(),
                  m_nativeImage,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));
}
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
{
    if (paintingDisabled())
        return;

    platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
}
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
                       const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return;  // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

    if (ctxt->platformContext()->useGPU() && ctxt->platformContext()->canAccelerate()) {
        drawBitmapGLES2(ctxt, bm, normSrcRect, normDstRect, colorSpace, compositeOp);
        return;
    }

    ctxt->platformContext()->prepareForSoftwareDraw();

    paintSkBitmap(ctxt->platformContext(),
                  *bm,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));
}
Beispiel #4
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
                       const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return; // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    paintSkBitmap(ctxt->platformContext(),
        *bm,
        normSrcRect,
        normDstRect,
        WebCoreCompositeToSkiaComposite(compositeOp));

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}
void GraphicsContextState::setCompositeOperation(CompositeOperator compositeOperation, WebBlendMode blendMode)
{
    m_compositeOperator = compositeOperation;
    m_blendMode = blendMode;
    SkXfermode::Mode xferMode = WebCoreCompositeToSkiaComposite(compositeOperation, blendMode);
    m_strokePaint.setXfermodeMode(xferMode);
    m_fillPaint.setXfermodeMode(xferMode);
}
Beispiel #6
0
PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder* builder)
{
    RefPtr<SkImageFilter> foreground(builder->build(inputEffect(0), operatingColorSpace()));
    RefPtr<SkImageFilter> background(builder->build(inputEffect(1), operatingColorSpace()));
    RefPtr<SkXfermode> mode(adoptRef(SkXfermode::Create(WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_mode))));
    SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset());
    return adoptRef(SkXfermodeImageFilter::Create(mode.get(), background.get(), foreground.get(), &cropRect));
}
PassRefPtr<SkImageFilter> FEBlend::createImageFilter(SkiaImageFilterBuilder& builder)
{
    RefPtr<SkImageFilter> foreground(builder.build(inputEffect(0), operatingColorSpace()));
    RefPtr<SkImageFilter> background(builder.build(inputEffect(1), operatingColorSpace()));
    sk_sp<SkXfermode> mode(SkXfermode::Make(WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_mode)));
    SkImageFilter::CropRect cropRect = getCropRect();
    return fromSkSp(SkXfermodeImageFilter::Make(std::move(mode), background.get(), foreground.get(), &cropRect));
}
Beispiel #8
0
void GraphicsContext::setCompositeOperation(CompositeOperator op)
{
    if (paintingDisabled())
        return;

    if (platformContext()->useGPU())
        platformContext()->gpuCanvas()->setCompositeOperation(op);

    platformContext()->setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
}
void PlatformGraphicsContextSkia::drawBitmapRect(const SkBitmap& bitmap,
                                             const SkIRect* src, const SkRect& dst,
                                             CompositeOperator op)
{
    SkPaint paint;
    setupPaintCommon(&paint);
    paint.setAlpha(getNormalizedAlpha());
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(op));
    fixPaintForBitmapsThatMaySeam(&paint);

    mCanvas->drawBitmapRect(bitmap, src, dst, &paint);
}
Beispiel #10
0
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace colorSpace, CompositeOperator compositeOp, RespectImageOrientationEnum shouldRespectImageOrientation)
{
    if (!m_source.initialized())
        return;

    // Spin the animation to the correct frame before we try to draw it, so we
    // don't draw an old frame and then immediately need to draw a newer one,
    // causing flicker and wasting CPU.
    startAnimation();

    NativeImageSkia* bm = nativeImageForCurrentFrame();
    if (!bm)
        return; // It's too early and we don't have an image yet.

    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);
    normSrcRect.intersect(FloatRect(0, 0, bm->bitmap().width(), bm->bitmap().height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    ImageOrientation orientation = DefaultImageOrientation;
    if (shouldRespectImageOrientation == RespectImageOrientation)
        orientation = frameOrientationAtIndex(m_currentFrame);

    GraphicsContextStateSaver saveContext(*ctxt, false);
    if (orientation != DefaultImageOrientation) {
        saveContext.save();

        // ImageOrientation expects the origin to be at (0, 0)
        ctxt->translate(normDstRect.x(), normDstRect.y());
        normDstRect.setLocation(FloatPoint());

        ctxt->concatCTM(orientation.transformFromDefault(normDstRect.size()));

        if (orientation.usesWidthAsHeight()) {
            // The destination rect will have it's width and height already reversed for the orientation of
            // the image, as it was needed for page layout, so we need to reverse it back here.
            normDstRect = FloatRect(normDstRect.x(), normDstRect.y(), normDstRect.height(), normDstRect.width());
        }
    }

    paintSkBitmap(ctxt->platformContext(),
        *bm,
        normSrcRect,
        normDstRect,
        WebCoreCompositeToSkiaComposite(compositeOp));

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}
void PlatformGraphicsContextSkia::drawBitmapPattern(
        const SkBitmap& bitmap, const SkMatrix& matrix,
        CompositeOperator compositeOp, const FloatRect& destRect)
{
    SkShader* shader = SkShader::CreateBitmapShader(bitmap,
                                                    SkShader::kRepeat_TileMode,
                                                    SkShader::kRepeat_TileMode);
    shader->setLocalMatrix(matrix);
    SkPaint paint;
    setupPaintCommon(&paint);
    paint.setAlpha(getNormalizedAlpha());
    paint.setShader(shader)->unref();
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
    fixPaintForBitmapsThatMaySeam(&paint);
    mCanvas->drawRect(destRect, paint);
}
Beispiel #12
0
void SVGPaintContext::applyCompositingIfNecessary() {
  DCHECK(!paintInfo().isRenderingClipPathAsMaskImage());

  const ComputedStyle& style = m_object.styleRef();
  float opacity = style.opacity();
  WebBlendMode blendMode = style.hasBlendMode() && m_object.isBlendingAllowed()
                               ? style.blendMode()
                               : WebBlendModeNormal;
  if (opacity < 1 || blendMode != WebBlendModeNormal) {
    const FloatRect compositingBounds =
        m_object.visualRectInLocalSVGCoordinates();
    m_compositingRecorder = WTF::wrapUnique(new CompositingRecorder(
        paintInfo().context, m_object,
        WebCoreCompositeToSkiaComposite(CompositeSourceOver, blendMode),
        opacity, &compositingBounds));
  }
}
Beispiel #13
0
void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
                                      const FloatRect& dstRect,
                                      const FloatRect& srcRect,
                                      ColorSpace styleColorSpace,
                                      CompositeOperator compositeOp)
{
    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return;  // Nothing to draw.

    paintSkBitmap(ctxt->platformContext(),
                  m_nativeImage,
                  enclosingIntRect(normSrcRect),
                  normDstRect,
                  WebCoreCompositeToSkiaComposite(compositeOp));
}
void SVGPaintContext::applyCompositingIfNecessary()
{
    ASSERT(!m_paintInfo.isRenderingClipPathAsMaskImage());

    // Layer takes care of root opacity and blend mode.
    if (m_object->isSVGRoot())
        return;

    const ComputedStyle& style = m_object->styleRef();
    float opacity = style.opacity();
    WebBlendMode blendMode = style.hasBlendMode() && m_object->isBlendingAllowed() ?
        style.blendMode() : WebBlendModeNormal;
    if (opacity < 1 || blendMode != WebBlendModeNormal) {
        const FloatRect compositingBounds = m_object->paintInvalidationRectInLocalCoordinates();
        m_compositingRecorder = adoptPtr(new CompositingRecorder(*m_paintInfo.context, *m_object,
            WebCoreCompositeToSkiaComposite(CompositeSourceOver, blendMode), opacity, &compositingBounds));
    }
}
Beispiel #15
0
void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
                                      const FloatRect& dstRect,
                                      const FloatRect& srcRect,
                                      ColorSpace styleColorSpace,
                                      CompositeOperator compositeOp)
{
    FloatRect normDstRect = normalizeRect(dstRect);
    FloatRect normSrcRect = normalizeRect(srcRect);
    normSrcRect.intersect(FloatRect(0, 0, m_nativeImage.bitmap().width(), m_nativeImage.bitmap().height()));

    if (normSrcRect.isEmpty() || normDstRect.isEmpty())
        return; // Nothing to draw.

    paintSkBitmap(ctxt->platformContext(),
        m_nativeImage,
        normSrcRect,
        normDstRect,
        WebCoreCompositeToSkiaComposite(compositeOp));

    if (ImageObserver* observer = imageObserver())
        observer->didDraw(this);
}
PaintLayerPainter::PaintResult PaintLayerPainter::paintLayerContentsInternal(GraphicsContext* context, const PaintLayerPaintingInfo& paintingInfoArg, PaintLayerFlags paintFlags, FragmentPolicy fragmentPolicy)
{
    ASSERT(m_paintLayer.isSelfPaintingLayer() || m_paintLayer.hasSelfPaintingLayerDescendant());
    ASSERT(!(paintFlags & PaintLayerAppliedTransform));

    bool isSelfPaintingLayer = m_paintLayer.isSelfPaintingLayer();
    bool isPaintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
    bool isPaintingScrollingContent = paintFlags & PaintLayerPaintingCompositingScrollingPhase;
    bool isPaintingCompositedForeground = paintFlags & PaintLayerPaintingCompositingForegroundPhase;
    bool isPaintingCompositedBackground = paintFlags & PaintLayerPaintingCompositingBackgroundPhase;
    bool isPaintingOverflowContents = paintFlags & PaintLayerPaintingOverflowContents;
    // Outline always needs to be painted even if we have no visible content. Also,
    // the outline is painted in the background phase during composited scrolling.
    // If it were painted in the foreground phase, it would move with the scrolled
    // content. When not composited scrolling, the outline is painted in the
    // foreground phase. Since scrolled contents are moved by paint invalidation in this
    // case, the outline won't get 'dragged along'.
    bool shouldPaintOutline = isSelfPaintingLayer && !isPaintingOverlayScrollbars
        && ((isPaintingScrollingContent && isPaintingCompositedBackground)
        || (!isPaintingScrollingContent && isPaintingCompositedForeground));
    bool shouldPaintContent = m_paintLayer.hasVisibleContent() && isSelfPaintingLayer && !isPaintingOverlayScrollbars;

    PaintResult result = FullyPainted;

    if (paintFlags & PaintLayerPaintingRootBackgroundOnly && !m_paintLayer.layoutObject()->isLayoutView() && !m_paintLayer.layoutObject()->isDocumentElement())
        return result;

    PaintLayerPaintingInfo paintingInfo = paintingInfoArg;

    // Ensure our lists are up-to-date.
    m_paintLayer.stackingNode()->updateLayerListsIfNeeded();

    LayoutPoint offsetFromRoot;
    m_paintLayer.convertToLayerCoords(paintingInfo.rootLayer, offsetFromRoot);

    if (m_paintLayer.compositingState() == PaintsIntoOwnBacking)
        offsetFromRoot.move(m_paintLayer.subpixelAccumulation());
    else
        offsetFromRoot.move(paintingInfo.subPixelAccumulation);

    LayoutRect bounds = m_paintLayer.physicalBoundingBox(offsetFromRoot);
    if (!paintingInfo.paintDirtyRect.contains(bounds))
        result = MaybeNotFullyPainted;

    LayoutRect rootRelativeBounds;
    bool rootRelativeBoundsComputed = false;

    if (paintingInfo.ancestorHasClipPathClipping && m_paintLayer.layoutObject()->style()->position() != StaticPosition)
        UseCounter::count(m_paintLayer.layoutObject()->document(), UseCounter::ClipPathOfPositionedElement);

    // These helpers output clip and compositing operations using a RAII pattern. Stack-allocated-varibles are destructed in the reverse order of construction,
    // so they are nested properly.
    ClipPathHelper clipPathHelper(context, m_paintLayer, paintingInfo, rootRelativeBounds, rootRelativeBoundsComputed, offsetFromRoot, paintFlags);

    Optional<CompositingRecorder> compositingRecorder;
    // Blending operations must be performed only with the nearest ancestor stacking context.
    // Note that there is no need to composite if we're painting the root.
    // FIXME: this should be unified further into PaintLayer::paintsWithTransparency().
    bool shouldCompositeForBlendMode = (!m_paintLayer.layoutObject()->isDocumentElement() || m_paintLayer.layoutObject()->isSVGRoot()) && m_paintLayer.stackingNode()->isStackingContext() && m_paintLayer.hasNonIsolatedDescendantWithBlendMode();
    if (shouldCompositeForBlendMode || m_paintLayer.paintsWithTransparency(paintingInfo.globalPaintFlags())) {
        FloatRect compositingBounds = FloatRect(m_paintLayer.paintingExtent(paintingInfo.rootLayer, paintingInfo.subPixelAccumulation, paintingInfo.globalPaintFlags()));
        compositingRecorder.emplace(*context, *m_paintLayer.layoutObject(),
            WebCoreCompositeToSkiaComposite(CompositeSourceOver, m_paintLayer.layoutObject()->style()->blendMode()),
            m_paintLayer.layoutObject()->opacity(), &compositingBounds);
    }

    PaintLayerPaintingInfo localPaintingInfo(paintingInfo);
    if (m_paintLayer.compositingState() == PaintsIntoOwnBacking)
        localPaintingInfo.subPixelAccumulation = m_paintLayer.subpixelAccumulation();

    PaintLayerFragments layerFragments;
    if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) {
        // Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment.
        ClipRectsCacheSlot cacheSlot = (paintFlags & PaintLayerUncachedClipRects) ? UncachedClipRects : PaintingClipRects;
        ShouldRespectOverflowClip respectOverflowClip = shouldRespectOverflowClip(paintFlags, m_paintLayer.layoutObject());
        if (fragmentPolicy == ForceSingleFragment)
            m_paintLayer.appendSingleFragmentIgnoringPagination(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation);
        else
            m_paintLayer.collectFragments(layerFragments, localPaintingInfo.rootLayer, localPaintingInfo.paintDirtyRect, cacheSlot, IgnoreOverlayScrollbarSize, respectOverflowClip, &offsetFromRoot, localPaintingInfo.subPixelAccumulation);
        if (shouldPaintContent) {
            // TODO(wangxianzhu): This is for old slow scrolling. Implement similar optimization for slimming paint v2.
            shouldPaintContent = atLeastOneFragmentIntersectsDamageRect(layerFragments, localPaintingInfo, paintFlags, offsetFromRoot);
            if (!shouldPaintContent)
                result = MaybeNotFullyPainted;
        }
    }

    bool selectionOnly = localPaintingInfo.globalPaintFlags() & GlobalPaintSelectionOnly;
    // If this layer's layoutObject is a child of the paintingRoot, we paint unconditionally, which
    // is done by passing a nil paintingRoot down to our layoutObject (as if no paintingRoot was ever set).
    // Else, our layout tree may or may not contain the painting root, so we pass that root along
    // so it will be tested against as we descend through the layoutObjects.
    LayoutObject* paintingRootForLayoutObject = 0;
    if (localPaintingInfo.paintingRoot && !m_paintLayer.layoutObject()->isDescendantOf(localPaintingInfo.paintingRoot))
        paintingRootForLayoutObject = localPaintingInfo.paintingRoot;

    { // Begin block for the lifetime of any filter.
        FilterPainter filterPainter(m_paintLayer, context, offsetFromRoot, layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect, localPaintingInfo, paintFlags,
            rootRelativeBounds, rootRelativeBoundsComputed);

        bool shouldPaintBackground = isPaintingCompositedBackground && shouldPaintContent && !selectionOnly;
        bool shouldPaintNegZOrderList = (isPaintingScrollingContent && isPaintingOverflowContents) || (!isPaintingScrollingContent && isPaintingCompositedBackground);
        bool shouldPaintOwnContents = isPaintingCompositedForeground && shouldPaintContent;
        bool shouldPaintNormalFlowAndPosZOrderLists = isPaintingCompositedForeground;
        bool shouldPaintOverlayScrollbars = isPaintingOverlayScrollbars;

        if (shouldPaintBackground) {
            paintBackgroundForFragments(layerFragments, context, paintingInfo.paintDirtyRect,
                localPaintingInfo, paintingRootForLayoutObject, paintFlags);
        }

        if (shouldPaintNegZOrderList) {
            if (paintChildren(NegativeZOrderChildren, context, paintingInfo, paintFlags) == MaybeNotFullyPainted)
                result = MaybeNotFullyPainted;
        }

        if (shouldPaintOwnContents) {
            paintForegroundForFragments(layerFragments, context, paintingInfo.paintDirtyRect,
                localPaintingInfo, paintingRootForLayoutObject, selectionOnly, paintFlags);
        }

        if (shouldPaintOutline)
            paintOutlineForFragments(layerFragments, context, localPaintingInfo, paintingRootForLayoutObject, paintFlags);

        if (shouldPaintNormalFlowAndPosZOrderLists) {
            if (paintChildren(NormalFlowChildren | PositiveZOrderChildren, context, paintingInfo, paintFlags) == MaybeNotFullyPainted)
                result = MaybeNotFullyPainted;
        }

        if (shouldPaintOverlayScrollbars)
            paintOverflowControlsForFragments(layerFragments, context, localPaintingInfo, paintFlags);
    } // FilterPainter block

    bool shouldPaintMask = (paintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && m_paintLayer.layoutObject()->hasMask() && !selectionOnly;
    bool shouldPaintClippingMask = (paintFlags & PaintLayerPaintingChildClippingMaskPhase) && shouldPaintContent && !selectionOnly;

    if (shouldPaintMask)
        paintMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForLayoutObject, paintFlags);
    if (shouldPaintClippingMask) {
        // Paint the border radius mask for the fragments.
        paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, paintingRootForLayoutObject, paintFlags);
    }

    m_paintLayer.setPreviousScrollOffsetAccumulationForPainting(paintingInfoArg.scrollOffsetAccumulation);

    return result;
}
Beispiel #17
0
void Image::drawPattern(GraphicsContext* context,
                        const FloatRect& floatSrcRect,
                        const AffineTransform& patternTransform,
                        const FloatPoint& phase,
                        ColorSpace styleColorSpace,
                        CompositeOperator compositeOp,
                        const FloatRect& destRect)
{
#if PLATFORM(CHROMIUM)
    TRACE_EVENT0("skia", "Image::drawPattern");
#endif
    FloatRect normSrcRect = normalizeRect(floatSrcRect);
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    NativeImageSkia* bitmap = nativeImageForCurrentFrame();
    if (!bitmap)
        return;

    SkMatrix ctm = context->platformContext()->canvas()->getTotalMatrix();
    SkMatrix totalMatrix;
    totalMatrix.setConcat(ctm, patternTransform);

    // Figure out what size the bitmap will be in the destination. The
    // destination rect is the bounds of the pattern, we need to use the
    // matrix to see how big it will be.
    SkRect destRectTarget;
    totalMatrix.mapRect(&destRectTarget, normSrcRect);

    float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
    float destBitmapHeight = SkScalarToFloat(destRectTarget.height());

    // Compute the resampling mode.
    ResamplingMode resampling;
    if (context->platformContext()->isAccelerated() || context->platformContext()->printing())
        resampling = RESAMPLE_LINEAR;
    else
        resampling = computeResamplingMode(totalMatrix, *bitmap, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight);
    resampling = limitResamplingMode(context->platformContext(), resampling);

    // Load the transform WebKit requested.
    SkMatrix matrix(patternTransform);

    SkShader* shader;
    if (resampling == RESAMPLE_AWESOME) {
        // Do nice resampling.
        float scaleX = destBitmapWidth / normSrcRect.width();
        float scaleY = destBitmapHeight / normSrcRect.height();
        SkRect scaledSrcRect;
        SkIRect enclosingScaledSrcRect;

        // The image fragment generated here is not exactly what is
        // requested. The scale factor used is approximated and image
        // fragment is slightly larger to align to integer
        // boundaries.
        SkBitmap resampled = extractScaledImageFragment(*bitmap, normSrcRect, scaleX, scaleY, &scaledSrcRect, &enclosingScaledSrcRect);
        shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);

        // Since we just resized the bitmap, we need to remove the scale
        // applied to the pixels in the bitmap shader. This means we need
        // CTM * patternTransform to have identity scale. Since we
        // can't modify CTM (or the rectangle will be drawn in the wrong
        // place), we must set patternTransform's scale to the inverse of
        // CTM scale.
        matrix.setScaleX(ctm.getScaleX() ? 1 / ctm.getScaleX() : 1);
        matrix.setScaleY(ctm.getScaleY() ? 1 / ctm.getScaleY() : 1);
    } else {
        // No need to do nice resampling.
        SkBitmap srcSubset;
        bitmap->bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
        shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
    }

    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the patter. If WebKit wants
    // a shifted image, it will shift it from there using the patternTransform.
    float adjustedX = phase.x() + normSrcRect.x() *
                      narrowPrecisionToFloat(patternTransform.a());
    float adjustedY = phase.y() + normSrcRect.y() *
                      narrowPrecisionToFloat(patternTransform.d());
    matrix.postTranslate(SkFloatToScalar(adjustedX),
                         SkFloatToScalar(adjustedY));
    shader->setLocalMatrix(matrix);

    SkPaint paint;
    paint.setShader(shader)->unref();
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
    paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);

    context->platformContext()->paintSkPaint(destRect, paint);
}
void NativeImageSkia::drawPattern(
    GraphicsContext* context,
    const FloatRect& floatSrcRect,
    const FloatSize& scale,
    const FloatPoint& phase,
    CompositeOperator compositeOp,
    const FloatRect& destRect,
    WebBlendMode blendMode,
    const IntSize& repeatSpacing) const
{
    FloatRect normSrcRect = floatSrcRect;
    normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height()));
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    SkMatrix totalMatrix = context->getTotalMatrix();
    AffineTransform ctm = context->getCTM();
    SkScalar ctmScaleX = ctm.xScale();
    SkScalar ctmScaleY = ctm.yScale();
    totalMatrix.preScale(scale.width(), scale.height());

    // Figure out what size the bitmap will be in the destination. The
    // destination rect is the bounds of the pattern, we need to use the
    // matrix to see how big it will be.
    SkRect destRectTarget;
    totalMatrix.mapRect(&destRectTarget, normSrcRect);

    float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
    float destBitmapHeight = SkScalarToFloat(destRectTarget.height());

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());

    // Compute the resampling mode.
    InterpolationQuality resampling;
    if (context->isAccelerated())
        resampling = InterpolationLow;
    else if (isLazyDecoded)
        resampling = InterpolationHigh;
    else
        resampling = computeInterpolationQuality(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight, isDataComplete());
    resampling = limitInterpolationQuality(context, resampling);

    SkMatrix localMatrix;
    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the pattern. If WebKit wants
    // a shifted image, it will shift it from there using the localMatrix.
    const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
    const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
    localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));

    RefPtr<SkShader> shader;
    SkFilterQuality filterLevel = static_cast<SkFilterQuality>(resampling);

    // Bicubic filter is only applied to defer-decoded images, see
    // NativeImageSkia::draw for details.
    if (resampling == InterpolationHigh && !isLazyDecoded) {
        // Do nice resampling.
        filterLevel = kNone_SkFilterQuality;
        float scaleX = destBitmapWidth / normSrcRect.width();
        float scaleY = destBitmapHeight / normSrcRect.height();
        SkRect scaledSrcRect;

        // Since we are resizing the bitmap, we need to remove the scale
        // applied to the pixels in the bitmap shader. This means we need
        // CTM * localMatrix to have identity scale. Since we
        // can't modify CTM (or the rectangle will be drawn in the wrong
        // place), we must set localMatrix's scale to the inverse of
        // CTM scale.
        localMatrix.preScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1);

        // The image fragment generated here is not exactly what is
        // requested. The scale factor used is approximated and image
        // fragment is slightly larger to align to integer
        // boundaries.
        SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect);
        if (repeatSpacing.isZero()) {
            shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        } else {
            shader = adoptRef(SkShader::CreateBitmapShader(
                createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        }
    } else {
        // Because no resizing occurred, the shader transform should be
        // set to the pattern's transform, which just includes scale.
        localMatrix.preScale(scale.width(), scale.height());

        // No need to resample before drawing.
        SkBitmap srcSubset;
        bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
        if (repeatSpacing.isZero()) {
            shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        } else {
            shader = adoptRef(SkShader::CreateBitmapShader(
                createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        }
    }

    SkPaint paint;
    paint.setShader(shader.get());
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode));
    paint.setColorFilter(context->colorFilter());
    paint.setFilterQuality(filterLevel);
    context->drawRect(destRect, paint);
}
void PlatformGraphicsContext::setCompositeOperation(CompositeOperator op)
{
    m_state->mode = WebCoreCompositeToSkiaComposite(op);
}
Beispiel #20
0
void Image::drawPattern(GraphicsContext* context,
                        const FloatRect& floatSrcRect,
                        const AffineTransform& patternTransform,
                        const FloatPoint& phase,
                        ColorSpace styleColorSpace,
                        CompositeOperator compositeOp,
                        const FloatRect& destRect)
{
    FloatRect normSrcRect = normalizeRect(floatSrcRect);
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    NativeImageSkia* bitmap = nativeImageForCurrentFrame();
    if (!bitmap)
        return;

    SkIRect srcRect = enclosingIntRect(normSrcRect);

    // Figure out what size the bitmap will be in the destination. The
    // destination rect is the bounds of the pattern, we need to use the
    // matrix to see how big it will be.
    float destBitmapWidth, destBitmapHeight;
    TransformDimensions(patternTransform, srcRect.width(), srcRect.height(),
                        &destBitmapWidth, &destBitmapHeight);

    // Compute the resampling mode.
    ResamplingMode resampling;
    if (context->platformContext()->isAccelerated() || context->platformContext()->printing())
        resampling = RESAMPLE_LINEAR;
    else
        resampling = computeResamplingMode(context->platformContext(), *bitmap, srcRect.width(), srcRect.height(), destBitmapWidth, destBitmapHeight);

    // Load the transform WebKit requested.
    SkMatrix matrix(patternTransform);

    SkShader* shader;
    if (resampling == RESAMPLE_AWESOME) {
        // Do nice resampling.
        int width = static_cast<int>(destBitmapWidth);
        int height = static_cast<int>(destBitmapHeight);
        SkBitmap resampled = bitmap->resizedBitmap(srcRect, width, height);
        shader = SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);

        // Since we just resized the bitmap, we need to undo the scale set in
        // the image transform.
        matrix.setScaleX(SkIntToScalar(1));
        matrix.setScaleY(SkIntToScalar(1));
    } else {
        // No need to do nice resampling.
        SkBitmap srcSubset;
        bitmap->bitmap().extractSubset(&srcSubset, srcRect);
        shader = SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
    }

    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the patter. If WebKit wants
    // a shifted image, it will shift it from there using the patternTransform.
    float adjustedX = phase.x() + normSrcRect.x() *
                      narrowPrecisionToFloat(patternTransform.a());
    float adjustedY = phase.y() + normSrcRect.y() *
                      narrowPrecisionToFloat(patternTransform.d());
    matrix.postTranslate(SkFloatToScalar(adjustedX),
                         SkFloatToScalar(adjustedY));
    shader->setLocalMatrix(matrix);

    SkPaint paint;
    paint.setShader(shader)->unref();
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp));
    paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);

    context->platformContext()->paintSkPaint(destRect, paint);
}