blob: 98e5b7aced899f64758631061c661a62d5d5dda5 [file] [log] [blame]
reedb184f7f2014-07-13 04:32:32 -07001/*
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 "SkBitmap.h"
9#include "SkCanvas.h"
Matt Sarett909d3792016-12-22 10:52:25 -050010#include "SkColorSpaceXform.h"
11#include "SkColorSpaceXformPriv.h"
bsalomon@google.comfb0d7412012-02-22 21:25:34 +000012#include "SkConfig8888.h"
reed@google.com7111d462014-03-25 16:20:24 +000013#include "SkColorPriv.h"
reedb184f7f2014-07-13 04:32:32 -070014#include "SkDither.h"
Matt Sarettcb6266b2017-01-17 10:48:53 -050015#include "SkImageInfoPriv.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000016#include "SkMathPriv.h"
Matt Sarett909d3792016-12-22 10:52:25 -050017#include "SkPM4fPriv.h"
Mike Reed6f0286f2016-11-28 17:26:27 -050018#include "SkRasterPipeline.h"
commit-bot@chromium.org61c49f32013-06-14 13:38:56 +000019#include "SkUnPreMultiply.h"
bsalomon@google.comfb0d7412012-02-22 21:25:34 +000020
Mike Reed6f0286f2016-11-28 17:26:27 -050021// For now disable 565 in the pipeline. Its (higher) quality is so different its too much to
22// rebase (for now)
23//
24//#define PIPELINE_HANDLES_565
25
26static bool is_srgb(const SkImageInfo& info) {
27 return info.colorSpace() && info.colorSpace()->gammaCloseToSRGB();
28}
29
30static bool copy_pipeline_pixels(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
31 const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
32 SkColorTable* ctable) {
33 SkASSERT(srcInfo.width() == dstInfo.width());
34 SkASSERT(srcInfo.height() == dstInfo.height());
35
36 bool src_srgb = is_srgb(srcInfo);
37 const bool dst_srgb = is_srgb(dstInfo);
38 if (!dstInfo.colorSpace()) {
39 src_srgb = false; // untagged dst means ignore tags on src
40 }
41
Mike Reed6f0286f2016-11-28 17:26:27 -050042 SkRasterPipeline pipeline;
43
44 switch (srcInfo.colorType()) {
45 case kRGBA_8888_SkColorType:
46 case kBGRA_8888_SkColorType:
Mike Klein729b5822016-11-28 18:23:23 -050047 pipeline.append(SkRasterPipeline::load_8888, &srcRow);
Mike Reed6f0286f2016-11-28 17:26:27 -050048 if (src_srgb) {
Mike Kleind37d5d92016-12-14 13:38:24 +000049 pipeline.append_from_srgb(srcInfo.alphaType());
Mike Reed6f0286f2016-11-28 17:26:27 -050050 }
Matt Sarett909d3792016-12-22 10:52:25 -050051 if (kBGRA_8888_SkColorType == srcInfo.colorType()) {
Mike Reed6f0286f2016-11-28 17:26:27 -050052 pipeline.append(SkRasterPipeline::swap_rb);
53 }
54 break;
55#ifdef PIPELINE_HANDLES_565
56 case kRGB_565_SkColorType:
Mike Klein729b5822016-11-28 18:23:23 -050057 pipeline.append(SkRasterPipeline::load_565, &srcRow);
Mike Reed6f0286f2016-11-28 17:26:27 -050058 break;
59#endif
60 case kRGBA_F16_SkColorType:
Mike Klein729b5822016-11-28 18:23:23 -050061 pipeline.append(SkRasterPipeline::load_f16, &srcRow);
Mike Reed6f0286f2016-11-28 17:26:27 -050062 break;
63 default:
64 return false; // src colortype unsupported
65 }
66
Matt Sarett909d3792016-12-22 10:52:25 -050067 float matrix[12];
68 if (!append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace())) {
69 return false;
70 }
71
Mike Reed6f0286f2016-11-28 17:26:27 -050072 SkAlphaType sat = srcInfo.alphaType();
73 SkAlphaType dat = dstInfo.alphaType();
74 if (sat == kPremul_SkAlphaType && dat == kUnpremul_SkAlphaType) {
75 pipeline.append(SkRasterPipeline::unpremul);
76 } else if (sat == kUnpremul_SkAlphaType && dat == kPremul_SkAlphaType) {
77 pipeline.append(SkRasterPipeline::premul);
78 }
79
80 switch (dstInfo.colorType()) {
81 case kRGBA_8888_SkColorType:
82 case kBGRA_8888_SkColorType:
Matt Sarett909d3792016-12-22 10:52:25 -050083 if (kBGRA_8888_SkColorType == dstInfo.colorType()) {
84 pipeline.append(SkRasterPipeline::swap_rb);
85 }
Mike Reed6f0286f2016-11-28 17:26:27 -050086 if (dst_srgb) {
87 pipeline.append(SkRasterPipeline::to_srgb);
88 }
89 pipeline.append(SkRasterPipeline::store_8888, &dstRow);
90 break;
91#ifdef PIPELINE_HANDLES_565
92 case kRGB_565_SkColorType:
93 pipeline.append(SkRasterPipeline::store_565, &dstRow);
94 break;
95#endif
96 case kRGBA_F16_SkColorType:
97 pipeline.append(SkRasterPipeline::store_f16, &dstRow);
98 break;
99 default:
100 return false; // dst colortype unsupported
101 }
102
103 auto p = pipeline.compile();
104
105 for (int y = 0; y < srcInfo.height(); ++y) {
106 p(0,0, srcInfo.width());
107 // The pipeline has pointers to srcRow and dstRow, so we just need to update them in the
108 // loop to move between rows of src/dst.
109 srcRow = (const char*)srcRow + srcRB;
110 dstRow = (char*)dstRow + dstRB;
111 }
112 return true;
113}
114
reed@google.com7111d462014-03-25 16:20:24 +0000115enum AlphaVerb {
116 kNothing_AlphaVerb,
117 kPremul_AlphaVerb,
118 kUnpremul_AlphaVerb,
119};
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000120
reed@google.com7111d462014-03-25 16:20:24 +0000121template <bool doSwapRB, AlphaVerb doAlpha> uint32_t convert32(uint32_t c) {
122 if (doSwapRB) {
123 c = SkSwizzle_RB(c);
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000124 }
reed@google.com7111d462014-03-25 16:20:24 +0000125
126 // Lucky for us, in both RGBA and BGRA, the alpha component is always in the same place, so
127 // we can perform premul or unpremul the same way without knowing the swizzles for RGB.
128 switch (doAlpha) {
129 case kNothing_AlphaVerb:
130 // no change
131 break;
132 case kPremul_AlphaVerb:
133 c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c),
134 SkGetPackedG32(c), SkGetPackedB32(c));
135 break;
136 case kUnpremul_AlphaVerb:
137 c = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(c);
138 break;
139 }
140 return c;
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000141}
142
reed@google.com7111d462014-03-25 16:20:24 +0000143template <bool doSwapRB, AlphaVerb doAlpha>
144void convert32_row(uint32_t* dst, const uint32_t* src, int count) {
145 // This has to be correct if src == dst (but not partial overlap)
146 for (int i = 0; i < count; ++i) {
147 dst[i] = convert32<doSwapRB, doAlpha>(src[i]);
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000148 }
149}
150
reed@google.com7111d462014-03-25 16:20:24 +0000151static bool is_32bit_colortype(SkColorType ct) {
152 return kRGBA_8888_SkColorType == ct || kBGRA_8888_SkColorType == ct;
153}
154
155static AlphaVerb compute_AlphaVerb(SkAlphaType src, SkAlphaType dst) {
reed44977482015-02-27 10:23:00 -0800156 SkASSERT(kUnknown_SkAlphaType != src);
157 SkASSERT(kUnknown_SkAlphaType != dst);
reed@google.com7111d462014-03-25 16:20:24 +0000158
159 if (kOpaque_SkAlphaType == src || kOpaque_SkAlphaType == dst || src == dst) {
160 return kNothing_AlphaVerb;
161 }
162 if (kPremul_SkAlphaType == dst) {
163 SkASSERT(kUnpremul_SkAlphaType == src);
164 return kPremul_AlphaVerb;
165 } else {
166 SkASSERT(kPremul_SkAlphaType == src);
167 SkASSERT(kUnpremul_SkAlphaType == dst);
168 return kUnpremul_AlphaVerb;
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000169 }
170}
171
reed@google.com7111d462014-03-25 16:20:24 +0000172static void memcpy32_row(uint32_t* dst, const uint32_t* src, int count) {
173 memcpy(dst, src, count * 4);
174}
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000175
reed@google.com7111d462014-03-25 16:20:24 +0000176bool SkSrcPixelInfo::convertPixelsTo(SkDstPixelInfo* dst, int width, int height) const {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500177 SkASSERT(width > 0 && height > 0);
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000178
reed@google.com7111d462014-03-25 16:20:24 +0000179 if (!is_32bit_colortype(fColorType) || !is_32bit_colortype(dst->fColorType)) {
180 return false;
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000181 }
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000182
reed@google.com7111d462014-03-25 16:20:24 +0000183 void (*proc)(uint32_t* dst, const uint32_t* src, int count);
184 AlphaVerb doAlpha = compute_AlphaVerb(fAlphaType, dst->fAlphaType);
185 bool doSwapRB = fColorType != dst->fColorType;
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000186
reed@google.com7111d462014-03-25 16:20:24 +0000187 switch (doAlpha) {
188 case kNothing_AlphaVerb:
189 if (doSwapRB) {
190 proc = convert32_row<true, kNothing_AlphaVerb>;
191 } else {
192 if (fPixels == dst->fPixels) {
193 return true;
194 }
195 proc = memcpy32_row;
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000196 }
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000197 break;
reed@google.com7111d462014-03-25 16:20:24 +0000198 case kPremul_AlphaVerb:
199 if (doSwapRB) {
200 proc = convert32_row<true, kPremul_AlphaVerb>;
201 } else {
202 proc = convert32_row<false, kPremul_AlphaVerb>;
203 }
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000204 break;
reed@google.com7111d462014-03-25 16:20:24 +0000205 case kUnpremul_AlphaVerb:
206 if (doSwapRB) {
207 proc = convert32_row<true, kUnpremul_AlphaVerb>;
208 } else {
209 proc = convert32_row<false, kUnpremul_AlphaVerb>;
210 }
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000211 break;
212 }
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000213
reed@google.com7111d462014-03-25 16:20:24 +0000214 uint32_t* dstP = static_cast<uint32_t*>(dst->fPixels);
215 const uint32_t* srcP = static_cast<const uint32_t*>(fPixels);
216 size_t srcInc = fRowBytes >> 2;
217 size_t dstInc = dst->fRowBytes >> 2;
218 for (int y = 0; y < height; ++y) {
219 proc(dstP, srcP, width);
220 dstP += dstInc;
221 srcP += srcInc;
commit-bot@chromium.org231f6b82014-03-25 13:38:44 +0000222 }
reed@google.com7111d462014-03-25 16:20:24 +0000223 return true;
bsalomon@google.comfb0d7412012-02-22 21:25:34 +0000224}
reedb184f7f2014-07-13 04:32:32 -0700225
reed0c9b1a82015-03-17 17:44:06 -0700226static void copy_g8_to_32(void* dst, size_t dstRB, const void* src, size_t srcRB, int w, int h) {
227 uint32_t* dst32 = (uint32_t*)dst;
228 const uint8_t* src8 = (const uint8_t*)src;
halcanary9d524f22016-03-29 09:03:52 -0700229
reed0c9b1a82015-03-17 17:44:06 -0700230 for (int y = 0; y < h; ++y) {
231 for (int x = 0; x < w; ++x) {
232 dst32[x] = SkPackARGB32(0xFF, src8[x], src8[x], src8[x]);
233 }
234 dst32 = (uint32_t*)((char*)dst32 + dstRB);
235 src8 += srcRB;
236 }
237}
238
lsalzmana2415ac2016-10-11 14:29:12 -0700239static bool extract_alpha(void* dst, size_t dstRB, const void* src, size_t srcRB,
240 const SkImageInfo& srcInfo, SkColorTable* ctable) {
241 uint8_t* SK_RESTRICT dst8 = (uint8_t*)dst;
242
243 const int w = srcInfo.width();
244 const int h = srcInfo.height();
245 if (srcInfo.isOpaque()) {
246 // src is opaque, so just fill alpha with 0xFF
247 for (int y = 0; y < h; ++y) {
248 memset(dst8, 0xFF, w);
249 dst8 += dstRB;
250 }
251 return true;
252 }
253 switch (srcInfo.colorType()) {
254 case kN32_SkColorType: {
255 const SkPMColor* SK_RESTRICT src32 = (const SkPMColor*)src;
256 for (int y = 0; y < h; ++y) {
257 for (int x = 0; x < w; ++x) {
258 dst8[x] = SkGetPackedA32(src32[x]);
259 }
260 dst8 += dstRB;
261 src32 = (const SkPMColor*)((const char*)src32 + srcRB);
262 }
263 break;
264 }
265 case kARGB_4444_SkColorType: {
266 const SkPMColor16* SK_RESTRICT src16 = (const SkPMColor16*)src;
267 for (int y = 0; y < h; ++y) {
268 for (int x = 0; x < w; ++x) {
269 dst8[x] = SkPacked4444ToA32(src16[x]);
270 }
271 dst8 += dstRB;
272 src16 = (const SkPMColor16*)((const char*)src16 + srcRB);
273 }
274 break;
275 }
276 case kIndex_8_SkColorType: {
277 if (nullptr == ctable) {
278 return false;
279 }
280 const SkPMColor* SK_RESTRICT table = ctable->readColors();
281 const uint8_t* SK_RESTRICT src8 = (const uint8_t*)src;
282 for (int y = 0; y < h; ++y) {
283 for (int x = 0; x < w; ++x) {
284 dst8[x] = SkGetPackedA32(table[src8[x]]);
285 }
286 dst8 += dstRB;
287 src8 += srcRB;
288 }
289 break;
290 }
291 default:
292 return false;
293 }
294 return true;
295}
296
Matt Sarett909d3792016-12-22 10:52:25 -0500297static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
298 if (kUnpremul_SkAlphaType == dstInfo.alphaType() && kPremul_SkAlphaType == srcInfo.alphaType())
299 {
300 return false;
301 }
302
303 switch (dstInfo.colorType()) {
304 case kRGBA_8888_SkColorType:
305 case kBGRA_8888_SkColorType:
306 case kRGBA_F16_SkColorType:
307 break;
308 default:
309 return false;
310 }
311
312 switch (srcInfo.colorType()) {
313 case kRGBA_8888_SkColorType:
314 case kBGRA_8888_SkColorType:
315 break;
316 default:
317 return false;
318 }
319
320 return true;
321}
322
323static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
324 const SkImageInfo& srcInfo, const void* srcPixels,
325 size_t srcRB) {
326 SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
327 SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
328 SkAlphaType xformAlpha;
329 switch (srcInfo.alphaType()) {
330 case kOpaque_SkAlphaType:
331 xformAlpha = kOpaque_SkAlphaType;
332 break;
333 case kPremul_SkAlphaType:
334 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType());
335
336 // This signal means: copy the src alpha to the dst, do not premultiply (in this
337 // case because the pixels are already premultiplied).
338 xformAlpha = kUnpremul_SkAlphaType;
339 break;
340 case kUnpremul_SkAlphaType:
341 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() ||
342 kUnpremul_SkAlphaType == dstInfo.alphaType());
343
344 xformAlpha = dstInfo.alphaType();
345 break;
346 default:
347 SkASSERT(false);
348 xformAlpha = kUnpremul_SkAlphaType;
349 break;
350 }
351
352 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcInfo.colorSpace(),
353 dstInfo.colorSpace());
354 SkASSERT(xform);
355
356 for (int y = 0; y < dstInfo.height(); y++) {
357 SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(),
358 xformAlpha));
359 dstPixels = SkTAddOffset<void>(dstPixels, dstRB);
360 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB);
361 }
362}
363
reedb184f7f2014-07-13 04:32:32 -0700364bool SkPixelInfo::CopyPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
365 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
366 SkColorTable* ctable) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500367 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
368 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
Matt Sarett909d3792016-12-22 10:52:25 -0500369
reedb184f7f2014-07-13 04:32:32 -0700370 const int width = srcInfo.width();
371 const int height = srcInfo.height();
halcanary9d524f22016-03-29 09:03:52 -0700372
reedd96e7e52016-02-17 07:15:29 -0800373 // Do the easiest one first : both configs are equal
Matt Sarettcb6266b2017-01-17 10:48:53 -0500374 if (srcInfo == dstInfo && kIndex_8_SkColorType != srcInfo.colorType()) {
reedd96e7e52016-02-17 07:15:29 -0800375 size_t bytes = width * srcInfo.bytesPerPixel();
376 for (int y = 0; y < height; ++y) {
377 memcpy(dstPixels, srcPixels, bytes);
378 srcPixels = (const char*)srcPixels + srcRB;
379 dstPixels = (char*)dstPixels + dstRB;
380 }
381 return true;
382 }
reedb184f7f2014-07-13 04:32:32 -0700383
Matt Sarett909d3792016-12-22 10:52:25 -0500384 const bool isColorAware = srcInfo.colorSpace() && dstInfo.colorSpace();
385
reedb184f7f2014-07-13 04:32:32 -0700386 // Handle fancy alpha swizzling if both are ARGB32
Matt Sarett909d3792016-12-22 10:52:25 -0500387 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) {
reedb184f7f2014-07-13 04:32:32 -0700388 SkDstPixelInfo dstPI;
389 dstPI.fColorType = dstInfo.colorType();
390 dstPI.fAlphaType = dstInfo.alphaType();
391 dstPI.fPixels = dstPixels;
392 dstPI.fRowBytes = dstRB;
mtklein775b8192014-12-02 09:11:25 -0800393
reedb184f7f2014-07-13 04:32:32 -0700394 SkSrcPixelInfo srcPI;
395 srcPI.fColorType = srcInfo.colorType();
396 srcPI.fAlphaType = srcInfo.alphaType();
397 srcPI.fPixels = srcPixels;
398 srcPI.fRowBytes = srcRB;
mtklein775b8192014-12-02 09:11:25 -0800399
reedb184f7f2014-07-13 04:32:32 -0700400 return srcPI.convertPixelsTo(&dstPI, width, height);
401 }
402
Matt Sarett909d3792016-12-22 10:52:25 -0500403 if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) {
404 apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
405 return true;
406 }
407
reedb184f7f2014-07-13 04:32:32 -0700408 // If they agree on colorType and the alphaTypes are compatible, then we just memcpy.
409 // Note: we've already taken care of 32bit colortypes above.
410 if (srcInfo.colorType() == dstInfo.colorType()) {
411 switch (srcInfo.colorType()) {
Matt Sarett909d3792016-12-22 10:52:25 -0500412 case kRGBA_F16_SkColorType:
413 if (!SkColorSpace::Equals(srcInfo.colorSpace(), dstInfo.colorSpace())) {
414 break;
415 }
reedb184f7f2014-07-13 04:32:32 -0700416 case kIndex_8_SkColorType:
417 case kARGB_4444_SkColorType:
418 if (srcInfo.alphaType() != dstInfo.alphaType()) {
Mike Reed343b6772016-11-28 11:57:48 -0500419 break;
reedb184f7f2014-07-13 04:32:32 -0700420 }
Mike Reed343b6772016-11-28 11:57:48 -0500421 case kRGB_565_SkColorType:
422 case kAlpha_8_SkColorType:
423 case kGray_8_SkColorType:
424 SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB,
425 width * srcInfo.bytesPerPixel(), height);
426 return true;
reedb184f7f2014-07-13 04:32:32 -0700427 default:
Mike Reed343b6772016-11-28 11:57:48 -0500428 break;
reedb184f7f2014-07-13 04:32:32 -0700429 }
reedb184f7f2014-07-13 04:32:32 -0700430 }
431
432 /*
433 * Begin section where we try to change colorTypes along the way. Not all combinations
434 * are supported.
435 */
436
reed0c9b1a82015-03-17 17:44:06 -0700437 if (kGray_8_SkColorType == srcInfo.colorType() && 4 == dstInfo.bytesPerPixel()) {
438 copy_g8_to_32(dstPixels, dstRB, srcPixels, srcRB, width, height);
439 return true;
440 }
reed0c9b1a82015-03-17 17:44:06 -0700441
lsalzmana2415ac2016-10-11 14:29:12 -0700442 if (kAlpha_8_SkColorType == dstInfo.colorType() &&
443 extract_alpha(dstPixels, dstRB, srcPixels, srcRB, srcInfo, ctable)) {
444 return true;
445 }
446
Mike Reed6f0286f2016-11-28 17:26:27 -0500447 // Try the pipeline
448 //
449 if (copy_pipeline_pixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable)) {
450 return true;
451 }
452
reedb184f7f2014-07-13 04:32:32 -0700453 // Can no longer draw directly into 4444, but we can manually whack it for a few combinations
454 if (kARGB_4444_SkColorType == dstInfo.colorType() &&
455 (kN32_SkColorType == srcInfo.colorType() || kIndex_8_SkColorType == srcInfo.colorType())) {
456 if (srcInfo.alphaType() == kUnpremul_SkAlphaType) {
457 // Our method for converting to 4444 assumes premultiplied.
458 return false;
459 }
mtklein775b8192014-12-02 09:11:25 -0800460
halcanary96fcdcc2015-08-27 07:41:13 -0700461 const SkPMColor* table = nullptr;
reedb184f7f2014-07-13 04:32:32 -0700462 if (kIndex_8_SkColorType == srcInfo.colorType()) {
Matt Sarettcb6266b2017-01-17 10:48:53 -0500463 SkASSERT(ctable);
mtklein775b8192014-12-02 09:11:25 -0800464 table = ctable->readColors();
reedb184f7f2014-07-13 04:32:32 -0700465 }
466
467 for (int y = 0; y < height; ++y) {
468 DITHER_4444_SCAN(y);
469 SkPMColor16* SK_RESTRICT dstRow = (SkPMColor16*)dstPixels;
470 if (table) {
471 const uint8_t* SK_RESTRICT srcRow = (const uint8_t*)srcPixels;
472 for (int x = 0; x < width; ++x) {
473 dstRow[x] = SkDitherARGB32To4444(table[srcRow[x]], DITHER_VALUE(x));
474 }
475 } else {
476 const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)srcPixels;
477 for (int x = 0; x < width; ++x) {
478 dstRow[x] = SkDitherARGB32To4444(srcRow[x], DITHER_VALUE(x));
479 }
480 }
481 dstPixels = (char*)dstPixels + dstRB;
482 srcPixels = (const char*)srcPixels + srcRB;
483 }
reedb184f7f2014-07-13 04:32:32 -0700484 return true;
485 }
486
487 if (dstInfo.alphaType() == kUnpremul_SkAlphaType) {
488 // We do not support drawing to unpremultiplied bitmaps.
489 return false;
490 }
491
492 // Final fall-back, draw with a canvas
493 //
494 // Always clear the dest in case one of the blitters accesses it
495 // TODO: switch the allocation of tmpDst to call sk_calloc_throw
496 {
497 SkBitmap bm;
halcanary96fcdcc2015-08-27 07:41:13 -0700498 if (!bm.installPixels(srcInfo, const_cast<void*>(srcPixels), srcRB, ctable, nullptr, nullptr)) {
reedb184f7f2014-07-13 04:32:32 -0700499 return false;
500 }
Mike Reed5df49342016-11-12 08:06:55 -0600501 std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(dstInfo, dstPixels, dstRB);
502 if (!canvas) {
reedb184f7f2014-07-13 04:32:32 -0700503 return false;
504 }
505
506 SkPaint paint;
507 paint.setDither(true);
508
509 canvas->clear(0);
510 canvas->drawBitmap(bm, 0, 0, &paint);
511 return true;
512 }
513}