1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2017 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCoreBlitters.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColorData.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkShader.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkUtils.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkXfermodePriv.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBlitMask.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColorData.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkNx.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void D16_S32X_src(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coverage == 0xFF);
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; ++i) {
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst[i] = SkPixel32ToPixel16(src[i]);
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void D16_S32X_src_coverage(uint16_t dst[], const SkPMColor src[], int count,
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                  uint8_t coverage) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (coverage) {
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case 0: break;
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case 0xFF:
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < count; ++i) {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst[i] = SkPixel32ToPixel16(src[i]);
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unsigned scale = coverage + (coverage >> 7);
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < count; ++i) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void D16_S32A_srcover(uint16_t dst[], const SkPMColor src[], int count, uint8_t coverage) {
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(coverage == 0xFF);
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; ++i) {
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        dst[i] = SkSrcOver32To16(src[i], dst[i]);
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void D16_S32A_srcover_coverage(uint16_t dst[], const SkPMColor src[], int count,
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                      uint8_t coverage) {
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    switch (coverage) {
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case 0: break;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case 0xFF:
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < count; ++i) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst[i] = SkSrcOver32To16(src[i], dst[i]);
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        default:
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            unsigned scale = coverage + (coverage >> 7);
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < count; ++i) {
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                dst[i] = SkSrcOver32To16(SkAlphaMulQ(src[i], scale), dst[i]);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkRGB565_Shader_Blitter::Supports(const SkPixmap& device, const SkPaint& paint) {
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (device.colorType() != kRGB_565_SkColorType) {
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (device.colorSpace()) {
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (paint.getBlendMode() != SkBlendMode::kSrcOver &&
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint.getBlendMode() != SkBlendMode::kSrc) {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (paint.isLCDRenderText()) {
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (paint.isDither()) {
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return false;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRGB565_Shader_Blitter::SkRGB565_Shader_Blitter(const SkPixmap& device,
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPaint& paint, SkShaderBase::Context* shaderContext)
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : INHERITED(device, paint, shaderContext)
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(shaderContext);
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(Supports(device, paint));
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor)));
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool isOpaque = SkToBool(shaderContext->getFlags() & SkShaderBase::kOpaqueAlpha_Flag);
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (paint.getBlendMode() == SkBlendMode::kSrc || isOpaque) {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlend = D16_S32X_src;
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlendCoverage = D16_S32X_src_coverage;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {    // srcover
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlend = isOpaque ? D16_S32X_src : D16_S32A_srcover;
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBlendCoverage = isOpaque ? D16_S32X_src_coverage : D16_S32A_srcover_coverage;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() {
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_free(fBuffer);
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRGB565_Shader_Blitter::blitH(int x, int y, int width) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint16_t* device = fDevice.writable_addr16(x, y);
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPMColor*  span = fBuffer;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fShaderContext->shadeSpan(x, y, span, width);
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fBlend(device, span, width, 0xFF);
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkRGB565_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha coverage[],
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                        const int16_t runs[]) {
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPMColor* span = fBuffer;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint16_t*  device = fDevice.writable_addr16(x, y);
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto*      shaderContext = fShaderContext;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (;;) {
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int count = *runs;
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (count <= 0) {
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int aa = *coverage;
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (aa) {
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            shaderContext->shadeSpan(x, y, span, count);
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fBlendCoverage(device, span, count, aa);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        device += count;
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        runs += count;
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        coverage += count;
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        x += count;
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
144