|  | /* | 
|  | * 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<const SkPicture> fPicture; | 
|  | SkMatrix                      fMatrix; | 
|  | SkTLazy<SkPaint>              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<SkSurface> 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<SkImage> image(surface->makeImageSnapshot()); | 
|  | if (!image) { | 
|  | return nullptr; | 
|  | } | 
|  | return SkSafeRef(as_IB(image)->peekTexture()); | 
|  | } | 
|  | #endif |