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
16 class SkPictureImageGenerator : SkImageGenerator {
17 public:
18 static SkImageGenerator* Create(const SkISize&, const SkPicture*, const SkMatrix*,
19 const SkPaint*);
20
21 protected:
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
31 private:
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
Create(const SkISize & size,const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)41 SkImageGenerator* 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
SkPictureImageGenerator(const SkISize & size,const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)50 SkPictureImageGenerator::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
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,SkPMColor ctable[],int * ctableCount)66 bool 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
onComputeScaledDimensions(SkScalar scale,SupportedSizes * sizes)84 bool 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
onGenerateScaledPixels(const SkISize & scaledSize,const SkIPoint & scaledOrigin,const SkPixmap & scaledPixels)99 bool 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
NewFromPicture(const SkISize & size,const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)124 SkImageGenerator* 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
onGenerateTexture(GrContext * ctx,const SkIRect * subset)134 GrTexture* 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