Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 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 "SkSpriteBlitter.h"
      9 #include "SkArenaAlloc.h"
     10 #include "SkBlitRow.h"
     11 #include "SkColorFilter.h"
     12 #include "SkColorPriv.h"
     13 #include "SkTemplates.h"
     14 #include "SkUtils.h"
     15 #include "SkXfermodePriv.h"
     16 
     17 ///////////////////////////////////////////////////////////////////////////////
     18 
     19 static void S32_src(uint16_t dst[], const SkPMColor src[], int count) {
     20     for (int i = 0; i < count; ++i) {
     21         dst[i] = SkPixel32ToPixel16(src[i]);
     22     }
     23 }
     24 
     25 static void S32_srcover(uint16_t dst[], const SkPMColor src[], int count) {
     26     for (int i = 0; i < count; ++i) {
     27         dst[i] = SkSrcOver32To16(src[i], dst[i]);
     28     }
     29 }
     30 
     31 class Sprite_D16_S32 : public SkSpriteBlitter {
     32 public:
     33     Sprite_D16_S32(const SkPixmap& src, SkBlendMode mode)  : INHERITED(src) {
     34         SkASSERT(src.colorType() == kN32_SkColorType);
     35         SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
     36 
     37         fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque();
     38     }
     39 
     40     void blitRect(int x, int y, int width, int height) override {
     41         SkASSERT(width > 0 && height > 0);
     42         uint16_t* SK_RESTRICT dst = fDst.writable_addr16(x, y);
     43         const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
     44         size_t dstRB = fDst.rowBytes();
     45         size_t srcRB = fSource.rowBytes();
     46 
     47         do {
     48             if (fUseSrcOver) {
     49                 S32_srcover(dst, src, width);
     50             } else {
     51                 S32_src(dst, src, width);
     52             }
     53 
     54             dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
     55             src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
     56         } while (--height != 0);
     57     }
     58 
     59 private:
     60     bool fUseSrcOver;
     61 
     62     typedef SkSpriteBlitter INHERITED;
     63 };
     64 
     65 SkSpriteBlitter* SkSpriteBlitter::ChooseL565(const SkPixmap& source, const SkPaint& paint,
     66                                              SkArenaAlloc* allocator) {
     67     SkASSERT(allocator != nullptr);
     68 
     69     if (paint.getColorFilter() != nullptr) {
     70         return nullptr;
     71     }
     72     if (paint.getMaskFilter() != nullptr) {
     73         return nullptr;
     74     }
     75 
     76     U8CPU alpha = paint.getAlpha();
     77     if (alpha != 0xFF) {
     78         return nullptr;
     79     }
     80 
     81     if (source.colorType() == kN32_SkColorType) {
     82         switch (paint.getBlendMode()) {
     83             case SkBlendMode::kSrc:
     84             case SkBlendMode::kSrcOver:
     85                 return allocator->make<Sprite_D16_S32>(source, paint.getBlendMode());
     86             default:
     87                 break;
     88         }
     89     }
     90     return nullptr;
     91 }
     92 
     93 //////////////////////////////////////////////////////////////////////////////////////////////////
     94 
     95 static unsigned div255(unsigned a, unsigned b) {
     96     return (a * b * 257 + 127) >> 16;
     97 }
     98 
     99 static void S32_src_da8(uint8_t dst[], const SkPMColor src[], int count) {
    100     for (int i = 0; i < count; ++i) {
    101         dst[i] = SkGetPackedA32(src[i]);
    102     }
    103 }
    104 
    105 static void S32_srcover_da8(uint8_t dst[], const SkPMColor src[], int count) {
    106     for (int i = 0; i < count; ++i) {
    107         SkPMColor c = src[i];
    108         if (c) {
    109             unsigned a = SkGetPackedA32(c);
    110             if (a == 0xFF) {
    111                 dst[i] = 0xFF;
    112             } else {
    113                 dst[i] = a + div255(255 - a, dst[i]);
    114             }
    115         }
    116     }
    117 }
    118 
    119 class Sprite_D8_S32 : public SkSpriteBlitter {
    120 public:
    121     Sprite_D8_S32(const SkPixmap& src, SkBlendMode mode)  : INHERITED(src) {
    122         SkASSERT(src.colorType() == kN32_SkColorType);
    123         SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
    124 
    125         fUseSrcOver = (mode == SkBlendMode::kSrcOver) && !src.isOpaque();
    126     }
    127 
    128     void blitRect(int x, int y, int width, int height) override {
    129         SkASSERT(width > 0 && height > 0);
    130         uint8_t* SK_RESTRICT dst = fDst.writable_addr8(x, y);
    131         const uint32_t* SK_RESTRICT src = fSource.addr32(x - fLeft, y - fTop);
    132         size_t dstRB = fDst.rowBytes();
    133         size_t srcRB = fSource.rowBytes();
    134 
    135         do {
    136             if (fUseSrcOver) {
    137                 S32_srcover_da8(dst, src, width);
    138             } else {
    139                 S32_src_da8(dst, src, width);
    140             }
    141 
    142             dst = (uint8_t* SK_RESTRICT)((char*)dst + dstRB);
    143             src = (const uint32_t* SK_RESTRICT)((const char*)src + srcRB);
    144         } while (--height != 0);
    145     }
    146 
    147 private:
    148     bool fUseSrcOver;
    149 
    150     typedef SkSpriteBlitter INHERITED;
    151 };
    152 
    153 SkSpriteBlitter* SkSpriteBlitter::ChooseLA8(const SkPixmap& source, const SkPaint& paint,
    154                                             SkArenaAlloc* allocator) {
    155     SkASSERT(allocator != nullptr);
    156 
    157     if (paint.getColorFilter() != nullptr) {
    158         return nullptr;
    159     }
    160     if (paint.getMaskFilter() != nullptr) {
    161         return nullptr;
    162     }
    163 
    164     U8CPU alpha = paint.getAlpha();
    165     if (alpha != 0xFF) {
    166         return nullptr;
    167     }
    168 
    169     if (source.colorType() == kN32_SkColorType) {
    170         switch (paint.getBlendMode()) {
    171             case SkBlendMode::kSrc:
    172             case SkBlendMode::kSrcOver:
    173                 return allocator->make<Sprite_D8_S32>(source, paint.getBlendMode());
    174             default:
    175                 break;
    176         }
    177     }
    178     return nullptr;
    179 }
    180