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