1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkImageGenerator.h" 9#include "SkCanvas.h" 10#include "SkMatrix.h" 11#include "SkPaint.h" 12#include "SkPicture.h" 13#include "SkSurface.h" 14#include "SkTLazy.h" 15 16class SkPictureImageGenerator : SkImageGenerator { 17public: 18 static SkImageGenerator* Create(const SkISize&, const SkPicture*, const SkMatrix*, 19 const SkPaint*); 20 21protected: 22 bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], 23 int* ctableCount) override; 24 bool onComputeScaledDimensions(SkScalar scale, SupportedSizes*) override; 25 bool onGenerateScaledPixels(const SkISize&, const SkIPoint&, const SkPixmap&) override; 26 27#if SK_SUPPORT_GPU 28 GrTexture* onGenerateTexture(GrContext*, const SkIRect*) override; 29#endif 30 31private: 32 SkPictureImageGenerator(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*); 33 34 SkAutoTUnref<const SkPicture> fPicture; 35 SkMatrix fMatrix; 36 SkTLazy<SkPaint> fPaint; 37 38 typedef SkImageGenerator INHERITED; 39}; 40 41SkImageGenerator* SkPictureImageGenerator::Create(const SkISize& size, const SkPicture* picture, 42 const SkMatrix* matrix, const SkPaint* paint) { 43 if (!picture || size.isEmpty()) { 44 return nullptr; 45 } 46 47 return new SkPictureImageGenerator(size, picture, matrix, paint); 48} 49 50SkPictureImageGenerator::SkPictureImageGenerator(const SkISize& size, const SkPicture* picture, 51 const SkMatrix* matrix, const SkPaint* paint) 52 : INHERITED(SkImageInfo::MakeN32Premul(size)) 53 , fPicture(SkRef(picture)) { 54 55 if (matrix) { 56 fMatrix = *matrix; 57 } else { 58 fMatrix.reset(); 59 } 60 61 if (paint) { 62 fPaint.set(*paint); 63 } 64} 65 66bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 67 SkPMColor ctable[], int* ctableCount) { 68 if (info != getInfo() || ctable || ctableCount) { 69 return false; 70 } 71 72 SkBitmap bitmap; 73 if (!bitmap.installPixels(info, pixels, rowBytes)) { 74 return false; 75 } 76 77 bitmap.eraseColor(SK_ColorTRANSPARENT); 78 SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); 79 canvas.drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); 80 81 return true; 82} 83 84bool SkPictureImageGenerator::onComputeScaledDimensions(SkScalar scale, 85 SupportedSizes* sizes) { 86 SkASSERT(scale > 0 && scale <= 1); 87 const int w = this->getInfo().width(); 88 const int h = this->getInfo().height(); 89 const int sw = SkScalarRoundToInt(scale * w); 90 const int sh = SkScalarRoundToInt(scale * h); 91 if (sw > 0 && sh > 0) { 92 sizes->fSizes[0].set(sw, sh); 93 sizes->fSizes[1].set(sw, sh); 94 return true; 95 } 96 return false; 97} 98 99bool SkPictureImageGenerator::onGenerateScaledPixels(const SkISize& scaledSize, 100 const SkIPoint& scaledOrigin, 101 const SkPixmap& scaledPixels) { 102 int w = scaledSize.width(); 103 int h = scaledSize.height(); 104 105 const SkScalar scaleX = SkIntToScalar(w) / this->getInfo().width(); 106 const SkScalar scaleY = SkIntToScalar(h) / this->getInfo().height(); 107 SkMatrix matrix = SkMatrix::MakeScale(scaleX, scaleY); 108 matrix.postTranslate(-SkIntToScalar(scaledOrigin.x()), -SkIntToScalar(scaledOrigin.y())); 109 110 SkBitmap bitmap; 111 if (!bitmap.installPixels(scaledPixels)) { 112 return false; 113 } 114 115 bitmap.eraseColor(SK_ColorTRANSPARENT); 116 SkCanvas canvas(bitmap, SkSurfaceProps(0, kUnknown_SkPixelGeometry)); 117 matrix.preConcat(fMatrix); 118 canvas.drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); 119 return true; 120} 121 122/////////////////////////////////////////////////////////////////////////////////////////////////// 123 124SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const SkPicture* picture, 125 const SkMatrix* matrix, const SkPaint* paint) { 126 return SkPictureImageGenerator::Create(size, picture, matrix, paint); 127} 128 129/////////////////////////////////////////////////////////////////////////////////////////////////// 130 131#if SK_SUPPORT_GPU 132#include "GrTexture.h" 133 134GrTexture* SkPictureImageGenerator::onGenerateTexture(GrContext* ctx, const SkIRect* subset) { 135 const SkImageInfo& info = this->getInfo(); 136 SkImageInfo surfaceInfo = subset ? info.makeWH(subset->width(), subset->height()) : info; 137 138 // 139 // TODO: respect the usage, by possibly creating a different (pow2) surface 140 // 141 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkBudgeted::kYes, 142 surfaceInfo)); 143 if (!surface.get()) { 144 return nullptr; 145 } 146 147 SkMatrix matrix = fMatrix; 148 if (subset) { 149 matrix.postTranslate(-subset->x(), -subset->y()); 150 } 151 surface->getCanvas()->clear(0); // does NewRenderTarget promise to do this for us? 152 surface->getCanvas()->drawPicture(fPicture, &matrix, fPaint.getMaybeNull()); 153 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 154 if (!image.get()) { 155 return nullptr; 156 } 157 return SkSafeRef(image->getTexture()); 158} 159#endif 160