Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      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 "SkColorSpace.h"
     10 #include "SkCoreBlitters.h"
     11 #include "SkOpts.h"
     12 #include "SkPM4fPriv.h"
     13 #include "SkRasterPipeline.h"
     14 #include "SkSpriteBlitter.h"
     15 
     16 SkSpriteBlitter::SkSpriteBlitter(const SkPixmap& source)
     17     : fSource(source) {}
     18 
     19 void SkSpriteBlitter::setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) {
     20     fDst = dst;
     21     fLeft = left;
     22     fTop = top;
     23     fPaint = &paint;
     24 }
     25 
     26 void SkSpriteBlitter::blitH(int x, int y, int width) {
     27     SkDEBUGFAIL("how did we get here?");
     28 
     29     // Fallback to blitRect.
     30     this->blitRect(x, y, width, 1);
     31 }
     32 
     33 void SkSpriteBlitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) {
     34     SkDEBUGFAIL("how did we get here?");
     35 
     36     // No fallback strategy.
     37 }
     38 
     39 void SkSpriteBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
     40     SkDEBUGFAIL("how did we get here?");
     41 
     42     // Fall back to superclass if the code gets here in release mode.
     43     INHERITED::blitV(x, y, height, alpha);
     44 }
     45 
     46 void SkSpriteBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
     47     SkDEBUGFAIL("how did we get here?");
     48 
     49     // Fall back to superclass if the code gets here in release mode.
     50     INHERITED::blitMask(mask, clip);
     51 }
     52 
     53 ///////////////////////////////////////////////////////////////////////////////
     54 
     55 class SkSpriteBlitter_Memcpy final : public SkSpriteBlitter {
     56 public:
     57     static bool Supports(const SkPixmap& dst, const SkPixmap& src, const SkPaint& paint) {
     58         if (dst.colorType() != src.colorType()) {
     59             return false;
     60         }
     61         if (!SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) {
     62             return false;
     63         }
     64         if (paint.getMaskFilter() || paint.getColorFilter() || paint.getImageFilter()) {
     65             return false;
     66         }
     67         if (0xFF != paint.getAlpha()) {
     68             return false;
     69         }
     70         SkBlendMode mode = paint.getBlendMode();
     71         return SkBlendMode::kSrc == mode || (SkBlendMode::kSrcOver == mode && src.isOpaque());
     72     }
     73 
     74     SkSpriteBlitter_Memcpy(const SkPixmap& src)
     75         : INHERITED(src) {}
     76 
     77     void blitRect(int x, int y, int width, int height) override {
     78         SkASSERT(fDst.colorType() == fSource.colorType());
     79         SkASSERT(width > 0 && height > 0);
     80 
     81         char* dst = (char*)fDst.writable_addr(x, y);
     82         const char* src = (const char*)fSource.addr(x - fLeft, y - fTop);
     83         const size_t dstRB = fDst.rowBytes();
     84         const size_t srcRB = fSource.rowBytes();
     85         const size_t bytesToCopy = width << fSource.shiftPerPixel();
     86 
     87         while (height --> 0) {
     88             memcpy(dst, src, bytesToCopy);
     89             dst += dstRB;
     90             src += srcRB;
     91         }
     92     }
     93 
     94 private:
     95     typedef SkSpriteBlitter INHERITED;
     96 };
     97 
     98 class SkRasterPipelineSpriteBlitter : public SkSpriteBlitter {
     99 public:
    100     SkRasterPipelineSpriteBlitter(const SkPixmap& src, SkArenaAlloc* alloc)
    101         : INHERITED(src)
    102         , fAlloc(alloc)
    103         , fBlitter(nullptr)
    104         , fSrcPtr(nullptr)
    105     {}
    106 
    107     void setup(const SkPixmap& dst, int left, int top, const SkPaint& paint) override {
    108         fDst  = dst;
    109         fLeft = left;
    110         fTop  = top;
    111 
    112         fPaintColor = SkColor4f_from_SkColor(paint.getColor(), fDst.colorSpace());
    113 
    114         SkRasterPipeline p(fAlloc);
    115         switch (fSource.colorType()) {
    116             case kAlpha_8_SkColorType:   p.append(SkRasterPipeline::load_a8,   &fSrcPtr); break;
    117             case kGray_8_SkColorType:    p.append(SkRasterPipeline::load_g8,   &fSrcPtr); break;
    118             case kRGB_565_SkColorType:   p.append(SkRasterPipeline::load_565,  &fSrcPtr); break;
    119             case kARGB_4444_SkColorType: p.append(SkRasterPipeline::load_4444, &fSrcPtr); break;
    120             case kBGRA_8888_SkColorType: p.append(SkRasterPipeline::load_bgra, &fSrcPtr); break;
    121             case kRGBA_8888_SkColorType: p.append(SkRasterPipeline::load_8888, &fSrcPtr); break;
    122             case kRGBA_F16_SkColorType:  p.append(SkRasterPipeline::load_f16,  &fSrcPtr); break;
    123             default: SkASSERT(false);
    124         }
    125         if (fDst.colorSpace() &&
    126                 (!fSource.colorSpace() || fSource.colorSpace()->gammaCloseToSRGB())) {
    127             p.append_from_srgb(fSource.alphaType());
    128         }
    129         if (fSource.colorType() == kAlpha_8_SkColorType) {
    130             p.append(SkRasterPipeline::set_rgb, &fPaintColor);
    131             p.append(SkRasterPipeline::premul);
    132         }
    133         append_gamut_transform(&p, fAlloc,
    134                                fSource.colorSpace(), fDst.colorSpace(), kPremul_SkAlphaType);
    135         if (fPaintColor.fA != 1.0f) {
    136             p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA);
    137         }
    138 
    139         bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f;
    140         fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc);
    141     }
    142 
    143     void blitRect(int x, int y, int width, int height) override {
    144         fSrcPtr = (const char*)fSource.addr(x-fLeft,y-fTop);
    145 
    146         // Our pipeline will load from fSrcPtr+x, fSrcPtr+x+1, etc.,
    147         // so we back up an extra x pixels to start at 0.
    148         fSrcPtr -= fSource.info().bytesPerPixel() * x;
    149 
    150         while (height --> 0) {
    151             fBlitter->blitH(x,y++, width);
    152             fSrcPtr += fSource.rowBytes();
    153         }
    154     }
    155 
    156 private:
    157     SkArenaAlloc* fAlloc;
    158     SkBlitter*    fBlitter;
    159     const char*   fSrcPtr;
    160     SkColor4f     fPaintColor;
    161 
    162     typedef SkSpriteBlitter INHERITED;
    163 };
    164 
    165 // returning null means the caller will call SkBlitter::Choose() and
    166 // have wrapped the source bitmap inside a shader
    167 SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint,
    168         const SkPixmap& source, int left, int top, SkArenaAlloc* allocator) {
    169     /*  We currently ignore antialiasing and filtertype, meaning we will take our
    170         special blitters regardless of these settings. Ignoring filtertype seems fine
    171         since by definition there is no scale in the matrix. Ignoring antialiasing is
    172         a bit of a hack, since we "could" pass in the fractional left/top for the bitmap,
    173         and respect that by blending the edges of the bitmap against the device. To support
    174         this we could either add more special blitters here, or detect antialiasing in the
    175         paint and return null if it is set, forcing the client to take the slow shader case
    176         (which does respect soft edges).
    177     */
    178     SkASSERT(allocator != nullptr);
    179 
    180     if (source.alphaType() == kUnpremul_SkAlphaType) {
    181         return nullptr;
    182     }
    183 
    184     SkSpriteBlitter* blitter = nullptr;
    185 
    186     if (!blitter && SkSpriteBlitter_Memcpy::Supports(dst, source, paint)) {
    187         blitter = allocator->make<SkSpriteBlitter_Memcpy>(source);
    188     }
    189     if (!blitter && !dst.colorSpace()) {
    190         switch (dst.colorType()) {
    191             case kN32_SkColorType:
    192                 blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator);
    193                 break;
    194             case kRGB_565_SkColorType:
    195                 blitter = SkSpriteBlitter::ChooseL565(source, paint, allocator);
    196                 break;
    197             case kAlpha_8_SkColorType:
    198                 blitter = SkSpriteBlitter::ChooseLA8(source, paint, allocator);
    199                 break;
    200             default:
    201                 break;
    202         }
    203     }
    204     if (!blitter) {
    205         blitter = allocator->make<SkRasterPipelineSpriteBlitter>(source, allocator);
    206     }
    207 
    208     if (blitter) {
    209         blitter->setup(dst, left, top, paint);
    210     }
    211     return blitter;
    212 }
    213