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