void
NinePatchGlue::drawStretchyPatch(SkCanvas& canvas, SkIRect& src, const SkRect& dst,
				 const BitmapGlue& bitmap, const PaintGlue& paint,
				 SkColor initColor, uint32_t colorHint,
				 bool hasXfer)
{
	if (colorHint !=  Res_png_9patch::NO_COLOR) {
		((PaintGlue*)&paint)->setColor(modAlpha(colorHint, paint.getAlpha()));
		canvas.drawRect(dst, paint);
		((PaintGlue*)&paint)->setColor(initColor);
	} else if (src.width() == 1 && src.height() == 1) {
		SkColor c;
		if (!getColor(bitmap, src.fLeft, src.fTop, &c)) {
			goto SLOW_CASE;
		}
		if (0 != c || hasXfer) {
			SkColor prev = paint.getColor();
			((PaintGlue*)&paint)->setColor(c);
			canvas.drawRect(dst, paint);
			((PaintGlue*)&paint)->setColor(prev);
		}
	} else {
	SLOW_CASE:
		canvas.drawBitmapRect(bitmap, &src, dst, &paint);
	}
}
    void paint(GraphicsContext* ctxt, const IntRect& r)
    {
        if (ctxt->paintingDisabled())
            return;

        if (!m_isVisible)
            return;

        if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef()))
            return;

        SkCanvas*   canvas = ctxt->platformContext()->getCanvas();
        if (!canvas)
            return;
        // We paint with the following rules in mind:
        // - only downscale the poster, never upscale
        // - maintain the natural aspect ratio of the poster
        // - the poster should be centered in the target rect
        float originalRatio = static_cast<float>(m_poster->width()) / static_cast<float>(m_poster->height());
        int posterWidth = r.width() > m_poster->width() ? m_poster->width() : r.width();
        int posterHeight = posterWidth / originalRatio;
        int posterX = ((r.width() - posterWidth) / 2) + r.x();
        int posterY = ((r.height() - posterHeight) / 2) + r.y();
        IntRect targetRect(posterX, posterY, posterWidth, posterHeight);
        canvas->drawBitmapRect(*m_poster, 0, targetRect, 0);
    }
