Line data Source code
1 : /*
2 : * Copyright 2014 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 "SkBlitMask.h"
9 : #include "SkColor.h"
10 : #include "SkColorPriv.h"
11 : #include "SkOpts.h"
12 :
13 419 : SkBlitMask::BlitLCD16RowProc SkBlitMask::BlitLCD16RowFactory(bool isOpaque) {
14 419 : BlitLCD16RowProc proc = PlatformBlitRowProcs16(isOpaque);
15 419 : if (proc) {
16 419 : return proc;
17 : }
18 :
19 0 : if (isOpaque) {
20 0 : return SkBlitLCD16OpaqueRow;
21 : } else {
22 0 : return SkBlitLCD16Row;
23 : }
24 : }
25 :
26 419 : static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB,
27 : const void* SK_RESTRICT mask, size_t maskRB,
28 : SkColor color, int width, int height) {
29 :
30 419 : SkPMColor* dstRow = (SkPMColor*)dst;
31 419 : const uint16_t* srcRow = (const uint16_t*)mask;
32 : SkPMColor opaqueDst;
33 :
34 419 : SkBlitMask::BlitLCD16RowProc proc = nullptr;
35 419 : bool isOpaque = (0xFF == SkColorGetA(color));
36 419 : proc = SkBlitMask::BlitLCD16RowFactory(isOpaque);
37 419 : SkASSERT(proc != nullptr);
38 :
39 419 : if (isOpaque) {
40 315 : opaqueDst = SkPreMultiplyColor(color);
41 : } else {
42 104 : opaqueDst = 0; // ignored
43 : }
44 :
45 5533 : do {
46 5533 : proc(dstRow, srcRow, color, width, opaqueDst);
47 5533 : dstRow = (SkPMColor*)((char*)dstRow + dstRB);
48 5533 : srcRow = (const uint16_t*)((const char*)srcRow + maskRB);
49 : } while (--height != 0);
50 419 : }
51 :
52 : ///////////////////////////////////////////////////////////////////////////////
53 :
54 453 : bool SkBlitMask::BlitColor(const SkPixmap& device, const SkMask& mask,
55 : const SkIRect& clip, SkColor color) {
56 453 : int x = clip.fLeft, y = clip.fTop;
57 :
58 453 : if (device.colorType() == kN32_SkColorType && mask.fFormat == SkMask::kA8_Format) {
59 102 : SkOpts::blit_mask_d32_a8(device.writable_addr32(x,y), device.rowBytes(),
60 68 : (const SkAlpha*)mask.getAddr(x,y), mask.fRowBytes,
61 68 : color, clip.width(), clip.height());
62 34 : return true;
63 : }
64 :
65 419 : if (device.colorType() == kN32_SkColorType && mask.fFormat == SkMask::kLCD16_Format) {
66 : // TODO: Is this reachable code? Seems like no.
67 1257 : D32_LCD16_Proc(device.writable_addr32(x,y), device.rowBytes(),
68 838 : mask.getAddr(x,y), mask.fRowBytes,
69 419 : color, clip.width(), clip.height());
70 419 : return true;
71 : }
72 :
73 0 : return false;
74 : }
75 :
76 : ///////////////////////////////////////////////////////////////////////////////
77 : ///////////////////////////////////////////////////////////////////////////////
78 :
79 0 : static void BW_RowProc_Blend(
80 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
81 0 : const uint8_t* SK_RESTRICT mask = static_cast<const uint8_t*>(maskIn);
82 0 : int i, octuple = (count + 7) >> 3;
83 0 : for (i = 0; i < octuple; ++i) {
84 0 : int m = *mask++;
85 0 : if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
86 0 : if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); }
87 0 : if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); }
88 0 : if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); }
89 0 : if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); }
90 0 : if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); }
91 0 : if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); }
92 0 : if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); }
93 0 : src += 8;
94 0 : dst += 8;
95 : }
96 0 : count &= 7;
97 0 : if (count > 0) {
98 0 : int m = *mask;
99 0 : do {
100 0 : if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
101 0 : m <<= 1;
102 0 : src += 1;
103 0 : dst += 1;
104 : } while (--count > 0);
105 : }
106 0 : }
107 :
108 0 : static void BW_RowProc_Opaque(
109 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
110 0 : const uint8_t* SK_RESTRICT mask = static_cast<const uint8_t*>(maskIn);
111 0 : int i, octuple = (count + 7) >> 3;
112 0 : for (i = 0; i < octuple; ++i) {
113 0 : int m = *mask++;
114 0 : if (m & 0x80) { dst[0] = src[0]; }
115 0 : if (m & 0x40) { dst[1] = src[1]; }
116 0 : if (m & 0x20) { dst[2] = src[2]; }
117 0 : if (m & 0x10) { dst[3] = src[3]; }
118 0 : if (m & 0x08) { dst[4] = src[4]; }
119 0 : if (m & 0x04) { dst[5] = src[5]; }
120 0 : if (m & 0x02) { dst[6] = src[6]; }
121 0 : if (m & 0x01) { dst[7] = src[7]; }
122 0 : src += 8;
123 0 : dst += 8;
124 : }
125 0 : count &= 7;
126 0 : if (count > 0) {
127 0 : int m = *mask;
128 0 : do {
129 0 : if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); }
130 0 : m <<= 1;
131 0 : src += 1;
132 0 : dst += 1;
133 : } while (--count > 0);
134 : }
135 0 : }
136 :
137 0 : static void A8_RowProc_Blend(
138 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
139 0 : const uint8_t* SK_RESTRICT mask = static_cast<const uint8_t*>(maskIn);
140 0 : for (int i = 0; i < count; ++i) {
141 0 : if (mask[i]) {
142 0 : dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]);
143 : }
144 : }
145 0 : }
146 :
147 90 : static void A8_RowProc_Opaque(
148 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
149 90 : const uint8_t* SK_RESTRICT mask = static_cast<const uint8_t*>(maskIn);
150 23190 : for (int i = 0; i < count; ++i) {
151 23100 : int m = mask[i];
152 23100 : if (m) {
153 22330 : m += (m >> 7);
154 22330 : dst[i] = SkPMLerp(src[i], dst[i], m);
155 : }
156 : }
157 90 : }
158 :
159 0 : static int upscale31To255(int value) {
160 0 : value = (value << 3) | (value >> 2);
161 0 : return value;
162 : }
163 :
164 0 : static int src_alpha_blend(int src, int dst, int srcA, int mask) {
165 :
166 0 : return dst + SkAlphaMul(src - SkAlphaMul(srcA, dst), mask);
167 : }
168 :
169 0 : static void LCD16_RowProc_Blend(
170 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
171 0 : const uint16_t* SK_RESTRICT mask = static_cast<const uint16_t*>(maskIn);
172 0 : for (int i = 0; i < count; ++i) {
173 0 : uint16_t m = mask[i];
174 0 : if (0 == m) {
175 0 : continue;
176 : }
177 :
178 0 : SkPMColor s = src[i];
179 0 : SkPMColor d = dst[i];
180 :
181 0 : int srcA = SkGetPackedA32(s);
182 0 : int srcR = SkGetPackedR32(s);
183 0 : int srcG = SkGetPackedG32(s);
184 0 : int srcB = SkGetPackedB32(s);
185 :
186 0 : srcA += srcA >> 7;
187 :
188 : /* We want all of these in 5bits, hence the shifts in case one of them
189 : * (green) is 6bits.
190 : */
191 0 : int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
192 0 : int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
193 0 : int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
194 :
195 0 : maskR = upscale31To255(maskR);
196 0 : maskG = upscale31To255(maskG);
197 0 : maskB = upscale31To255(maskB);
198 :
199 0 : int dstR = SkGetPackedR32(d);
200 0 : int dstG = SkGetPackedG32(d);
201 0 : int dstB = SkGetPackedB32(d);
202 :
203 : // LCD blitting is only supported if the dst is known/required
204 : // to be opaque
205 0 : dst[i] = SkPackARGB32(0xFF,
206 0 : src_alpha_blend(srcR, dstR, srcA, maskR),
207 0 : src_alpha_blend(srcG, dstG, srcA, maskG),
208 0 : src_alpha_blend(srcB, dstB, srcA, maskB));
209 : }
210 0 : }
211 :
212 0 : static void LCD16_RowProc_Opaque(
213 : SkPMColor* SK_RESTRICT dst, const void* maskIn, const SkPMColor* SK_RESTRICT src, int count) {
214 0 : const uint16_t* SK_RESTRICT mask = static_cast<const uint16_t*>(maskIn);
215 0 : for (int i = 0; i < count; ++i) {
216 0 : uint16_t m = mask[i];
217 0 : if (0 == m) {
218 0 : continue;
219 : }
220 :
221 0 : SkPMColor s = src[i];
222 0 : SkPMColor d = dst[i];
223 :
224 0 : int srcR = SkGetPackedR32(s);
225 0 : int srcG = SkGetPackedG32(s);
226 0 : int srcB = SkGetPackedB32(s);
227 :
228 : /* We want all of these in 5bits, hence the shifts in case one of them
229 : * (green) is 6bits.
230 : */
231 0 : int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5);
232 0 : int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5);
233 0 : int maskB = SkGetPackedB16(m) >> (SK_B16_BITS - 5);
234 :
235 : // Now upscale them to 0..32, so we can use blend32
236 0 : maskR = SkUpscale31To32(maskR);
237 0 : maskG = SkUpscale31To32(maskG);
238 0 : maskB = SkUpscale31To32(maskB);
239 :
240 0 : int dstR = SkGetPackedR32(d);
241 0 : int dstG = SkGetPackedG32(d);
242 0 : int dstB = SkGetPackedB32(d);
243 :
244 : // LCD blitting is only supported if the dst is known/required
245 : // to be opaque
246 0 : dst[i] = SkPackARGB32(0xFF,
247 0 : SkBlend32(srcR, dstR, maskR),
248 0 : SkBlend32(srcG, dstG, maskG),
249 0 : SkBlend32(srcB, dstB, maskB));
250 : }
251 0 : }
252 :
253 61 : SkBlitMask::RowProc SkBlitMask::RowFactory(SkColorType ct,
254 : SkMask::Format format,
255 : RowFlags flags) {
256 : // make this opt-in until chrome can rebaseline
257 61 : RowProc proc = PlatformRowProcs(ct, format, flags);
258 61 : if (proc) {
259 0 : return proc;
260 : }
261 :
262 : static const RowProc gProcs[] = {
263 : // need X coordinate to handle BW
264 : false ? (RowProc)BW_RowProc_Blend : nullptr, // suppress unused warning
265 : false ? (RowProc)BW_RowProc_Opaque : nullptr, // suppress unused warning
266 : (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque,
267 : (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque,
268 : };
269 :
270 : int index;
271 61 : switch (ct) {
272 : case kN32_SkColorType:
273 61 : switch (format) {
274 0 : case SkMask::kBW_Format: index = 0; break;
275 61 : case SkMask::kA8_Format: index = 2; break;
276 0 : case SkMask::kLCD16_Format: index = 4; break;
277 : default:
278 0 : return nullptr;
279 : }
280 61 : if (flags & kSrcIsOpaque_RowFlag) {
281 61 : index |= 1;
282 : }
283 61 : SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs));
284 61 : return gProcs[index];
285 : default:
286 0 : break;
287 : }
288 0 : return nullptr;
289 : }
|