1 /*
2  * Copyright 2016 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 "SkLinearBitmapPipeline.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <limits>
13 #include <tuple>
14 
15 #include "SkArenaAlloc.h"
16 #include "SkLinearBitmapPipeline_core.h"
17 #include "SkLinearBitmapPipeline_matrix.h"
18 #include "SkLinearBitmapPipeline_tile.h"
19 #include "SkLinearBitmapPipeline_sample.h"
20 #include "SkNx.h"
21 #include "SkOpts.h"
22 #include "SkPM4f.h"
23 
24 namespace  {
25 
26 ////////////////////////////////////////////////////////////////////////////////////////////////////
27 // Matrix Stage
28 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
29 // must implement the following methods:
30 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
31 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixels
32 //   to work over.
33 //   span - encapsulation of span.
34 //   next - a pointer to the next stage.
35 //   maybeProcessSpan - returns false if it can not process the span and needs to fallback to
36 //                      point lists for processing.
37 template<typename Strategy, typename Next>
38 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
39 public:
40     template <typename... Args>
MatrixStage(Next * next,Args &&...args)41     MatrixStage(Next* next, Args&&... args)
42         : fNext{next}
43         , fStrategy{std::forward<Args>(args)...}{ }
44 
MatrixStage(Next * next,MatrixStage * stage)45     MatrixStage(Next* next, MatrixStage* stage)
46         : fNext{next}
47         , fStrategy{stage->fStrategy} { }
48 
pointListFew(int n,Sk4s xs,Sk4s ys)49     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
50         fStrategy.processPoints(&xs, &ys);
51         fNext->pointListFew(n, xs, ys);
52     }
53 
pointList4(Sk4s xs,Sk4s ys)54     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
55         fStrategy.processPoints(&xs, &ys);
56         fNext->pointList4(xs, ys);
57     }
58 
59     // The span you pass must not be empty.
pointSpan(Span span)60     void pointSpan(Span span) override {
61         SkASSERT(!span.isEmpty());
62         if (!fStrategy.maybeProcessSpan(span, fNext)) {
63             span_fallback(span, this);
64         }
65     }
66 
67 private:
68     Next* const fNext;
69     Strategy fStrategy;
70 };
71 
72 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
73 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>;
74 
75 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
76 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>;
77 
78 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
79 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>;
80 
81 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
82 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>;
83 
84 
85 ////////////////////////////////////////////////////////////////////////////////////////////////////
86 // Tile Stage
87 
88 template<typename XStrategy, typename YStrategy, typename Next>
89 class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
90 public:
CombinedTileStage(Next * next,SkISize dimensions)91     CombinedTileStage(Next* next, SkISize dimensions)
92         : fNext{next}
93         , fXStrategy{dimensions.width()}
94         , fYStrategy{dimensions.height()}{ }
95 
CombinedTileStage(Next * next,CombinedTileStage * stage)96     CombinedTileStage(Next* next, CombinedTileStage* stage)
97         : fNext{next}
98         , fXStrategy{stage->fXStrategy}
99         , fYStrategy{stage->fYStrategy} { }
100 
pointListFew(int n,Sk4s xs,Sk4s ys)101     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
102         fXStrategy.tileXPoints(&xs);
103         fYStrategy.tileYPoints(&ys);
104         fNext->pointListFew(n, xs, ys);
105     }
106 
pointList4(Sk4s xs,Sk4s ys)107     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
108         fXStrategy.tileXPoints(&xs);
109         fYStrategy.tileYPoints(&ys);
110         fNext->pointList4(xs, ys);
111     }
112 
113     // The span you pass must not be empty.
pointSpan(Span span)114     void pointSpan(Span span) override {
115         SkASSERT(!span.isEmpty());
116         SkPoint start; SkScalar length; int count;
117         std::tie(start, length, count) = span;
118 
119         if (span.count() == 1) {
120             // DANGER:
121             // The explicit casts from float to Sk4f are not usually necessary, but are here to
122             // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug
123             // 5566.
124             this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
125             return;
126         }
127 
128         SkScalar x = X(start);
129         SkScalar y = fYStrategy.tileY(Y(start));
130         Span yAdjustedSpan{{x, y}, length, count};
131 
132         if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
133             span_fallback(span, this);
134         }
135     }
136 
137 private:
138     Next* const fNext;
139     XStrategy fXStrategy;
140     YStrategy fYStrategy;
141 };
142 
143 ////////////////////////////////////////////////////////////////////////////////////////////////////
144 // Specialized Samplers
145 
146 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
147 // are the same format and do not need in transformations in pixel space. Therefore, there is no
148 // need to convert them to HiFi pixel format.
149 class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
150                                     public SkLinearBitmapPipeline::DestinationInterface {
151 public:
RGBA8888UnitRepeatSrc(const uint32_t * src,int32_t width)152     RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
153         : fSrc{src}, fWidth{width} { }
154 
pointListFew(int n,Sk4s xs,Sk4s ys)155     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
156         SkASSERT(fDest + n <= fEnd);
157         // At this point xs and ys should be >= 0, so trunc is the same as floor.
158         Sk4i iXs = SkNx_cast<int>(xs);
159         Sk4i iYs = SkNx_cast<int>(ys);
160 
161         if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
162         if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
163         if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
164     }
165 
pointList4(Sk4s xs,Sk4s ys)166     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
167         SkASSERT(fDest + 4 <= fEnd);
168         Sk4i iXs = SkNx_cast<int>(xs);
169         Sk4i iYs = SkNx_cast<int>(ys);
170         *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
171         *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
172         *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
173         *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
174     }
175 
pointSpan(Span span)176     void pointSpan(Span span) override {
177         SkASSERT(fDest + span.count() <= fEnd);
178         if (span.length() != 0.0f) {
179             int32_t x = SkScalarTruncToInt(span.startX());
180             int32_t y = SkScalarTruncToInt(span.startY());
181             const uint32_t* src = this->pixelAddress(x, y);
182             memmove(fDest, src, span.count() * sizeof(uint32_t));
183             fDest += span.count();
184         }
185     }
186 
repeatSpan(Span span,int32_t repeatCount)187     void repeatSpan(Span span, int32_t repeatCount) override {
188         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
189 
190         int32_t x = SkScalarTruncToInt(span.startX());
191         int32_t y = SkScalarTruncToInt(span.startY());
192         const uint32_t* src = this->pixelAddress(x, y);
193         uint32_t* dest = fDest;
194         while (repeatCount --> 0) {
195             memmove(dest, src, span.count() * sizeof(uint32_t));
196             dest += span.count();
197         }
198         fDest = dest;
199     }
200 
setDestination(void * dst,int count)201     void setDestination(void* dst, int count) override  {
202         fDest = static_cast<uint32_t*>(dst);
203         fEnd = fDest + count;
204     }
205 
206 private:
pixelAddress(int32_t x,int32_t y)207     const uint32_t* pixelAddress(int32_t x, int32_t y) {
208         return &fSrc[fWidth * y + x];
209     }
210     const uint32_t* const fSrc;
211     const int32_t         fWidth;
212     uint32_t*             fDest;
213     uint32_t*             fEnd;
214 };
215 
216 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
217 // are the same format and do not need in transformations in pixel space. Therefore, there is no
218 // need to convert them to HiFi pixel format.
219 class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
220                                         public SkLinearBitmapPipeline::DestinationInterface {
221 public:
RGBA8888UnitRepeatSrcOver(const uint32_t * src,int32_t width)222     RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
223         : fSrc{src}, fWidth{width} { }
224 
pointListFew(int n,Sk4s xs,Sk4s ys)225     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
226         SkASSERT(fDest + n <= fEnd);
227         // At this point xs and ys should be >= 0, so trunc is the same as floor.
228         Sk4i iXs = SkNx_cast<int>(xs);
229         Sk4i iYs = SkNx_cast<int>(ys);
230 
231         if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
232         if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
233         if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
234     }
235 
pointList4(Sk4s xs,Sk4s ys)236     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
237         SkASSERT(fDest + 4 <= fEnd);
238         Sk4i iXs = SkNx_cast<int>(xs);
239         Sk4i iYs = SkNx_cast<int>(ys);
240         blendPixelAt(iXs[0], iYs[0]);
241         blendPixelAt(iXs[1], iYs[1]);
242         blendPixelAt(iXs[2], iYs[2]);
243         blendPixelAt(iXs[3], iYs[3]);
244     }
245 
pointSpan(Span span)246     void pointSpan(Span span) override {
247         if (span.length() != 0.0f) {
248             this->repeatSpan(span, 1);
249         }
250     }
251 
repeatSpan(Span span,int32_t repeatCount)252     void repeatSpan(Span span, int32_t repeatCount) override {
253         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
254         SkASSERT(span.count() > 0);
255         SkASSERT(repeatCount > 0);
256 
257         int32_t x = (int32_t)span.startX();
258         int32_t y = (int32_t)span.startY();
259         const uint32_t* beginSpan = this->pixelAddress(x, y);
260 
261         SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
262 
263         fDest += span.count() * repeatCount;
264 
265         SkASSERT(fDest <= fEnd);
266     }
267 
setDestination(void * dst,int count)268     void setDestination(void* dst, int count) override  {
269         SkASSERT(count > 0);
270         fDest = static_cast<uint32_t*>(dst);
271         fEnd = fDest + count;
272     }
273 
274 private:
pixelAddress(int32_t x,int32_t y)275     const uint32_t* pixelAddress(int32_t x, int32_t y) {
276         return &fSrc[fWidth * y + x];
277     }
278 
blendPixelAt(int32_t x,int32_t y)279     void blendPixelAt(int32_t x, int32_t y) {
280         const uint32_t* src = this->pixelAddress(x, y);
281         SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
282         fDest += 1;
283     }
284 
285     const uint32_t* const fSrc;
286     const int32_t         fWidth;
287     uint32_t*             fDest;
288     uint32_t*             fEnd;
289 };
290 
291 using Blender = SkLinearBitmapPipeline::BlendProcessorInterface;
292 
293 ////////////////////////////////////////////////////////////////////////////////////////////////////
294 // Pixel Blender Stage
295 template <SkAlphaType alphaType>
296 class SrcFPPixel final : public Blender {
297 public:
SrcFPPixel(float postAlpha)298     SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
SrcFPPixel(const SrcFPPixel & Blender)299     SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
blendPixel(Sk4f pixel)300     void SK_VECTORCALL blendPixel(Sk4f pixel) override {
301         SkASSERT(fDst + 1 <= fEnd );
302         this->srcPixel(fDst, pixel, 0);
303         fDst += 1;
304     }
305 
blend4Pixels(Sk4f p0,Sk4f p1,Sk4f p2,Sk4f p3)306     void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
307         SkASSERT(fDst + 4 <= fEnd);
308         SkPM4f* dst = fDst;
309         this->srcPixel(dst, p0, 0);
310         this->srcPixel(dst, p1, 1);
311         this->srcPixel(dst, p2, 2);
312         this->srcPixel(dst, p3, 3);
313         fDst += 4;
314     }
315 
setDestination(void * dst,int count)316     void setDestination(void* dst, int count) override {
317         fDst = static_cast<SkPM4f*>(dst);
318         fEnd = fDst + count;
319     }
320 
321 private:
srcPixel(SkPM4f * dst,Sk4f pixel,int index)322     void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
323         check_pixel(pixel);
324 
325         Sk4f newPixel = pixel;
326         if (alphaType == kUnpremul_SkAlphaType) {
327             newPixel = Premultiply(pixel);
328         }
329         newPixel = newPixel * fPostAlpha;
330         newPixel.store(dst + index);
331     }
Premultiply(Sk4f pixel)332     static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
333         float alpha = pixel[3];
334         return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
335     }
336 
337     SkPM4f* fDst;
338     SkPM4f* fEnd;
339     float   fPostAlpha;
340 };
341 
342 }  // namespace
343 
344 ////////////////////////////////////////////////////////////////////////////////////////////////////
345 // SkLinearBitmapPipeline
~SkLinearBitmapPipeline()346 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
347 
SkLinearBitmapPipeline(const SkMatrix & inverse,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,SkColor paintColor,const SkPixmap & srcPixmap,SkArenaAlloc * allocator)348 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
349     const SkMatrix& inverse,
350     SkFilterQuality filterQuality,
351     SkShader::TileMode xTile, SkShader::TileMode yTile,
352     SkColor paintColor,
353     const SkPixmap& srcPixmap,
354     SkArenaAlloc* allocator)
355 {
356     SkISize dimensions = srcPixmap.info().dimensions();
357     const SkImageInfo& srcImageInfo = srcPixmap.info();
358 
359     SkMatrix adjustedInverse = inverse;
360     if (filterQuality == kNone_SkFilterQuality) {
361         if (inverse.getScaleX() >= 0.0f) {
362             adjustedInverse.setTranslateX(
363                 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
364         }
365         if (inverse.getScaleY() >= 0.0f) {
366             adjustedInverse.setTranslateY(
367                 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
368         }
369     }
370 
371     SkScalar dx = adjustedInverse.getScaleX();
372 
373     // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
374     SkAlphaType alphaType = srcImageInfo.alphaType();
375     if (srcPixmap.colorType() == kIndex_8_SkColorType) {
376         alphaType = kUnpremul_SkAlphaType;
377     }
378 
379     float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
380     // As the stages are built, the chooser function may skip a stage. For example, with the
381     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
382     auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
383     auto samplerStage = this->chooseSampler(
384         blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
385     auto tilerStage   = this->chooseTiler(
386         samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
387     fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
388     fLastStage        = blenderStage;
389 }
390 
SkLinearBitmapPipeline(const SkLinearBitmapPipeline & pipeline,const SkPixmap & srcPixmap,SkBlendMode mode,const SkImageInfo & dstInfo,SkArenaAlloc * allocator)391 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
392     const SkLinearBitmapPipeline& pipeline,
393     const SkPixmap& srcPixmap,
394     SkBlendMode mode,
395     const SkImageInfo& dstInfo,
396     SkArenaAlloc* allocator)
397 {
398     SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
399     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
400              && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
401 
402     SampleProcessorInterface* sampleStage;
403     if (mode == SkBlendMode::kSrc) {
404         auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
405             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
406         sampleStage = sampler;
407         fLastStage = sampler;
408     } else {
409         auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
410             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
411         sampleStage = sampler;
412         fLastStage = sampler;
413     }
414 
415     auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
416     auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
417     fFirstStage = matrixStage;
418 }
419 
ClonePipelineForBlitting(const SkLinearBitmapPipeline & pipeline,SkMatrix::TypeMask matrixMask,SkFilterQuality filterQuality,const SkPixmap & srcPixmap,float finalAlpha,SkBlendMode blendMode,const SkImageInfo & dstInfo,SkArenaAlloc * allocator)420 SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting(
421     const SkLinearBitmapPipeline& pipeline,
422     SkMatrix::TypeMask matrixMask,
423     SkFilterQuality filterQuality,
424     const SkPixmap& srcPixmap,
425     float finalAlpha,
426     SkBlendMode blendMode,
427     const SkImageInfo& dstInfo,
428     SkArenaAlloc* allocator)
429 {
430     if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
431         blendMode = SkBlendMode::kSrc;
432     }
433 
434     if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
435     if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
436     if (finalAlpha != 1.0f) { return nullptr; }
437     if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
438         || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
439 
440     if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
441         return nullptr;
442     }
443 
444     if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
445         return nullptr;
446     }
447 
448     return allocator->make<SkLinearBitmapPipeline>(
449         pipeline, srcPixmap, blendMode, dstInfo, allocator);
450 }
451 
shadeSpan4f(int x,int y,SkPM4f * dst,int count)452 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
453     SkASSERT(count > 0);
454     this->blitSpan(x, y, dst, count);
455 }
456 
blitSpan(int x,int y,void * dst,int count)457 void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
458     SkASSERT(count > 0);
459     fLastStage->setDestination(dst, count);
460 
461     // The count and length arguments start out in a precise relation in order to keep the
462     // math correct through the different stages. Count is the number of pixel to produce.
463     // Since the code samples at pixel centers, length is the distance from the center of the
464     // first pixel to the center of the last pixel. This implies that length is count-1.
465     fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
466 }
467 
468 SkLinearBitmapPipeline::PointProcessorInterface*
chooseMatrix(PointProcessorInterface * next,const SkMatrix & inverse,SkArenaAlloc * allocator)469 SkLinearBitmapPipeline::chooseMatrix(
470     PointProcessorInterface* next,
471     const SkMatrix& inverse,
472     SkArenaAlloc* allocator)
473 {
474     if (inverse.hasPerspective()) {
475         auto matrixStage = allocator->make<PerspectiveMatrix<>>(
476             next,
477             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
478             SkVector{inverse.getScaleX(), inverse.getScaleY()},
479             SkVector{inverse.getSkewX(), inverse.getSkewY()},
480             SkVector{inverse.getPerspX(), inverse.getPerspY()},
481             inverse.get(SkMatrix::kMPersp2));
482         fMatrixStageCloner =
483             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
484                 return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
485             };
486         return matrixStage;
487     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
488         auto matrixStage = allocator->make<AffineMatrix<>>(
489             next,
490             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
491             SkVector{inverse.getScaleX(), inverse.getScaleY()},
492             SkVector{inverse.getSkewX(), inverse.getSkewY()});
493         fMatrixStageCloner =
494             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
495                 return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
496             };
497         return matrixStage;
498     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
499         auto matrixStage = allocator->make<ScaleMatrix<>>(
500             next,
501             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
502             SkVector{inverse.getScaleX(), inverse.getScaleY()});
503         fMatrixStageCloner =
504             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
505                 return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
506             };
507         return matrixStage;
508     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
509         auto matrixStage = allocator->make<TranslateMatrix<>>(
510             next,
511             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
512         fMatrixStageCloner =
513             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
514                 return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
515             };
516         return matrixStage;
517     } else {
518         fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
519             return cloneNext;
520         };
521         return next;
522     }
523 }
524 
525 template <typename Tiler>
createTiler(SampleProcessorInterface * next,SkISize dimensions,SkArenaAlloc * allocator)526 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
527     SampleProcessorInterface* next,
528     SkISize dimensions,
529     SkArenaAlloc* allocator)
530 {
531     auto tilerStage = allocator->make<Tiler>(next, dimensions);
532     fTileStageCloner =
533         [tilerStage](SampleProcessorInterface* cloneNext,
534                      SkArenaAlloc* memory) -> PointProcessorInterface* {
535             return memory->make<Tiler>(cloneNext, tilerStage);
536         };
537     return tilerStage;
538 }
539 
540 template <typename XStrategy>
chooseTilerYMode(SampleProcessorInterface * next,SkShader::TileMode yMode,SkISize dimensions,SkArenaAlloc * allocator)541 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
542     SampleProcessorInterface* next,
543     SkShader::TileMode yMode,
544     SkISize dimensions,
545     SkArenaAlloc* allocator)
546 {
547     switch (yMode) {
548         case SkShader::kClamp_TileMode: {
549             using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
550             return this->createTiler<Tiler>(next, dimensions, allocator);
551         }
552         case SkShader::kRepeat_TileMode: {
553             using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
554             return this->createTiler<Tiler>(next, dimensions, allocator);
555         }
556         case SkShader::kMirror_TileMode: {
557             using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
558             return this->createTiler<Tiler>(next, dimensions, allocator);
559         }
560     }
561 
562     // Should never get here.
563     SkFAIL("Not all Y tile cases covered.");
564     return nullptr;
565 }
566 
chooseTiler(SampleProcessorInterface * next,SkISize dimensions,SkShader::TileMode xMode,SkShader::TileMode yMode,SkFilterQuality filterQuality,SkScalar dx,SkArenaAlloc * allocator)567 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler(
568     SampleProcessorInterface* next,
569     SkISize dimensions,
570     SkShader::TileMode xMode,
571     SkShader::TileMode yMode,
572     SkFilterQuality filterQuality,
573     SkScalar dx,
574     SkArenaAlloc* allocator)
575 {
576     switch (xMode) {
577         case SkShader::kClamp_TileMode:
578             return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
579         case SkShader::kRepeat_TileMode:
580             if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
581                 return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
582                     next, yMode, dimensions, allocator);
583             } else {
584                 return this->chooseTilerYMode<XRepeatStrategy>(
585                     next, yMode, dimensions, allocator);
586             }
587         case SkShader::kMirror_TileMode:
588             return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
589     }
590 
591     // Should never get here.
592     SkFAIL("Not all X tile cases covered.");
593     return nullptr;
594 }
595 
596 template <SkColorType colorType>
597 SkLinearBitmapPipeline::PixelAccessorInterface*
chooseSpecificAccessor(const SkPixmap & srcPixmap,SkArenaAlloc * allocator)598     SkLinearBitmapPipeline::chooseSpecificAccessor(
599     const SkPixmap& srcPixmap,
600     SkArenaAlloc* allocator)
601 {
602     if (srcPixmap.info().gammaCloseToSRGB()) {
603         using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
604         return allocator->make<Accessor>(srcPixmap);
605     } else {
606         using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
607         return allocator->make<Accessor>(srcPixmap);
608     }
609 }
610 
choosePixelAccessor(const SkPixmap & srcPixmap,const SkColor A8TintColor,SkArenaAlloc * allocator)611 SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
612     const SkPixmap& srcPixmap,
613     const SkColor A8TintColor,
614     SkArenaAlloc* allocator)
615 {
616     const SkImageInfo& imageInfo = srcPixmap.info();
617 
618     switch (imageInfo.colorType()) {
619         case kAlpha_8_SkColorType: {
620             using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
621             return allocator->make<Accessor>(srcPixmap, A8TintColor);
622         }
623         case kARGB_4444_SkColorType:
624             return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
625         case kRGB_565_SkColorType:
626             return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
627         case kRGBA_8888_SkColorType:
628             return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
629         case kBGRA_8888_SkColorType:
630             return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
631         case kIndex_8_SkColorType:
632             return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
633         case kGray_8_SkColorType:
634             return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
635         case kRGBA_F16_SkColorType: {
636             using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
637             return allocator->make<Accessor>(srcPixmap);
638         }
639         default:
640             // Should never get here.
641             SkFAIL("Pixel source not supported.");
642             return nullptr;
643     }
644 }
645 
chooseSampler(Blender * next,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,const SkPixmap & srcPixmap,const SkColor A8TintColor,SkArenaAlloc * allocator)646 SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler(
647     Blender* next,
648     SkFilterQuality filterQuality,
649     SkShader::TileMode xTile, SkShader::TileMode yTile,
650     const SkPixmap& srcPixmap,
651     const SkColor A8TintColor,
652     SkArenaAlloc* allocator)
653 {
654     const SkImageInfo& imageInfo = srcPixmap.info();
655     SkISize dimensions = imageInfo.dimensions();
656 
657     // Special case samplers with fully expanded templates
658     if (imageInfo.gammaCloseToSRGB()) {
659         if (filterQuality == kNone_SkFilterQuality) {
660             switch (imageInfo.colorType()) {
661                 case kN32_SkColorType: {
662                     using Sampler =
663                     NearestNeighborSampler<
664                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
665                     return allocator->make<Sampler>(next, srcPixmap);
666                 }
667                 case kIndex_8_SkColorType: {
668                     using Sampler =
669                     NearestNeighborSampler<
670                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
671                     return allocator->make<Sampler>(next, srcPixmap);
672                 }
673                 default:
674                     break;
675             }
676         } else {
677             switch (imageInfo.colorType()) {
678                 case kN32_SkColorType: {
679                     using Sampler =
680                     BilerpSampler<
681                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
682                     return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
683                 }
684                 case kIndex_8_SkColorType: {
685                     using Sampler =
686                     BilerpSampler<
687                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
688                     return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
689                 }
690                 default:
691                     break;
692             }
693         }
694     }
695 
696     auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
697     // General cases.
698     if (filterQuality == kNone_SkFilterQuality) {
699         using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
700         return allocator->make<Sampler>(next, pixelAccessor);
701     } else {
702         using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
703         return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
704     }
705 }
706 
chooseBlenderForShading(SkAlphaType alphaType,float postAlpha,SkArenaAlloc * allocator)707 Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
708     SkAlphaType alphaType,
709     float postAlpha,
710     SkArenaAlloc* allocator)
711 {
712     if (alphaType == kUnpremul_SkAlphaType) {
713         return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
714     } else {
715         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
716         return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
717     }
718 }
719