/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkImage_Base.h" #include "SkImageGenerator.h" #include "SkCanvas.h" #include "SkMatrix.h" #include "SkPaint.h" #include "SkPicture.h" #include "SkSurface.h" #include "SkTLazy.h" class SkPictureImageGenerator : SkImageGenerator { public: static SkImageGenerator* Create(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*); protected: bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override; bool onComputeScaledDimensions(SkScalar scale, SupportedSizes*) override; bool onGenerateScaledPixels(const SkISize&, const SkIPoint&, const SkPixmap&) override; #if SK_SUPPORT_GPU GrTexture* onGenerateTexture(GrContext*, const SkIRect*) override; #endif private: SkPictureImageGenerator(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*); SkAutoTUnref fPicture; SkMatrix fMatrix; SkTLazy fPaint; typedef SkImageGenerator INHERITED; }; SkImageGenerator* SkPictureImageGenerator::Create(const SkISize& size, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { if (!picture || size.isEmpty()) { return nullptr; } return new SkPictureImageGenerator(size, picture, matrix, paint); } SkPictureImageGenerator::SkPictureImageGenerator(const SkISize& size, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) : INHERITED(SkImageInfo::MakeN32Premul(size)) , fPicture(SkRef(picture)) { if (matrix) { fMatrix = *matrix; } else { fMatrix.reset(); } if (paint) { fPaint.set(*paint); } } bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { if (info != getInfo() || ctable || ctableCount) { return false; } SkBitmap bitmap; if (!bitmap.installPixels(info, pixels, rowBytes)) { return false; } bitmap.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); canvas.drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); return true; } bool SkPictureImageGenerator::onComputeScaledDimensions(SkScalar scale, SupportedSizes* sizes) { SkASSERT(scale > 0 && scale <= 1); const int w = this->getInfo().width(); const int h = this->getInfo().height(); const int sw = SkScalarRoundToInt(scale * w); const int sh = SkScalarRoundToInt(scale * h); if (sw > 0 && sh > 0) { sizes->fSizes[0].set(sw, sh); sizes->fSizes[1].set(sw, sh); return true; } return false; } bool SkPictureImageGenerator::onGenerateScaledPixels(const SkISize& scaledSize, const SkIPoint& scaledOrigin, const SkPixmap& scaledPixels) { int w = scaledSize.width(); int h = scaledSize.height(); const SkScalar scaleX = SkIntToScalar(w) / this->getInfo().width(); const SkScalar scaleY = SkIntToScalar(h) / this->getInfo().height(); SkMatrix matrix = SkMatrix::MakeScale(scaleX, scaleY); matrix.postTranslate(-SkIntToScalar(scaledOrigin.x()), -SkIntToScalar(scaledOrigin.y())); SkBitmap bitmap; if (!bitmap.installPixels(scaledPixels)) { return false; } bitmap.eraseColor(SK_ColorTRANSPARENT); SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); matrix.preConcat(fMatrix); canvas.drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); return true; } /////////////////////////////////////////////////////////////////////////////////////////////////// SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { return SkPictureImageGenerator::Create(size, picture, matrix, paint); } /////////////////////////////////////////////////////////////////////////////////////////////////// #if SK_SUPPORT_GPU #include "GrTexture.h" GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, const SkIRect* subset) { const SkImageInfo& info = this->getInfo(); SkImageInfo surfaceInfo = subset ? info.makeWH(subset->width(), subset->height()) : info; // // TODO: respect the usage, by possibly creating a different (pow2) surface // sk_sp surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, surfaceInfo)); if (!surface) { return nullptr; } SkMatrix matrix = fMatrix; if (subset) { matrix.postTranslate(-subset->x(), -subset->y()); } surface->getCanvas()->clear(0); // does NewRenderTarget promise to do this for us? surface->getCanvas()->drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); sk_sp image(surface->makeImageSnapshot()); if (!image) { return nullptr; } return SkSafeRef(as_IB(image)->peekTexture()); } #endif