Exemple #3
0
static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
{
    SkPaint paint;
    paint.setXfermodeMode(compOp);
    paint.setFilterBitmap(true);
    paint.setAlpha(platformContext->getNormalizedAlpha());
    paint.setLooper(platformContext->getDrawLooper());
    // only antialias if we're rotated or skewed
    paint.setAntiAlias(hasNon90rotation(platformContext));

    SkCanvas* canvas = platformContext->canvas();

    ResamplingMode resampling;
    if (platformContext->isAccelerated())
        resampling = RESAMPLE_LINEAR;
    else
        resampling = platformContext->printing() ? RESAMPLE_NONE :
            computeResamplingMode(platformContext, bitmap, srcRect.width(), srcRect.height(), SkScalarToFloat(destRect.width()), SkScalarToFloat(destRect.height()));
    if (resampling == RESAMPLE_AWESOME) {
        drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
    } else {
        // No resampling necessary, we can just draw the bitmap. We want to
        // filter it if we decided to do linear interpolation above, or if there
        // is something interesting going on with the matrix (like a rotation).
        // Note: for serialization, we will want to subset the bitmap first so
        // we don't send extra pixels.
        canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint);
    }
}
Exemple #4
0
ImageTexture::ImageTexture(SkBitmapRef* img)
    : m_imageRef(img)
    , m_image(0)
    , m_textureId(0)
    , m_refCount(0)
{
#ifdef DEBUG_COUNT
    ClassTracker::instance()->increment("ImageTexture");
#endif
    if (!m_imageRef)
        return;

    SkBitmap* bitmap = &m_imageRef->bitmap();
    m_image = new SkBitmap();
    int w = bitmap->width();
    int h = bitmap->height();
    m_image->setConfig(SkBitmap::kARGB_8888_Config, w, h);
    m_image->allocPixels();
    SkDevice* device = new SkDevice(NULL, *m_image, false);
    SkCanvas canvas;
    canvas.setDevice(device);
    device->unref();
    SkRect dest;
    dest.set(0, 0, w, h);
    m_image->setIsOpaque(false);
    m_image->eraseARGB(0, 0, 0, 0);
    canvas.drawBitmapRect(*bitmap, 0, dest);
}
Exemple #5
0
void TransparencyWin::compositeTextComposite()
{
    if (!m_validLayer)
        return;

    const SkBitmap& bitmap = m_layerBuffer->context()->platformContext()->canvas()->getTopDevice()->accessBitmap(true);
    SkColor textColor = m_textCompositeColor.rgb();
    for (int y = 0; y < m_layerSize.height(); y++) {
        uint32_t* row = bitmap.getAddr32(0, y);
        for (int x = 0; x < m_layerSize.width(); x++) {
            // The alpha is the average of the R, G, and B channels.
            int alpha = (SkGetPackedR32(row[x]) + SkGetPackedG32(row[x]) + SkGetPackedB32(row[x])) / 3;

            // Apply that alpha to the text color and write the result.
            row[x] = SkAlphaMulQ(textColor, SkAlpha255To256(255 - alpha));
        }
    }

    // Now the layer has text with the proper color and opacity.
    SkCanvas* destCanvas = canvasForContext(*m_destContext);
    destCanvas->save();

    // We want to use Untransformed space (see above)
    SkMatrix identity;
    identity.reset();
    destCanvas->setMatrix(identity);
    SkRect destRect = { m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY() };

    // Note that we need to specify the source layer subset, since the bitmap
    // may have been cached and it could be larger than what we're using.
    SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
    destCanvas->drawBitmapRect(bitmap, &sourceRect, destRect, 0);
    destCanvas->restore();
}
Exemple #6
0
// This does a lot of computation to resample only the portion of the bitmap
// that will only be drawn. This is critical for performance since when we are
// scrolling, for example, we are only drawing a small strip of the image.
// Resampling the whole image every time is very slow, so this speeds up things
// dramatically.
//
// Note: this code is only used when the canvas transformation is limited to
// scaling or translation.
static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkRect& srcRect, const SkRect& destRect)
{
#if PLATFORM(CHROMIUM)
    TRACE_EVENT0("skia", "drawResampledBitmap");
#endif
    // We want to scale |destRect| with transformation in the canvas to obtain
    // the final scale. The final scale is a combination of scale transform
    // in canvas and explicit scaling (srcRect and destRect).
    SkRect screenRect;
    canvas.getTotalMatrix().mapRect(&screenRect, destRect);
    float realScaleX = screenRect.width() / srcRect.width();
    float realScaleY = screenRect.height() / srcRect.height();

    // This part of code limits scaling only to visible portion in the
    SkRect destRectVisibleSubset;
    ClipRectToCanvas(canvas, destRect, &destRectVisibleSubset);

    // ClipRectToCanvas often overshoots, resulting in a larger region than our
    // original destRect. Intersecting gets us back inside.
    if (!destRectVisibleSubset.intersect(destRect))
        return; // Nothing visible in destRect.

    // Find the corresponding rect in the source image.
    SkMatrix destToSrcTransform;
    SkRect srcRectVisibleSubset;
    destToSrcTransform.setRectToRect(destRect, srcRect, SkMatrix::kFill_ScaleToFit);
    destToSrcTransform.mapRect(&srcRectVisibleSubset, destRectVisibleSubset);

    SkRect scaledSrcRect;
    SkIRect enclosingScaledSrcRect;
    SkBitmap scaledImageFragment = extractScaledImageFragment(bitmap, srcRectVisibleSubset, realScaleX, realScaleY, &scaledSrcRect, &enclosingScaledSrcRect);

    // Expand the destination rectangle because the source rectangle was
    // expanded to fit to integer boundaries.
    SkMatrix scaledSrcToDestTransform;
    scaledSrcToDestTransform.setRectToRect(scaledSrcRect, destRectVisibleSubset, SkMatrix::kFill_ScaleToFit);
    SkRect enclosingDestRect;
    enclosingDestRect.set(enclosingScaledSrcRect);
    scaledSrcToDestTransform.mapRect(&enclosingDestRect);

    // The reason we do clipping is because Skia doesn't support SkRect as
    // source rect. See http://crbug.com/145540.
    // When Skia supports then use this as the source rect to replace 0.
    //
    // scaledSrcRect.offset(-enclosingScaledSrcRect.x(), -enclosingScaledSrcRect.y());
    canvas.save();
    canvas.clipRect(destRectVisibleSubset);

    // Because the image fragment is generated with an approxmiated scaling
    // factor. This draw will perform a close to 1 scaling.
    //
    // NOTE: For future optimization. If the difference in scale is so small
    // that Skia doesn't produce a difference then we can just blit it directly
    // to enhance performance.
    canvas.drawBitmapRect(scaledImageFragment, 0, enclosingDestRect, &paint);
    canvas.restore();
}
Exemple #7
0
void TransparencyWin::compositeOpaqueComposite()
{
    if (!m_validLayer)
        return;

    SkCanvas* destCanvas = canvasForContext(*m_destContext);
    destCanvas->save();

    SkBitmap* bitmap = const_cast<SkBitmap*>(
        &bitmapForContext(*m_layerBuffer->context()));
    
    // This function will be called for WhiteLayer as well, which we don't want
    // to change.
    if (m_layerMode == OpaqueCompositeLayer) {
        // Fix up our bitmap, making it contain only the pixels which changed
        // and transparent everywhere else.
        SkAutoLockPixels sourceLock(*m_referenceBitmap);
        SkAutoLockPixels lock(*bitmap);
        for (int y = 0; y < bitmap->height(); y++) {
            uint32_t* source = m_referenceBitmap->getAddr32(0, y);
            uint32_t* dest = bitmap->getAddr32(0, y);
            for (int x = 0; x < bitmap->width(); x++) {
                // Clear out any pixels that were untouched.
                if (dest[x] == source[x])
                    dest[x] = 0;
                else
                    dest[x] |= (0xFF << SK_A32_SHIFT);
            }
        }
    } else
        makeLayerOpaque();

    SkRect destRect;
    if (m_transformMode != Untransform) {
        // We want to use Untransformed space.
        //
        // Note that we DON'T call m_layerBuffer->image() here. This actually
        // makes a copy of the image, which is unnecessary and slow. Instead, we
        // just draw the image from inside the destination context.
        SkMatrix identity;
        identity.reset();
        destCanvas->setMatrix(identity);

        destRect.set(m_transformedSourceRect.x(), m_transformedSourceRect.y(), m_transformedSourceRect.maxX(), m_transformedSourceRect.maxY());
    } else
        destRect.set(m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.maxX(), m_sourceRect.maxY());

    SkPaint paint;
    paint.setFilterBitmap(true);
    paint.setAntiAlias(true);

    // Note that we need to specify the source layer subset, since the bitmap
    // may have been cached and it could be larger than what we're using.
    SkIRect sourceRect = { 0, 0, m_layerSize.width(), m_layerSize.height() };
    destCanvas->drawBitmapRect(*bitmap, &sourceRect, destRect, &paint);
    destCanvas->restore();
}
DEF_TEST(IndexedPngOverflow, reporter) {
    SkBitmap image;
    bool success = decode_memory(gPng, sizeof(gPng), &image);
    REPORTER_ASSERT(reporter, success);

    SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(20, 1)));
    SkCanvas* canvas = surface->getCanvas();
    SkRect destRect = SkRect::MakeXYWH(0, 0, 20, 1);
    canvas->drawBitmapRect(image, destRect, nullptr);
}
void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
                       const FloatRect& srcRect, CompositeOperator compositeOp)
{
    startAnimation();

    SkBitmapRef* image = this->nativeImageForCurrentFrame();
    if (!image) { // If it's too early we won't have an image yet.
        return;
    }

    // in case we get called with an incomplete bitmap
    const SkBitmap& bitmap = image->bitmap();
    if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
#ifdef TRACE_SKIPPED_BITMAPS
        SkDebugf("----- skip bitmapimage: [%d %d] pixels %p pixelref %p\n",
                 bitmap.width(), bitmap.height(),
                 bitmap.getPixels(), bitmap.pixelRef());
#endif
        return;
    }

    SkIRect srcR;
    SkRect  dstR;    
    float invScaleX = (float)bitmap.width() / image->origWidth();
    float invScaleY = (float)bitmap.height() / image->origHeight();

    android_setrect(&dstR, dstRect);
    android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
    if (srcR.isEmpty() || dstR.isEmpty()) {
#ifdef TRACE_SKIPPED_BITMAPS
        SkDebugf("----- skip bitmapimage: [%d %d] src-empty %d dst-empty %d\n",
                 bitmap.width(), bitmap.height(),
                 srcR.isEmpty(), dstR.isEmpty());
#endif
        return;
    }

    SkCanvas*   canvas = ctxt->platformContext()->mCanvas;
    SkPaint     paint;

    paint.setFilterBitmap(true);
    paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
    canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);

