LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkLinearBitmapPipeline.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 324 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 196 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
      39             : public:
      40             :     template <typename... Args>
      41           0 :     MatrixStage(Next* next, Args&&... args)
      42             :         : fNext{next}
      43           0 :         , fStrategy{std::forward<Args>(args)...}{ }
      44             : 
      45           0 :     MatrixStage(Next* next, MatrixStage* stage)
      46             :         : fNext{next}
      47           0 :         , fStrategy{stage->fStrategy} { }
      48             : 
      49           0 :     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
      50           0 :         fStrategy.processPoints(&xs, &ys);
      51           0 :         fNext->pointListFew(n, xs, ys);
      52           0 :     }
      53             : 
      54           0 :     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
      55           0 :         fStrategy.processPoints(&xs, &ys);
      56           0 :         fNext->pointList4(xs, ys);
      57           0 :     }
      58             : 
      59             :     // The span you pass must not be empty.
      60           0 :     void pointSpan(Span span) override {
      61           0 :         SkASSERT(!span.isEmpty());
      62           0 :         if (!fStrategy.maybeProcessSpan(span, fNext)) {
      63           0 :             span_fallback(span, this);
      64             :         }
      65           0 :     }
      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           0 : class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
      90             : public:
      91           0 :     CombinedTileStage(Next* next, SkISize dimensions)
      92             :         : fNext{next}
      93             :         , fXStrategy{dimensions.width()}
      94           0 :         , fYStrategy{dimensions.height()}{ }
      95             : 
      96           0 :     CombinedTileStage(Next* next, CombinedTileStage* stage)
      97             :         : fNext{next}
      98             :         , fXStrategy{stage->fXStrategy}
      99           0 :         , fYStrategy{stage->fYStrategy} { }
     100             : 
     101           0 :     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
     102           0 :         fXStrategy.tileXPoints(&xs);
     103           0 :         fYStrategy.tileYPoints(&ys);
     104           0 :         fNext->pointListFew(n, xs, ys);
     105           0 :     }
     106             : 
     107           0 :     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
     108           0 :         fXStrategy.tileXPoints(&xs);
     109           0 :         fYStrategy.tileYPoints(&ys);
     110           0 :         fNext->pointList4(xs, ys);
     111           0 :     }
     112             : 
     113             :     // The span you pass must not be empty.
     114           0 :     void pointSpan(Span span) override {
     115           0 :         SkASSERT(!span.isEmpty());
     116             :         SkPoint start; SkScalar length; int count;
     117           0 :         std::tie(start, length, count) = span;
     118             : 
     119           0 :         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           0 :             this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
     125           0 :             return;
     126             :         }
     127             : 
     128           0 :         SkScalar x = X(start);
     129           0 :         SkScalar y = fYStrategy.tileY(Y(start));
     130           0 :         Span yAdjustedSpan{{x, y}, length, count};
     131             : 
     132           0 :         if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
     133           0 :             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           0 : class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
     150             :                                     public SkLinearBitmapPipeline::DestinationInterface {
     151             : public:
     152           0 :     RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
     153           0 :         : fSrc{src}, fWidth{width} { }
     154             : 
     155           0 :     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
     156           0 :         SkASSERT(fDest + n <= fEnd);
     157             :         // At this point xs and ys should be >= 0, so trunc is the same as floor.
     158           0 :         Sk4i iXs = SkNx_cast<int>(xs);
     159           0 :         Sk4i iYs = SkNx_cast<int>(ys);
     160             : 
     161           0 :         if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
     162           0 :         if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
     163           0 :         if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
     164           0 :     }
     165             : 
     166           0 :     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
     167           0 :         SkASSERT(fDest + 4 <= fEnd);
     168           0 :         Sk4i iXs = SkNx_cast<int>(xs);
     169           0 :         Sk4i iYs = SkNx_cast<int>(ys);
     170           0 :         *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
     171           0 :         *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
     172           0 :         *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
     173           0 :         *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
     174           0 :     }
     175             : 
     176           0 :     void pointSpan(Span span) override {
     177           0 :         SkASSERT(fDest + span.count() <= fEnd);
     178           0 :         if (span.length() != 0.0f) {
     179           0 :             int32_t x = SkScalarTruncToInt(span.startX());
     180           0 :             int32_t y = SkScalarTruncToInt(span.startY());
     181           0 :             const uint32_t* src = this->pixelAddress(x, y);
     182           0 :             memmove(fDest, src, span.count() * sizeof(uint32_t));
     183           0 :             fDest += span.count();
     184             :         }
     185           0 :     }
     186             : 
     187           0 :     void repeatSpan(Span span, int32_t repeatCount) override {
     188           0 :         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
     189             : 
     190           0 :         int32_t x = SkScalarTruncToInt(span.startX());
     191           0 :         int32_t y = SkScalarTruncToInt(span.startY());
     192           0 :         const uint32_t* src = this->pixelAddress(x, y);
     193           0 :         uint32_t* dest = fDest;
     194           0 :         while (repeatCount --> 0) {
     195           0 :             memmove(dest, src, span.count() * sizeof(uint32_t));
     196           0 :             dest += span.count();
     197             :         }
     198           0 :         fDest = dest;
     199           0 :     }
     200             : 
     201           0 :     void setDestination(void* dst, int count) override  {
     202           0 :         fDest = static_cast<uint32_t*>(dst);
     203           0 :         fEnd = fDest + count;
     204           0 :     }
     205             : 
     206             : private:
     207           0 :     const uint32_t* pixelAddress(int32_t x, int32_t y) {
     208           0 :         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           0 : class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
     220             :                                         public SkLinearBitmapPipeline::DestinationInterface {
     221             : public:
     222           0 :     RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
     223           0 :         : fSrc{src}, fWidth{width} { }
     224             : 
     225           0 :     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
     226           0 :         SkASSERT(fDest + n <= fEnd);
     227             :         // At this point xs and ys should be >= 0, so trunc is the same as floor.
     228           0 :         Sk4i iXs = SkNx_cast<int>(xs);
     229           0 :         Sk4i iYs = SkNx_cast<int>(ys);
     230             : 
     231           0 :         if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
     232           0 :         if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
     233           0 :         if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
     234           0 :     }
     235             : 
     236           0 :     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
     237           0 :         SkASSERT(fDest + 4 <= fEnd);
     238           0 :         Sk4i iXs = SkNx_cast<int>(xs);
     239           0 :         Sk4i iYs = SkNx_cast<int>(ys);
     240           0 :         blendPixelAt(iXs[0], iYs[0]);
     241           0 :         blendPixelAt(iXs[1], iYs[1]);
     242           0 :         blendPixelAt(iXs[2], iYs[2]);
     243           0 :         blendPixelAt(iXs[3], iYs[3]);
     244           0 :     }
     245             : 
     246           0 :     void pointSpan(Span span) override {
     247           0 :         if (span.length() != 0.0f) {
     248           0 :             this->repeatSpan(span, 1);
     249             :         }
     250           0 :     }
     251             : 
     252           0 :     void repeatSpan(Span span, int32_t repeatCount) override {
     253           0 :         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
     254           0 :         SkASSERT(span.count() > 0);
     255           0 :         SkASSERT(repeatCount > 0);
     256             : 
     257           0 :         int32_t x = (int32_t)span.startX();
     258           0 :         int32_t y = (int32_t)span.startY();
     259           0 :         const uint32_t* beginSpan = this->pixelAddress(x, y);
     260             : 
     261           0 :         SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
     262             : 
     263           0 :         fDest += span.count() * repeatCount;
     264             : 
     265           0 :         SkASSERT(fDest <= fEnd);
     266           0 :     }
     267             : 
     268           0 :     void setDestination(void* dst, int count) override  {
     269           0 :         SkASSERT(count > 0);
     270           0 :         fDest = static_cast<uint32_t*>(dst);
     271           0 :         fEnd = fDest + count;
     272           0 :     }
     273             : 
     274             : private:
     275           0 :     const uint32_t* pixelAddress(int32_t x, int32_t y) {
     276           0 :         return &fSrc[fWidth * y + x];
     277             :     }
     278             : 
     279           0 :     void blendPixelAt(int32_t x, int32_t y) {
     280           0 :         const uint32_t* src = this->pixelAddress(x, y);
     281           0 :         SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
     282           0 :         fDest += 1;
     283           0 :     }
     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           0 : class SrcFPPixel final : public Blender {
     297             : public:
     298           0 :     SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
     299             :     SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
     300           0 :     void SK_VECTORCALL blendPixel(Sk4f pixel) override {
     301           0 :         SkASSERT(fDst + 1 <= fEnd );
     302           0 :         this->srcPixel(fDst, pixel, 0);
     303           0 :         fDst += 1;
     304           0 :     }
     305             : 
     306           0 :     void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
     307           0 :         SkASSERT(fDst + 4 <= fEnd);
     308           0 :         SkPM4f* dst = fDst;
     309           0 :         this->srcPixel(dst, p0, 0);
     310           0 :         this->srcPixel(dst, p1, 1);
     311           0 :         this->srcPixel(dst, p2, 2);
     312           0 :         this->srcPixel(dst, p3, 3);
     313           0 :         fDst += 4;
     314           0 :     }
     315             : 
     316           0 :     void setDestination(void* dst, int count) override {
     317           0 :         fDst = static_cast<SkPM4f*>(dst);
     318           0 :         fEnd = fDst + count;
     319           0 :     }
     320             : 
     321             : private:
     322           0 :     void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
     323           0 :         check_pixel(pixel);
     324             : 
     325           0 :         Sk4f newPixel = pixel;
     326             :         if (alphaType == kUnpremul_SkAlphaType) {
     327           0 :             newPixel = Premultiply(pixel);
     328             :         }
     329           0 :         newPixel = newPixel * fPostAlpha;
     330           0 :         newPixel.store(dst + index);
     331           0 :     }
     332           0 :     static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
     333           0 :         float alpha = pixel[3];
     334           0 :         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
     346           0 : SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
     347             : 
     348           0 : SkLinearBitmapPipeline::SkLinearBitmapPipeline(
     349             :     const SkMatrix& inverse,
     350             :     SkFilterQuality filterQuality,
     351             :     SkShader::TileMode xTile, SkShader::TileMode yTile,
     352             :     SkColor paintColor,
     353             :     const SkPixmap& srcPixmap,
     354           0 :     SkArenaAlloc* allocator)
     355             : {
     356           0 :     SkISize dimensions = srcPixmap.info().dimensions();
     357           0 :     const SkImageInfo& srcImageInfo = srcPixmap.info();
     358             : 
     359           0 :     SkMatrix adjustedInverse = inverse;
     360           0 :     if (filterQuality == kNone_SkFilterQuality) {
     361           0 :         if (inverse.getScaleX() >= 0.0f) {
     362           0 :             adjustedInverse.setTranslateX(
     363           0 :                 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
     364             :         }
     365           0 :         if (inverse.getScaleY() >= 0.0f) {
     366           0 :             adjustedInverse.setTranslateY(
     367           0 :                 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
     368             :         }
     369             :     }
     370             : 
     371           0 :     SkScalar dx = adjustedInverse.getScaleX();
     372             : 
     373             :     // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
     374           0 :     SkAlphaType alphaType = srcImageInfo.alphaType();
     375           0 :     if (srcPixmap.colorType() == kIndex_8_SkColorType) {
     376           0 :         alphaType = kUnpremul_SkAlphaType;
     377             :     }
     378             : 
     379           0 :     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           0 :     auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
     383             :     auto samplerStage = this->chooseSampler(
     384           0 :         blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
     385             :     auto tilerStage   = this->chooseTiler(
     386           0 :         samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
     387           0 :     fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
     388           0 :     fLastStage        = blenderStage;
     389           0 : }
     390             : 
     391           0 : SkLinearBitmapPipeline::SkLinearBitmapPipeline(
     392             :     const SkLinearBitmapPipeline& pipeline,
     393             :     const SkPixmap& srcPixmap,
     394             :     SkBlendMode mode,
     395             :     const SkImageInfo& dstInfo,
     396           0 :     SkArenaAlloc* allocator)
     397             : {
     398           0 :     SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
     399           0 :     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
     400             :              && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
     401             : 
     402             :     SampleProcessorInterface* sampleStage;
     403           0 :     if (mode == SkBlendMode::kSrc) {
     404             :         auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
     405           0 :             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
     406           0 :         sampleStage = sampler;
     407           0 :         fLastStage = sampler;
     408             :     } else {
     409             :         auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
     410           0 :             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
     411           0 :         sampleStage = sampler;
     412           0 :         fLastStage = sampler;
     413             :     }
     414             : 
     415           0 :     auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
     416           0 :     auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
     417           0 :     fFirstStage = matrixStage;
     418           0 : }
     419             : 
     420           0 : 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           0 :     if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
     431           0 :         blendMode = SkBlendMode::kSrc;
     432             :     }
     433             : 
     434           0 :     if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
     435           0 :     if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
     436           0 :     if (finalAlpha != 1.0f) { return nullptr; }
     437           0 :     if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
     438           0 :         || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
     439             : 
     440           0 :     if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
     441           0 :         return nullptr;
     442             :     }
     443             : 
     444           0 :     if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
     445           0 :         return nullptr;
     446             :     }
     447             : 
     448           0 :     return allocator->make<SkLinearBitmapPipeline>(
     449           0 :         pipeline, srcPixmap, blendMode, dstInfo, allocator);
     450             : }
     451             : 
     452           0 : void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
     453           0 :     SkASSERT(count > 0);
     454           0 :     this->blitSpan(x, y, dst, count);
     455           0 : }
     456             : 
     457           0 : void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
     458           0 :     SkASSERT(count > 0);
     459           0 :     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           0 :     fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
     466           0 : }
     467             : 
     468             : SkLinearBitmapPipeline::PointProcessorInterface*
     469           0 : SkLinearBitmapPipeline::chooseMatrix(
     470             :     PointProcessorInterface* next,
     471             :     const SkMatrix& inverse,
     472             :     SkArenaAlloc* allocator)
     473             : {
     474           0 :     if (inverse.hasPerspective()) {
     475             :         auto matrixStage = allocator->make<PerspectiveMatrix<>>(
     476             :             next,
     477           0 :             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
     478           0 :             SkVector{inverse.getScaleX(), inverse.getScaleY()},
     479           0 :             SkVector{inverse.getSkewX(), inverse.getSkewY()},
     480           0 :             SkVector{inverse.getPerspX(), inverse.getPerspY()},
     481           0 :             inverse.get(SkMatrix::kMPersp2));
     482             :         fMatrixStageCloner =
     483           0 :             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
     484           0 :                 return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
     485           0 :             };
     486           0 :         return matrixStage;
     487           0 :     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
     488             :         auto matrixStage = allocator->make<AffineMatrix<>>(
     489             :             next,
     490           0 :             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
     491           0 :             SkVector{inverse.getScaleX(), inverse.getScaleY()},
     492           0 :             SkVector{inverse.getSkewX(), inverse.getSkewY()});
     493             :         fMatrixStageCloner =
     494           0 :             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
     495           0 :                 return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
     496           0 :             };
     497           0 :         return matrixStage;
     498           0 :     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
     499             :         auto matrixStage = allocator->make<ScaleMatrix<>>(
     500             :             next,
     501           0 :             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
     502           0 :             SkVector{inverse.getScaleX(), inverse.getScaleY()});
     503             :         fMatrixStageCloner =
     504           0 :             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
     505           0 :                 return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
     506           0 :             };
     507           0 :         return matrixStage;
     508           0 :     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
     509             :         auto matrixStage = allocator->make<TranslateMatrix<>>(
     510             :             next,
     511           0 :             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
     512             :         fMatrixStageCloner =
     513           0 :             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
     514           0 :                 return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
     515           0 :             };
     516           0 :         return matrixStage;
     517             :     } else {
     518           0 :         fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
     519             :             return cloneNext;
     520           0 :         };
     521           0 :         return next;
     522             :     }
     523             : }
     524             : 
     525             : template <typename Tiler>
     526           0 : SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
     527             :     SampleProcessorInterface* next,
     528             :     SkISize dimensions,
     529             :     SkArenaAlloc* allocator)
     530             : {
     531           0 :     auto tilerStage = allocator->make<Tiler>(next, dimensions);
     532           0 :     fTileStageCloner =
     533             :         [tilerStage](SampleProcessorInterface* cloneNext,
     534           0 :                      SkArenaAlloc* memory) -> PointProcessorInterface* {
     535           0 :             return memory->make<Tiler>(cloneNext, tilerStage);
     536             :         };
     537           0 :     return tilerStage;
     538             : }
     539             : 
     540             : template <typename XStrategy>
     541           0 : SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
     542             :     SampleProcessorInterface* next,
     543             :     SkShader::TileMode yMode,
     544             :     SkISize dimensions,
     545             :     SkArenaAlloc* allocator)
     546             : {
     547           0 :     switch (yMode) {
     548             :         case SkShader::kClamp_TileMode: {
     549             :             using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
     550           0 :             return this->createTiler<Tiler>(next, dimensions, allocator);
     551             :         }
     552             :         case SkShader::kRepeat_TileMode: {
     553             :             using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
     554           0 :             return this->createTiler<Tiler>(next, dimensions, allocator);
     555             :         }
     556             :         case SkShader::kMirror_TileMode: {
     557             :             using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
     558           0 :             return this->createTiler<Tiler>(next, dimensions, allocator);
     559             :         }
     560             :     }
     561             : 
     562             :     // Should never get here.
     563           0 :     SkFAIL("Not all Y tile cases covered.");
     564           0 :     return nullptr;
     565             : }
     566             : 
     567           0 : 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           0 :     switch (xMode) {
     577             :         case SkShader::kClamp_TileMode:
     578           0 :             return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
     579             :         case SkShader::kRepeat_TileMode:
     580           0 :             if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
     581             :                 return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
     582           0 :                     next, yMode, dimensions, allocator);
     583             :             } else {
     584             :                 return this->chooseTilerYMode<XRepeatStrategy>(
     585           0 :                     next, yMode, dimensions, allocator);
     586             :             }
     587             :         case SkShader::kMirror_TileMode:
     588           0 :             return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
     589             :     }
     590             : 
     591             :     // Should never get here.
     592           0 :     SkFAIL("Not all X tile cases covered.");
     593           0 :     return nullptr;
     594             : }
     595             : 
     596             : template <SkColorType colorType>
     597             : SkLinearBitmapPipeline::PixelAccessorInterface*
     598           0 :     SkLinearBitmapPipeline::chooseSpecificAccessor(
     599             :     const SkPixmap& srcPixmap,
     600             :     SkArenaAlloc* allocator)
     601             : {
     602           0 :     if (srcPixmap.info().gammaCloseToSRGB()) {
     603             :         using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
     604           0 :         return allocator->make<Accessor>(srcPixmap);
     605             :     } else {
     606             :         using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
     607           0 :         return allocator->make<Accessor>(srcPixmap);
     608             :     }
     609             : }
     610             : 
     611           0 : SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
     612             :     const SkPixmap& srcPixmap,
     613             :     const SkColor A8TintColor,
     614             :     SkArenaAlloc* allocator)
     615             : {
     616           0 :     const SkImageInfo& imageInfo = srcPixmap.info();
     617             : 
     618           0 :     switch (imageInfo.colorType()) {
     619             :         case kAlpha_8_SkColorType: {
     620             :             using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
     621           0 :             return allocator->make<Accessor>(srcPixmap, A8TintColor);
     622             :         }
     623             :         case kARGB_4444_SkColorType:
     624           0 :             return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
     625             :         case kRGB_565_SkColorType:
     626           0 :             return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
     627             :         case kRGBA_8888_SkColorType:
     628           0 :             return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
     629             :         case kBGRA_8888_SkColorType:
     630           0 :             return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
     631             :         case kIndex_8_SkColorType:
     632           0 :             return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
     633             :         case kGray_8_SkColorType:
     634           0 :             return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
     635             :         case kRGBA_F16_SkColorType: {
     636             :             using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
     637           0 :             return allocator->make<Accessor>(srcPixmap);
     638             :         }
     639             :         default:
     640             :             // Should never get here.
     641           0 :             SkFAIL("Pixel source not supported.");
     642           0 :             return nullptr;
     643             :     }
     644             : }
     645             : 
     646           0 : 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           0 :     const SkImageInfo& imageInfo = srcPixmap.info();
     655           0 :     SkISize dimensions = imageInfo.dimensions();
     656             : 
     657             :     // Special case samplers with fully expanded templates
     658           0 :     if (imageInfo.gammaCloseToSRGB()) {
     659           0 :         if (filterQuality == kNone_SkFilterQuality) {
     660           0 :             switch (imageInfo.colorType()) {
     661             :                 case kN32_SkColorType: {
     662             :                     using Sampler =
     663             :                     NearestNeighborSampler<
     664             :                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
     665           0 :                     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           0 :                     return allocator->make<Sampler>(next, srcPixmap);
     672             :                 }
     673             :                 default:
     674           0 :                     break;
     675             :             }
     676             :         } else {
     677           0 :             switch (imageInfo.colorType()) {
     678             :                 case kN32_SkColorType: {
     679             :                     using Sampler =
     680             :                     BilerpSampler<
     681             :                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
     682           0 :                     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           0 :                     return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
     689             :                 }
     690             :                 default:
     691           0 :                     break;
     692             :             }
     693             :         }
     694             :     }
     695             : 
     696           0 :     auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
     697             :     // General cases.
     698           0 :     if (filterQuality == kNone_SkFilterQuality) {
     699             :         using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
     700           0 :         return allocator->make<Sampler>(next, pixelAccessor);
     701             :     } else {
     702             :         using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
     703           0 :         return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
     704             :     }
     705             : }
     706             : 
     707           0 : Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
     708             :     SkAlphaType alphaType,
     709             :     float postAlpha,
     710             :     SkArenaAlloc* allocator)
     711             : {
     712           0 :     if (alphaType == kUnpremul_SkAlphaType) {
     713           0 :         return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
     714             :     } else {
     715             :         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
     716           0 :         return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
     717             :     }
     718             : }

Generated by: LCOV version 1.13