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 "SkArenaAlloc.h"
9 #include "SkBitmapController.h"
10 #include "SkBitmapProcShader.h"
11 #include "SkBitmapProvider.h"
12 #include "SkColorTable.h"
13 #include "SkEmptyShader.h"
14 #include "SkImage_Base.h"
15 #include "SkImageShader.h"
16 #include "SkImageShaderContext.h"
17 #include "SkPM4fPriv.h"
18 #include "SkReadBuffer.h"
19 #include "SkWriteBuffer.h"
20 
SkImageShader(sk_sp<SkImage> img,TileMode tmx,TileMode tmy,const SkMatrix * matrix)21 SkImageShader::SkImageShader(sk_sp<SkImage> img, TileMode tmx, TileMode tmy, const SkMatrix* matrix)
22     : INHERITED(matrix)
23     , fImage(std::move(img))
24     , fTileModeX(tmx)
25     , fTileModeY(tmy)
26 {}
27 
CreateProc(SkReadBuffer & buffer)28 sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
29     const TileMode tx = (TileMode)buffer.readUInt();
30     const TileMode ty = (TileMode)buffer.readUInt();
31     SkMatrix matrix;
32     buffer.readMatrix(&matrix);
33     sk_sp<SkImage> img = buffer.readImage();
34     if (!img) {
35         return nullptr;
36     }
37     return SkImageShader::Make(std::move(img), tx, ty, &matrix);
38 }
39 
flatten(SkWriteBuffer & buffer) const40 void SkImageShader::flatten(SkWriteBuffer& buffer) const {
41     buffer.writeUInt(fTileModeX);
42     buffer.writeUInt(fTileModeY);
43     buffer.writeMatrix(this->getLocalMatrix());
44     buffer.writeImage(fImage.get());
45 }
46 
isOpaque() const47 bool SkImageShader::isOpaque() const {
48     return fImage->isOpaque();
49 }
50 
onMakeContext(const ContextRec & rec,SkArenaAlloc * alloc) const51 SkShader::Context* SkImageShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const {
52     return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY,
53                                                  SkBitmapProvider(fImage.get(), rec.fDstColorSpace),
54                                                  rec, alloc);
55 }
56 
onIsAImage(SkMatrix * texM,TileMode xy[]) const57 SkImage* SkImageShader::onIsAImage(SkMatrix* texM, TileMode xy[]) const {
58     if (texM) {
59         *texM = this->getLocalMatrix();
60     }
61     if (xy) {
62         xy[0] = (TileMode)fTileModeX;
63         xy[1] = (TileMode)fTileModeY;
64     }
65     return const_cast<SkImage*>(fImage.get());
66 }
67 
68 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP
onIsABitmap(SkBitmap * texture,SkMatrix * texM,TileMode xy[]) const69 bool SkImageShader::onIsABitmap(SkBitmap* texture, SkMatrix* texM, TileMode xy[]) const {
70     const SkBitmap* bm = as_IB(fImage)->onPeekBitmap();
71     if (!bm) {
72         return false;
73     }
74 
75     if (texture) {
76         *texture = *bm;
77     }
78     if (texM) {
79         *texM = this->getLocalMatrix();
80     }
81     if (xy) {
82         xy[0] = (TileMode)fTileModeX;
83         xy[1] = (TileMode)fTileModeY;
84     }
85     return true;
86 }
87 #endif
88 
bitmap_is_too_big(int w,int h)89 static bool bitmap_is_too_big(int w, int h) {
90     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
91     // communicates between its matrix-proc and its sampler-proc. Until we can
92     // widen that, we have to reject bitmaps that are larger.
93     //
94     static const int kMaxSize = 65535;
95 
96     return w > kMaxSize || h > kMaxSize;
97 }
98 
Make(sk_sp<SkImage> image,TileMode tx,TileMode ty,const SkMatrix * localMatrix)99 sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, TileMode tx, TileMode ty,
100                                     const SkMatrix* localMatrix) {
101     if (!image || bitmap_is_too_big(image->width(), image->height())) {
102         return sk_make_sp<SkEmptyShader>();
103     } else {
104         return sk_make_sp<SkImageShader>(image, tx, ty, localMatrix);
105     }
106 }
107 
108 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const109 void SkImageShader::toString(SkString* str) const {
110     const char* gTileModeName[SkShader::kTileModeCount] = {
111         "clamp", "repeat", "mirror"
112     };
113 
114     str->appendf("ImageShader: ((%s %s) ", gTileModeName[fTileModeX], gTileModeName[fTileModeY]);
115     fImage->toString(str);
116     this->INHERITED::toString(str);
117     str->append(")");
118 }
119 #endif
120 
121 ///////////////////////////////////////////////////////////////////////////////////////////////////
122 
123 #if SK_SUPPORT_GPU
124 
125 #include "SkGr.h"
126 #include "GrContext.h"
127 #include "effects/GrSimpleTextureEffect.h"
128 #include "effects/GrBicubicEffect.h"
129 #include "effects/GrSimpleTextureEffect.h"
130 
asFragmentProcessor(const AsFPArgs & args) const131 sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& args) const {
132 
133     SkMatrix lmInverse;
134     if (!this->getLocalMatrix().invert(&lmInverse)) {
135         return nullptr;
136     }
137     if (args.fLocalMatrix) {
138         SkMatrix inv;
139         if (!args.fLocalMatrix->invert(&inv)) {
140             return nullptr;
141         }
142         lmInverse.postConcat(inv);
143     }
144 
145     SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
146 
147     // Must set wrap and filter on the sampler before requesting a texture. In two places below
148     // we check the matrix scale factors to determine how to interpret the filter quality setting.
149     // This completely ignores the complexity of the drawVertices case where explicit local coords
150     // are provided by the caller.
151     bool doBicubic;
152     GrSamplerParams::FilterMode textureFilterMode =
153     GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
154                                     &doBicubic);
155     GrSamplerParams params(tm, textureFilterMode);
156     sk_sp<SkColorSpace> texColorSpace;
157     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
158     sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(args.fContext, params,
159                                                                  args.fDstColorSpace,
160                                                                  &texColorSpace, scaleAdjust));
161     if (!proxy) {
162         return nullptr;
163     }
164 
165     bool isAlphaOnly = GrPixelConfigIsAlphaOnly(proxy->config());
166 
167     lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]);
168 
169     sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(texColorSpace.get(),
170                                                                        args.fDstColorSpace);
171     sk_sp<GrFragmentProcessor> inner;
172     if (doBicubic) {
173         inner = GrBicubicEffect::Make(args.fContext->resourceProvider(), std::move(proxy),
174                                       std::move(colorSpaceXform), lmInverse, tm);
175     } else {
176         inner = GrSimpleTextureEffect::Make(args.fContext->resourceProvider(), std::move(proxy),
177                                             std::move(colorSpaceXform), lmInverse, params);
178     }
179 
180     if (isAlphaOnly) {
181         return inner;
182     }
183     return sk_sp<GrFragmentProcessor>(GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner)));
184 }
185 
186 #endif
187 
188 ///////////////////////////////////////////////////////////////////////////////////////////////////
189 #include "SkImagePriv.h"
190 
SkMakeBitmapShader(const SkBitmap & src,SkShader::TileMode tmx,SkShader::TileMode tmy,const SkMatrix * localMatrix,SkCopyPixelsMode cpm)191 sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
192                                    SkShader::TileMode tmy, const SkMatrix* localMatrix,
193                                    SkCopyPixelsMode cpm) {
194     return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm),
195                                tmx, tmy, localMatrix);
196 }
197 
SkBitmapProcShader_CreateProc(SkReadBuffer & buffer)198 static sk_sp<SkFlattenable> SkBitmapProcShader_CreateProc(SkReadBuffer& buffer) {
199     SkMatrix lm;
200     buffer.readMatrix(&lm);
201     sk_sp<SkImage> image = buffer.readBitmapAsImage();
202     SkShader::TileMode mx = (SkShader::TileMode)buffer.readUInt();
203     SkShader::TileMode my = (SkShader::TileMode)buffer.readUInt();
204     return image ? image->makeShader(mx, my, &lm) : nullptr;
205 }
206 
207 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkShader)
208 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkImageShader)
209 SkFlattenable::Register("SkBitmapProcShader", SkBitmapProcShader_CreateProc, kSkShader_Type);
210 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
211 
212 
onAppendStages(SkRasterPipeline * p,SkColorSpace * dst,SkArenaAlloc * scratch,const SkMatrix & ctm,const SkPaint & paint,const SkMatrix * localM) const213 bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkArenaAlloc* scratch,
214                                    const SkMatrix& ctm, const SkPaint& paint,
215                                    const SkMatrix* localM) const {
216     auto matrix = SkMatrix::Concat(ctm, this->getLocalMatrix());
217     if (localM) {
218         matrix.preConcat(*localM);
219     }
220 
221     if (!matrix.invert(&matrix)) {
222         return false;
223     }
224     auto quality = paint.getFilterQuality();
225 
226     SkBitmapProvider provider(fImage.get(), dst);
227     SkDefaultBitmapController controller(SkDefaultBitmapController::CanShadeHQ::kYes);
228     std::unique_ptr<SkBitmapController::State> state {
229         controller.requestBitmap(provider, matrix, quality)
230     };
231     if (!state) {
232         return false;
233     }
234 
235     const SkPixmap& pm = state->pixmap();
236     matrix  = state->invMatrix();
237     quality = state->quality();
238     auto info = pm.info();
239 
240     // When the matrix is just an integer translate, bilerp == nearest neighbor.
241     if (quality == kLow_SkFilterQuality &&
242         matrix.getType() <= SkMatrix::kTranslate_Mask &&
243         matrix.getTranslateX() == (int)matrix.getTranslateX() &&
244         matrix.getTranslateY() == (int)matrix.getTranslateY()) {
245         quality = kNone_SkFilterQuality;
246     }
247 
248     // See skia:4649 and the GM image_scale_aligned.
249     if (quality == kNone_SkFilterQuality) {
250         if (matrix.getScaleX() >= 0) {
251             matrix.setTranslateX(nextafterf(matrix.getTranslateX(),
252                                             floorf(matrix.getTranslateX())));
253         }
254         if (matrix.getScaleY() >= 0) {
255             matrix.setTranslateY(nextafterf(matrix.getTranslateY(),
256                                             floorf(matrix.getTranslateY())));
257         }
258     }
259 
260     auto ctx = scratch->make<SkImageShaderContext>();
261     ctx->state   = std::move(state);  // Extend lifetime to match the pipeline's.
262     ctx->pixels  = pm.addr();
263     ctx->ctable  = pm.ctable();
264     ctx->color4f = SkColor4f_from_SkColor(paint.getColor(), dst);
265     ctx->stride  = pm.rowBytesAsPixels();
266     ctx->width   = (float)pm.width();
267     ctx->height  = (float)pm.height();
268     if (matrix.asAffine(ctx->matrix)) {
269         p->append(SkRasterPipeline::matrix_2x3, ctx->matrix);
270     } else {
271         matrix.get9(ctx->matrix);
272         p->append(SkRasterPipeline::matrix_perspective, ctx->matrix);
273     }
274 
275     auto append_tiling_and_gather = [&] {
276         switch (fTileModeX) {
277             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_x,  &ctx->width); break;
278             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x, &ctx->width); break;
279             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x, &ctx->width); break;
280         }
281         switch (fTileModeY) {
282             case kClamp_TileMode:  p->append(SkRasterPipeline::clamp_y,  &ctx->height); break;
283             case kMirror_TileMode: p->append(SkRasterPipeline::mirror_y, &ctx->height); break;
284             case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &ctx->height); break;
285         }
286         switch (info.colorType()) {
287             case kAlpha_8_SkColorType:   p->append(SkRasterPipeline::gather_a8,   ctx); break;
288             case kIndex_8_SkColorType:   p->append(SkRasterPipeline::gather_i8,   ctx); break;
289             case kGray_8_SkColorType:    p->append(SkRasterPipeline::gather_g8,   ctx); break;
290             case kRGB_565_SkColorType:   p->append(SkRasterPipeline::gather_565,  ctx); break;
291             case kARGB_4444_SkColorType: p->append(SkRasterPipeline::gather_4444, ctx); break;
292             case kRGBA_8888_SkColorType:
293             case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx); break;
294             case kRGBA_F16_SkColorType:  p->append(SkRasterPipeline::gather_f16,  ctx); break;
295             default: SkASSERT(false);
296         }
297         if (info.gammaCloseToSRGB() && dst != nullptr) {
298             p->append_from_srgb(info.alphaType());
299         }
300     };
301 
302     auto sample = [&](SkRasterPipeline::StockStage setup_x,
303                       SkRasterPipeline::StockStage setup_y) {
304         p->append(setup_x, ctx);
305         p->append(setup_y, ctx);
306         append_tiling_and_gather();
307         p->append(SkRasterPipeline::accumulate, ctx);
308     };
309 
310     if (quality == kNone_SkFilterQuality) {
311         append_tiling_and_gather();
312     } else if (quality == kLow_SkFilterQuality) {
313         p->append(SkRasterPipeline::save_xy, ctx);
314 
315         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_ny);
316         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_ny);
317         sample(SkRasterPipeline::bilinear_nx, SkRasterPipeline::bilinear_py);
318         sample(SkRasterPipeline::bilinear_px, SkRasterPipeline::bilinear_py);
319 
320         p->append(SkRasterPipeline::move_dst_src);
321     } else {
322         p->append(SkRasterPipeline::save_xy, ctx);
323 
324         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n3y);
325         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n3y);
326         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n3y);
327         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n3y);
328 
329         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_n1y);
330         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_n1y);
331         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_n1y);
332         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_n1y);
333 
334         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p1y);
335         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p1y);
336         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p1y);
337         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p1y);
338 
339         sample(SkRasterPipeline::bicubic_n3x, SkRasterPipeline::bicubic_p3y);
340         sample(SkRasterPipeline::bicubic_n1x, SkRasterPipeline::bicubic_p3y);
341         sample(SkRasterPipeline::bicubic_p1x, SkRasterPipeline::bicubic_p3y);
342         sample(SkRasterPipeline::bicubic_p3x, SkRasterPipeline::bicubic_p3y);
343 
344         p->append(SkRasterPipeline::move_dst_src);
345     }
346 
347     auto effective_color_type = [](SkColorType ct) {
348         return ct == kIndex_8_SkColorType ? kN32_SkColorType : ct;
349     };
350 
351     if (effective_color_type(info.colorType()) == kBGRA_8888_SkColorType) {
352         p->append(SkRasterPipeline::swap_rb);
353     }
354     if (info.colorType() == kAlpha_8_SkColorType) {
355         p->append(SkRasterPipeline::set_rgb, &ctx->color4f);
356     }
357     if (info.colorType() == kAlpha_8_SkColorType || info.alphaType() == kUnpremul_SkAlphaType) {
358         p->append(SkRasterPipeline::premul);
359     }
360     if (quality > kLow_SkFilterQuality) {
361         // Bicubic filtering naturally produces out of range values on both sides.
362         p->append(SkRasterPipeline::clamp_0);
363         p->append(SkRasterPipeline::clamp_a);
364     }
365     return append_gamut_transform(p, scratch, info.colorSpace(), dst);
366 }
367