#ifdef TRACE_SUBSAMPLED_BITMAPS
    if (bitmap.width() != image->origWidth() ||
        bitmap.height() != image->origHeight()) {
        SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
                 bitmap.width(), bitmap.height(),
                 image->origWidth(), image->origHeight());
    }
#endif
}
Exemple #10
0
static void paintSkBitmap(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, const SkIRect& srcRect, const SkRect& destRect, const SkXfermode::Mode& compOp)
{
#if PLATFORM(CHROMIUM)
    TRACE_EVENT0("skia", "paintSkBitmap");
#endif
    SkPaint paint;
    paint.setXfermodeMode(compOp);
    paint.setAlpha(platformContext->getNormalizedAlpha());
    paint.setLooper(platformContext->getDrawLooper());
    // only antialias if we're rotated or skewed
    paint.setAntiAlias(hasNon90rotation(platformContext));

    SkCanvas* canvas = platformContext->canvas();

    ResamplingMode resampling;
    if (platformContext->isAccelerated())
        resampling = RESAMPLE_LINEAR;
    else if (platformContext->printing())
        resampling = RESAMPLE_NONE;
    else {
        // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale).
        SkRect destRectTarget = destRect;
        if (!(canvas->getTotalMatrix().getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
            canvas->getTotalMatrix().mapRect(&destRectTarget, destRect);

        resampling = computeResamplingMode(canvas->getTotalMatrix(), bitmap, srcRect.width(), srcRect.height(),
                                           SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height()));
    }

    if (resampling == RESAMPLE_NONE) {
      // FIXME: This is to not break tests (it results in the filter bitmap flag
      // being set to true). We need to decide if we respect RESAMPLE_NONE
      // being returned from computeResamplingMode.
        resampling = RESAMPLE_LINEAR;
    }
    resampling = limitResamplingMode(platformContext, resampling);
    paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
    if (resampling == RESAMPLE_AWESOME)
        drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
    else {
        // No resampling necessary, we can just draw the bitmap. We want to
        // filter it if we decided to do linear interpolation above, or if there
        // is something interesting going on with the matrix (like a rotation).
        // Note: for serialization, we will want to subset the bitmap first so
        // we don't send extra pixels.
        canvas->drawBitmapRect(bitmap.bitmap(), &srcRect, destRect, &paint);
    }
    platformContext->didDrawRect(destRect, paint, &bitmap.bitmap());
}
Exemple #11
0
// Draws the given bitmap to the given canvas. The subset of the source bitmap
// identified by src_rect is drawn to the given destination rect. The bitmap
// will be resampled to resample_width * resample_height (this is the size of
// the whole image, not the subset). See shouldResampleBitmap for more.
//
// This does a lot of computation to resample only the portion of the bitmap
// that will only be drawn. This is critical for performance since when we are
// scrolling, for example, we are only drawing a small strip of the image.
// Resampling the whole image every time is very slow, so this speeds up things
// dramatically.
//
// Note: this code is only used when the canvas transformation is limited to
// scaling or translation.
static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
{
#if PLATFORM(CHROMIUM)
    TRACE_EVENT0("skia", "drawResampledBitmap");
#endif
    // Apply forward transform to destRect to estimate required size of
    // re-sampled bitmap, and use only in calls required to resize, or that
    // check for the required size.
    SkRect destRectTransformed;
    canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect);
    SkIRect destRectTransformedRounded;
    destRectTransformed.round(&destRectTransformedRounded);

    // Compute the visible portion of our rect.
    SkRect destRectVisibleSubset;
    ClipRectToCanvas(canvas, destRect, &destRectVisibleSubset);
    // ClipRectToCanvas often overshoots, resulting in a larger region than our
    // original destRect. Intersecting gets us back inside.
    if (!destRectVisibleSubset.intersect(destRect))
        return; // Nothing visible in destRect.

    // Compute the image-relative (bitmap space) subset.
    SkRect destBitmapSubset = destRectVisibleSubset;
    destBitmapSubset.offset(-destRect.x(), -destRect.y());

    // Scale the subset to the requested size. The canvas scale can be negative,
    // but the resampling code is only interested in positive scaling in its normal space.
    SkMatrix subsetTransform;
    subsetTransform.setScale(SkScalarAbs(canvas.getTotalMatrix().getScaleX()),
                             SkScalarAbs(canvas.getTotalMatrix().getScaleY()));
    SkRect destBitmapSubsetTransformed;
    subsetTransform.mapRect(&destBitmapSubsetTransformed, destBitmapSubset);
    SkIRect destBitmapSubsetTransformedRounded;
    destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded);

    // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded
    // to go outside the image, so need to clip to avoid problems.
    if (!destBitmapSubsetTransformedRounded.intersect(
            0, 0, destRectTransformedRounded.width(), destRectTransformedRounded.height()))
        return; // Image is not visible.

    SkBitmap resampled = bitmap.resizedBitmap(srcIRect,
                                              destRectTransformedRounded.width(),
                                              destRectTransformedRounded.height(),
                                              destBitmapSubsetTransformedRounded);
    canvas.drawBitmapRect(resampled, 0, destRectVisibleSubset, &paint);
}
Exemple #12
0
// Draws the given bitmap to the given canvas. The subset of the source bitmap
// identified by src_rect is drawn to the given destination rect. The bitmap
// will be resampled to resample_width * resample_height (this is the size of
// the whole image, not the subset). See shouldResampleBitmap for more.
//
// This does a lot of computation to resample only the portion of the bitmap
// that will only be drawn. This is critical for performance since when we are
// scrolling, for example, we are only drawing a small strip of the image.
// Resampling the whole image every time is very slow, so this speeds up things
// dramatically.
//
// Note: this code is only used when the canvas transformation is limited to
// scaling or translation.
static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
{
#if PLATFORM(CHROMIUM)
    TRACE_EVENT("drawResampledBitmap", &canvas, 0);
#endif
    // Apply forward transform to destRect to estimate required size of
    // re-sampled bitmap, and use only in calls required to resize, or that
    // check for the required size.
    SkRect destRectTransformed;
    canvas.getTotalMatrix().mapRect(&destRectTransformed, destRect);
    SkIRect destRectTransformedRounded;
    destRectTransformed.round(&destRectTransformedRounded);

    // Compute the visible portion of our rect.
    SkRect destRectVisibleSubset;
    ClipRectToCanvas(canvas, destRect, &destRectVisibleSubset);
    // ClipRectToCanvas often overshoots, resulting in a larger region than our
    // original destRect. Intersecting gets us back inside.
    if (!destRectVisibleSubset.intersect(destRect))
        return; // Nothing visible in destRect.

    // Compute the transformed (screen space) portion of the visible portion for
    // use below.
    SkRect destRectVisibleSubsetTransformed;
    canvas.getTotalMatrix().mapRect(&destRectVisibleSubsetTransformed, destRectVisibleSubset);
    SkRect destBitmapSubsetTransformed = destRectVisibleSubsetTransformed;
    destBitmapSubsetTransformed.offset(-destRectTransformed.fLeft,
                                       -destRectTransformed.fTop);
    SkIRect destBitmapSubsetTransformedRounded;
    destBitmapSubsetTransformed.round(&destBitmapSubsetTransformedRounded);

    // Transforms above plus rounding may cause destBitmapSubsetTransformedRounded
    // to go outside the image, so need to clip to avoid problems.
    if (!destBitmapSubsetTransformedRounded.intersect(
            0, 0, destRectTransformedRounded.width(), destRectTransformedRounded.height()))
        return; // Image is not visible.

    SkBitmap resampled = bitmap.resizedBitmap(srcIRect,
                                              destRectTransformedRounded.width(),
                                              destRectTransformedRounded.height(),
                                              destBitmapSubsetTransformedRounded);
    canvas.drawBitmapRect(resampled, 0, destRectVisibleSubset, &paint);
}
void renderer_item_image::draw_graphics_item (SkCanvas &canvas, const renderer_state &/*state*/, const renderer_config *config) const
{
  SkBitmap bitmap =  qt2skia::image (m_image_data);
  SkPaint paint;

  paint.setAlpha ((int) (m_opacity * 255));
  if (config->render_for_selection ())
  {
    if (!configure_painter_for_selection (paint))
      return;
    canvas.drawRect (qt2skia::rect (m_dst_rect), paint);
  }
  else
    {
      if (!bitmap.isNull ())
      {
        SkIRect irect = qt2skia::Irect (m_src_rect);
        canvas.drawBitmapRect (bitmap, &irect, qt2skia::rect (m_dst_rect), &paint);
      }
    }
}
Exemple #14
0
// Test out SkPictureRecorder::partialReplay
DEF_TEST(PictureRecorder_replay, reporter) {
    // check save/saveLayer state
    {
        SkPictureRecorder recorder;

        SkCanvas* canvas = recorder.beginRecording(10, 10);

        canvas->saveLayer(nullptr, nullptr);

        sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));

        // The extra save and restore comes from the Copy process.
        check_save_state(reporter, copy.get(), 2, 1, 3);

        canvas->saveLayer(nullptr, nullptr);

        sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());

        check_save_state(reporter, final.get(), 1, 2, 3);

        // The copy shouldn't pick up any operations added after it was made
        check_save_state(reporter, copy.get(), 2, 1, 3);
    }

    // (partially) check leakage of draw ops
    {
        SkPictureRecorder recorder;

        SkCanvas* canvas = recorder.beginRecording(10, 10);

        SkRect r = SkRect::MakeWH(5, 5);
        SkPaint p;

        canvas->drawRect(r, p);

        sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));

        REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());

        SkBitmap bm;
        make_bm(&bm, 10, 10, SK_ColorRED, true);

        r.offset(5.0f, 5.0f);
        canvas->drawBitmapRect(bm, r, nullptr);

        sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
        REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());

        REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());

        // The snapshot shouldn't pick up any operations added after it was made
        REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
    }

    // Recreate the Android partialReplay test case
    {
        SkPictureRecorder recorder;

        SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
        create_imbalance(canvas);

        int expectedSaveCount = canvas->getSaveCount();

        sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
        check_balance(reporter, copy.get());

        REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());

        // End the recording of source to test the picture finalization
        // process isn't complicated by the partialReplay step
        sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
    }
}
Exemple #15
0
// Draws the given bitmap to the given canvas. The subset of the source bitmap
// identified by src_rect is drawn to the given destination rect. The bitmap
// will be resampled to resample_width * resample_height (this is the size of
// the whole image, not the subset). See shouldResampleBitmap for more.
//
// This does a lot of computation to resample only the portion of the bitmap
// that will only be drawn. This is critical for performance since when we are
// scrolling, for example, we are only drawing a small strip of the image.
// Resampling the whole image every time is very slow, so this speeds up things
// dramatically.
static void drawResampledBitmap(SkCanvas& canvas, SkPaint& paint, const NativeImageSkia& bitmap, const SkIRect& srcIRect, const SkRect& destRect)
{
    // First get the subset we need. This is efficient and does not copy pixels.
    SkBitmap subset;
    bitmap.extractSubset(&subset, srcIRect);
    SkRect srcRect;
    srcRect.set(srcIRect);

    // Whether we're doing a subset or using the full source image.
    bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0
        && srcIRect.width() == bitmap.width()
        && srcIRect.height() == bitmap.height();

    // We will always draw in integer sizes, so round the destination rect.
    SkIRect destRectRounded;
    destRect.round(&destRectRounded);
    SkIRect resizedImageRect =  // Represents the size of the resized image.
        { 0, 0, destRectRounded.width(), destRectRounded.height() };

    if (srcIsFull && bitmap.hasResizedBitmap(destRectRounded.width(), destRectRounded.height())) {
        // Yay, this bitmap frame already has a resized version.
        SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(), destRectRounded.height());
        canvas.drawBitmapRect(resampled, 0, destRect, &paint);
        return;
    }

    // Compute the visible portion of our rect.
    SkRect destBitmapSubsetSk;
    ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
    destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);

    // The matrix inverting, etc. could have introduced rounding error which
    // causes the bounds to be outside of the resized bitmap. We round outward
    // so we always lean toward it being larger rather than smaller than we
    // need, and then clamp to the bitmap bounds so we don't get any invalid
    // data.
    SkIRect destBitmapSubsetSkI;
    destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
    if (!destBitmapSubsetSkI.intersect(resizedImageRect))
        return;  // Resized image does not intersect.

    if (srcIsFull && bitmap.shouldCacheResampling(
            resizedImageRect.width(),
            resizedImageRect.height(),
            destBitmapSubsetSkI.width(),
            destBitmapSubsetSkI.height())) {
        // We're supposed to resize the entire image and cache it, even though
        // we don't need all of it.
        SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
                                                  destRectRounded.height());
        canvas.drawBitmapRect(resampled, 0, destRect, &paint);
    } else {
        // We should only resize the exposed part of the bitmap to do the
        // minimal possible work.

        // Resample the needed part of the image.
        SkBitmap resampled = skia::ImageOperations::Resize(subset,
            skia::ImageOperations::RESIZE_LANCZOS3,
            destRectRounded.width(), destRectRounded.height(),
            destBitmapSubsetSkI);

        // Compute where the new bitmap should be drawn. Since our new bitmap
        // may be smaller than the original, we have to shift it over by the
        // same amount that we cut off the top and left.
        destBitmapSubsetSkI.offset(destRect.fLeft, destRect.fTop);
        SkRect offsetDestRect;
        offsetDestRect.set(destBitmapSubsetSkI);

        canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
    }
}