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