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 | |
16 | static 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 | |
23 | static 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 | |
41 | static 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 | |
48 | static 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 | |
66 | bool 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 | |
83 | SkRGB565_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 | |
103 | SkRGB565_Shader_Blitter::~SkRGB565_Shader_Blitter() { |
104 | sk_free(fBuffer); |
105 | } |
106 | |
107 | void 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 | |
117 | void 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 | |