blob: 9682d5572a97c3c245c7d381d6a535a6eb97a8d8 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkBlitter.h"
11#include "SkAntiRun.h"
12#include "SkColor.h"
13#include "SkColorFilter.h"
reed@google.com02f65f22012-08-06 21:20:05 +000014#include "SkFilterShader.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000015#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkMask.h"
17#include "SkMaskFilter.h"
18#include "SkTemplatesPriv.h"
reed@google.com45884902012-05-11 14:38:51 +000019#include "SkTLazy.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include "SkUtils.h"
21#include "SkXfermode.h"
robertphillips@google.com76f9e932013-01-15 20:17:47 +000022#include "SkString.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
reed@android.com845fdac2009-06-23 03:01:32 +000024SkBlitter::~SkBlitter() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000025
reed@google.comea033602012-12-14 13:13:55 +000026bool SkBlitter::isNullBlitter() const { return false; }
27
reed@google.com82065d62011-02-07 15:30:46 +000028const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029 return NULL;
30}
31
reed@google.com82065d62011-02-07 15:30:46 +000032void SkBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000033 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000034}
35
reed@google.com82065d62011-02-07 15:30:46 +000036void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
37 const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000038 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000039}
40
reed@google.com82065d62011-02-07 15:30:46 +000041void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
42 if (alpha == 255) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000043 this->blitRect(x, y, 1, height);
reed@google.com82065d62011-02-07 15:30:46 +000044 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 int16_t runs[2];
46 runs[0] = 1;
47 runs[1] = 0;
48
reed@google.com82065d62011-02-07 15:30:46 +000049 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000050 this->blitAntiH(x, y++, &alpha, runs);
reed@google.com82065d62011-02-07 15:30:46 +000051 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 }
53}
54
reed@google.com82065d62011-02-07 15:30:46 +000055void SkBlitter::blitRect(int x, int y, int width, int height) {
tomhudson@google.coma31ac732011-12-29 16:09:31 +000056 SkASSERT(width > 0);
reed@google.com82065d62011-02-07 15:30:46 +000057 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 this->blitH(x, y++, width);
reed@google.com82065d62011-02-07 15:30:46 +000059 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000060}
61
tomhudson@google.com49eac192011-12-27 13:59:20 +000062/// Default implementation doesn't check for any easy optimizations
63/// such as alpha == 0 or 255; also uses blitV(), which some subclasses
64/// may not support.
65void SkBlitter::blitAntiRect(int x, int y, int width, int height,
66 SkAlpha leftAlpha, SkAlpha rightAlpha) {
tomhudson@google.com47143592011-12-28 17:58:07 +000067 this->blitV(x++, y, height, leftAlpha);
tomhudson@google.coma31ac732011-12-29 16:09:31 +000068 if (width > 0) {
tomhudson@google.com47143592011-12-28 17:58:07 +000069 this->blitRect(x, y, width, height);
70 x += width;
71 }
72 this->blitV(x, y, height, rightAlpha);
tomhudson@google.com49eac192011-12-27 13:59:20 +000073}
74
reed@android.com8a1c16f2008-12-17 15:59:43 +000075//////////////////////////////////////////////////////////////////////////////
76
reed@google.com82065d62011-02-07 15:30:46 +000077static inline void bits_to_runs(SkBlitter* blitter, int x, int y,
78 const uint8_t bits[],
79 U8CPU left_mask, int rowBytes,
80 U8CPU right_mask) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 int inFill = 0;
82 int pos = 0;
83
reed@google.com82065d62011-02-07 15:30:46 +000084 while (--rowBytes >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 unsigned b = *bits++ & left_mask;
reed@google.com82065d62011-02-07 15:30:46 +000086 if (rowBytes == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 b &= right_mask;
reed@google.com82065d62011-02-07 15:30:46 +000088 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000089
reed@google.com82065d62011-02-07 15:30:46 +000090 for (unsigned test = 0x80; test != 0; test >>= 1) {
91 if (b & test) {
92 if (!inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 pos = x;
94 inFill = true;
95 }
reed@google.com82065d62011-02-07 15:30:46 +000096 } else {
97 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 blitter->blitH(pos, y, x - pos);
99 inFill = false;
100 }
101 }
102 x += 1;
103 }
104 left_mask = 0xFF;
105 }
106
107 // final cleanup
reed@google.com82065d62011-02-07 15:30:46 +0000108 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 blitter->blitH(pos, y, x - pos);
reed@google.com82065d62011-02-07 15:30:46 +0000110 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111}
112
reed@google.com82065d62011-02-07 15:30:46 +0000113void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114 SkASSERT(mask.fBounds.contains(clip));
115
reed@google.com82065d62011-02-07 15:30:46 +0000116 if (mask.fFormat == SkMask::kBW_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 int cx = clip.fLeft;
118 int cy = clip.fTop;
119 int maskLeft = mask.fBounds.fLeft;
120 int mask_rowBytes = mask.fRowBytes;
121 int height = clip.height();
122
123 const uint8_t* bits = mask.getAddr1(cx, cy);
124
reed@google.com82065d62011-02-07 15:30:46 +0000125 if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) {
126 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 bits_to_runs(this, cx, cy, bits, 0xFF, mask_rowBytes, 0xFF);
128 bits += mask_rowBytes;
129 cy += 1;
130 }
reed@google.com82065d62011-02-07 15:30:46 +0000131 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 int left_edge = cx - maskLeft;
133 SkASSERT(left_edge >= 0);
134 int rite_edge = clip.fRight - maskLeft;
135 SkASSERT(rite_edge > left_edge);
136
137 int left_mask = 0xFF >> (left_edge & 7);
138 int rite_mask = 0xFF << (8 - (rite_edge & 7));
139 int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
140
reed@google.coma89c77b2011-12-01 21:47:26 +0000141 // check for empty right mask, so we don't read off the end (or go slower than we need to)
reed@google.com82065d62011-02-07 15:30:46 +0000142 if (rite_mask == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 SkASSERT(full_runs >= 0);
144 full_runs -= 1;
145 rite_mask = 0xFF;
146 }
reed@google.com82065d62011-02-07 15:30:46 +0000147 if (left_mask == 0xFF) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 full_runs -= 1;
reed@google.com82065d62011-02-07 15:30:46 +0000149 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150
reed@google.coma89c77b2011-12-01 21:47:26 +0000151 // back up manually so we can keep in sync with our byte-aligned src
152 // have cx reflect our actual starting x-coord
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 cx -= left_edge & 7;
154
reed@google.com82065d62011-02-07 15:30:46 +0000155 if (full_runs < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 SkASSERT((left_mask & rite_mask) != 0);
reed@google.com82065d62011-02-07 15:30:46 +0000157 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 bits_to_runs(this, cx, cy, bits, left_mask, 1, rite_mask);
159 bits += mask_rowBytes;
160 cy += 1;
161 }
reed@google.com82065d62011-02-07 15:30:46 +0000162 } else {
163 while (--height >= 0) {
reed@google.coma89c77b2011-12-01 21:47:26 +0000164 bits_to_runs(this, cx, cy, bits, left_mask, full_runs + 2, rite_mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 bits += mask_rowBytes;
166 cy += 1;
167 }
168 }
169 }
reed@google.com82065d62011-02-07 15:30:46 +0000170 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 int width = clip.width();
172 SkAutoSTMalloc<64, int16_t> runStorage(width + 1);
173 int16_t* runs = runStorage.get();
reed@google.com79891862011-10-18 15:44:57 +0000174 const uint8_t* aa = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175
176 sk_memset16((uint16_t*)runs, 1, width);
177 runs[width] = 0;
178
179 int height = clip.height();
180 int y = clip.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000181 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 this->blitAntiH(clip.fLeft, y, aa, runs);
183 aa += mask.fRowBytes;
184 y += 1;
185 }
186 }
187}
188
189/////////////////////// these guys are not virtual, just a helpers
190
191void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
192 if (clip.quickReject(mask.fBounds)) {
193 return;
194 }
reed@google.com82065d62011-02-07 15:30:46 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 SkRegion::Cliperator clipper(clip, mask.fBounds);
reed@google.com82065d62011-02-07 15:30:46 +0000197
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 while (!clipper.done()) {
199 const SkIRect& cr = clipper.rect();
200 this->blitMask(mask, cr);
201 clipper.next();
202 }
203}
204
205void SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) {
206 SkRegion::Cliperator clipper(clip, rect);
reed@google.com82065d62011-02-07 15:30:46 +0000207
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 while (!clipper.done()) {
209 const SkIRect& cr = clipper.rect();
210 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
211 clipper.next();
212 }
213}
214
215void SkBlitter::blitRegion(const SkRegion& clip) {
216 SkRegion::Iterator iter(clip);
reed@google.com82065d62011-02-07 15:30:46 +0000217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 while (!iter.done()) {
219 const SkIRect& cr = iter.rect();
220 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
221 iter.next();
222 }
223}
224
reed@google.com82065d62011-02-07 15:30:46 +0000225///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226
reed@google.com82065d62011-02-07 15:30:46 +0000227void SkNullBlitter::blitH(int x, int y, int width) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
reed@google.com82065d62011-02-07 15:30:46 +0000229void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
230 const int16_t runs[]) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
reed@google.com82065d62011-02-07 15:30:46 +0000232void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233
reed@google.com82065d62011-02-07 15:30:46 +0000234void SkNullBlitter::blitRect(int x, int y, int width, int height) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
reed@google.com82065d62011-02-07 15:30:46 +0000236void SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
reed@google.com82065d62011-02-07 15:30:46 +0000238const SkBitmap* SkNullBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 return NULL;
240}
241
reed@google.comea033602012-12-14 13:13:55 +0000242bool SkNullBlitter::isNullBlitter() const { return true; }
243
reed@google.com82065d62011-02-07 15:30:46 +0000244///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245
reed@google.com82065d62011-02-07 15:30:46 +0000246static int compute_anti_width(const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 int width = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000248
249 for (;;) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 int count = runs[0];
reed@google.com82065d62011-02-07 15:30:46 +0000251
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 SkASSERT(count >= 0);
reed@google.com82065d62011-02-07 15:30:46 +0000253 if (count == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 break;
reed@google.com82065d62011-02-07 15:30:46 +0000255 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 width += count;
257 runs += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 }
259 return width;
260}
261
reed@google.com82065d62011-02-07 15:30:46 +0000262static inline bool y_in_rect(int y, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
264}
265
reed@google.com82065d62011-02-07 15:30:46 +0000266static inline bool x_in_rect(int x, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
268}
269
reed@google.com82065d62011-02-07 15:30:46 +0000270void SkRectClipBlitter::blitH(int left, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 SkASSERT(width > 0);
272
reed@google.com82065d62011-02-07 15:30:46 +0000273 if (!y_in_rect(y, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 return;
reed@google.com82065d62011-02-07 15:30:46 +0000275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276
277 int right = left + width;
278
reed@google.com82065d62011-02-07 15:30:46 +0000279 if (left < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000280 left = fClipRect.fLeft;
reed@google.com82065d62011-02-07 15:30:46 +0000281 }
282 if (right > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 right = fClipRect.fRight;
reed@google.com82065d62011-02-07 15:30:46 +0000284 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285
286 width = right - left;
reed@google.com82065d62011-02-07 15:30:46 +0000287 if (width > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 fBlitter->blitH(left, y, width);
reed@google.com82065d62011-02-07 15:30:46 +0000289 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290}
291
reed@google.com82065d62011-02-07 15:30:46 +0000292void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[],
293 const int16_t runs[]) {
294 if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 return;
reed@google.com82065d62011-02-07 15:30:46 +0000296 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000297
298 int x0 = left;
299 int x1 = left + compute_anti_width(runs);
300
reed@google.com82065d62011-02-07 15:30:46 +0000301 if (x1 <= fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 return;
reed@google.com82065d62011-02-07 15:30:46 +0000303 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304
305 SkASSERT(x0 < x1);
reed@google.com82065d62011-02-07 15:30:46 +0000306 if (x0 < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000307 int dx = fClipRect.fLeft - x0;
308 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx);
309 runs += dx;
310 aa += dx;
311 x0 = fClipRect.fLeft;
312 }
313
314 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
reed@google.com82065d62011-02-07 15:30:46 +0000315 if (x1 > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000316 x1 = fClipRect.fRight;
317 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0);
318 ((int16_t*)runs)[x1 - x0] = 0;
319 }
320
321 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
322 SkASSERT(compute_anti_width(runs) == x1 - x0);
323
324 fBlitter->blitAntiH(x0, y, aa, runs);
325}
326
reed@google.com82065d62011-02-07 15:30:46 +0000327void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328 SkASSERT(height > 0);
329
reed@google.com82065d62011-02-07 15:30:46 +0000330 if (!x_in_rect(x, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 return;
reed@google.com82065d62011-02-07 15:30:46 +0000332 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333
334 int y0 = y;
335 int y1 = y + height;
336
reed@google.com82065d62011-02-07 15:30:46 +0000337 if (y0 < fClipRect.fTop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000338 y0 = fClipRect.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000339 }
340 if (y1 > fClipRect.fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 y1 = fClipRect.fBottom;
reed@google.com82065d62011-02-07 15:30:46 +0000342 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343
reed@google.com82065d62011-02-07 15:30:46 +0000344 if (y0 < y1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 fBlitter->blitV(x, y0, y1 - y0, alpha);
reed@google.com82065d62011-02-07 15:30:46 +0000346 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347}
348
reed@google.com82065d62011-02-07 15:30:46 +0000349void SkRectClipBlitter::blitRect(int left, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 SkIRect r;
351
352 r.set(left, y, left + width, y + height);
reed@google.com82065d62011-02-07 15:30:46 +0000353 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
reed@google.com82065d62011-02-07 15:30:46 +0000355 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356}
357
tomhudson@google.com49eac192011-12-27 13:59:20 +0000358void SkRectClipBlitter::blitAntiRect(int left, int y, int width, int height,
359 SkAlpha leftAlpha, SkAlpha rightAlpha) {
360 SkIRect r;
361
362 // The *true* width of the rectangle blitted is width+2:
363 r.set(left, y, left + width + 2, y + height);
364 if (r.intersect(fClipRect)) {
365 if (r.fLeft != left) {
366 SkASSERT(r.fLeft > left);
367 leftAlpha = 255;
368 }
369 if (r.fRight != left + width + 2) {
370 SkASSERT(r.fRight < left + width + 2);
371 rightAlpha = 255;
372 }
373 if (255 == leftAlpha && 255 == rightAlpha) {
374 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
375 } else if (1 == r.width()) {
376 if (r.fLeft == left) {
377 fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
378 } else {
379 SkASSERT(r.fLeft == left + width + 1);
380 fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
381 }
382 } else {
383 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
384 leftAlpha, rightAlpha);
385 }
386 }
387}
388
reed@google.com82065d62011-02-07 15:30:46 +0000389void SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390 SkASSERT(mask.fBounds.contains(clip));
391
392 SkIRect r = clip;
393
reed@google.com82065d62011-02-07 15:30:46 +0000394 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395 fBlitter->blitMask(mask, r);
reed@google.com82065d62011-02-07 15:30:46 +0000396 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397}
398
reed@google.com82065d62011-02-07 15:30:46 +0000399const SkBitmap* SkRectClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 return fBlitter->justAnOpaqueColor(value);
401}
402
reed@google.com82065d62011-02-07 15:30:46 +0000403///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404
reed@google.com82065d62011-02-07 15:30:46 +0000405void SkRgnClipBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 SkRegion::Spanerator span(*fRgn, y, x, x + width);
407 int left, right;
408
reed@google.com82065d62011-02-07 15:30:46 +0000409 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410 SkASSERT(left < right);
411 fBlitter->blitH(left, y, right - left);
412 }
413}
414
reed@google.com82065d62011-02-07 15:30:46 +0000415void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
416 const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000417 int width = compute_anti_width(runs);
418 SkRegion::Spanerator span(*fRgn, y, x, x + width);
419 int left, right;
420 SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
reed@google.com82065d62011-02-07 15:30:46 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 int prevRite = x;
reed@google.com82065d62011-02-07 15:30:46 +0000423 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000424 SkASSERT(x <= left);
425 SkASSERT(left < right);
426 SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
reed@google.com82065d62011-02-07 15:30:46 +0000427
reed@android.com8a1c16f2008-12-17 15:59:43 +0000428 SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
429
430 // now zero before left
reed@google.com82065d62011-02-07 15:30:46 +0000431 if (left > prevRite) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000432 int index = prevRite - x;
433 ((uint8_t*)aa)[index] = 0; // skip runs after right
434 ((int16_t*)runs)[index] = SkToS16(left - prevRite);
435 }
reed@google.com82065d62011-02-07 15:30:46 +0000436
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 prevRite = right;
438 }
reed@google.com82065d62011-02-07 15:30:46 +0000439
440 if (prevRite > x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 ((int16_t*)runs)[prevRite - x] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000442
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443 if (x < 0) {
444 int skip = runs[0];
445 SkASSERT(skip >= -x);
446 aa += skip;
447 runs += skip;
448 x += skip;
449 }
450 fBlitter->blitAntiH(x, y, aa, runs);
451 }
452}
453
reed@google.com82065d62011-02-07 15:30:46 +0000454void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455 SkIRect bounds;
456 bounds.set(x, y, x + 1, y + height);
457
458 SkRegion::Cliperator iter(*fRgn, bounds);
459
reed@google.com82065d62011-02-07 15:30:46 +0000460 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461 const SkIRect& r = iter.rect();
462 SkASSERT(bounds.contains(r));
463
464 fBlitter->blitV(x, r.fTop, r.height(), alpha);
465 iter.next();
466 }
467}
468
reed@google.com82065d62011-02-07 15:30:46 +0000469void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470 SkIRect bounds;
471 bounds.set(x, y, x + width, y + height);
472
473 SkRegion::Cliperator iter(*fRgn, bounds);
474
reed@google.com82065d62011-02-07 15:30:46 +0000475 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 const SkIRect& r = iter.rect();
477 SkASSERT(bounds.contains(r));
478
479 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
480 iter.next();
481 }
482}
483
tomhudson@google.com49eac192011-12-27 13:59:20 +0000484void SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
485 SkAlpha leftAlpha, SkAlpha rightAlpha) {
486 // The *true* width of the rectangle to blit is width + 2
487 SkIRect bounds;
488 bounds.set(x, y, x + width + 2, y + height);
489
490 SkRegion::Cliperator iter(*fRgn, bounds);
491
492 while (!iter.done()) {
493 const SkIRect& r = iter.rect();
494 SkASSERT(bounds.contains(r));
495 SkASSERT(r.fLeft >= x);
tomhudson@google.com31bab392012-01-03 20:12:42 +0000496 SkASSERT(r.fRight <= x + width + 2);
tomhudson@google.com49eac192011-12-27 13:59:20 +0000497
498 SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
499 SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
500 rightAlpha : 255;
501
502 if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
503 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
504 } else if (1 == r.width()) {
505 if (r.fLeft == x) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000506 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
tomhudson@google.com49eac192011-12-27 13:59:20 +0000507 effectiveLeftAlpha);
508 } else {
509 SkASSERT(r.fLeft == x + width + 1);
510 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
511 effectiveRightAlpha);
512 }
513 } else {
514 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
515 effectiveLeftAlpha, effectiveRightAlpha);
516 }
517 iter.next();
518 }
519}
520
521
reed@google.com82065d62011-02-07 15:30:46 +0000522void SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000523 SkASSERT(mask.fBounds.contains(clip));
524
525 SkRegion::Cliperator iter(*fRgn, clip);
526 const SkIRect& r = iter.rect();
527 SkBlitter* blitter = fBlitter;
528
reed@google.com82065d62011-02-07 15:30:46 +0000529 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 blitter->blitMask(mask, r);
531 iter.next();
532 }
533}
534
reed@google.com82065d62011-02-07 15:30:46 +0000535const SkBitmap* SkRgnClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000536 return fBlitter->justAnOpaqueColor(value);
537}
538
reed@google.com82065d62011-02-07 15:30:46 +0000539///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
reed@google.com82065d62011-02-07 15:30:46 +0000541SkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip,
542 const SkIRect* ir) {
543 if (clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 const SkIRect& clipR = clip->getBounds();
545
reed@google.com82065d62011-02-07 15:30:46 +0000546 if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547 blitter = &fNullBlitter;
reed@google.com82065d62011-02-07 15:30:46 +0000548 } else if (clip->isRect()) {
549 if (ir == NULL || !clipR.contains(*ir)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000550 fRectBlitter.init(blitter, clipR);
551 blitter = &fRectBlitter;
552 }
reed@google.com82065d62011-02-07 15:30:46 +0000553 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000554 fRgnBlitter.init(blitter, clip);
555 blitter = &fRgnBlitter;
556 }
557 }
558 return blitter;
559}
560
reed@google.com82065d62011-02-07 15:30:46 +0000561///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000562
563#include "SkColorShader.h"
564#include "SkColorPriv.h"
565
566class Sk3DShader : public SkShader {
567public:
reed@google.com82065d62011-02-07 15:30:46 +0000568 Sk3DShader(SkShader* proxy) : fProxy(proxy) {
569 SkSafeRef(proxy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000570 fMask = NULL;
571 }
reed@google.com82065d62011-02-07 15:30:46 +0000572
573 virtual ~Sk3DShader() {
574 SkSafeUnref(fProxy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000575 }
reed@google.com82065d62011-02-07 15:30:46 +0000576
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577 void setMask(const SkMask* mask) { fMask = mask; }
578
reed@google.com82065d62011-02-07 15:30:46 +0000579 virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
reed@google.coma641f3f2012-12-13 22:16:30 +0000580 const SkMatrix& matrix) SK_OVERRIDE {
581 if (!this->INHERITED::setContext(device, paint, matrix)) {
582 return false;
583 }
reed@google.com82065d62011-02-07 15:30:46 +0000584 if (fProxy) {
reed@google.coma641f3f2012-12-13 22:16:30 +0000585 if (!fProxy->setContext(device, paint, matrix)) {
586 // must keep our set/end context calls balanced
587 this->INHERITED::endContext();
588 return false;
589 }
reed@google.com82065d62011-02-07 15:30:46 +0000590 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 fPMColor = SkPreMultiplyColor(paint.getColor());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000592 }
reed@google.coma641f3f2012-12-13 22:16:30 +0000593 return true;
594 }
skia.committer@gmail.com61b05dc2012-12-14 02:02:06 +0000595
reed@google.coma641f3f2012-12-13 22:16:30 +0000596 virtual void endContext() SK_OVERRIDE {
597 if (fProxy) {
598 fProxy->endContext();
599 }
600 this->INHERITED::endContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000602
reed@google.coma641f3f2012-12-13 22:16:30 +0000603 virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE {
reed@google.com82065d62011-02-07 15:30:46 +0000604 if (fProxy) {
605 fProxy->shadeSpan(x, y, span, count);
606 }
607
608 if (fMask == NULL) {
609 if (fProxy == NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000610 sk_memset32(span, fPMColor, count);
reed@google.com82065d62011-02-07 15:30:46 +0000611 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 return;
613 }
614
615 SkASSERT(fMask->fBounds.contains(x, y));
616 SkASSERT(fMask->fBounds.contains(x + count - 1, y));
617
618 size_t size = fMask->computeImageSize();
reed@google.com79891862011-10-18 15:44:57 +0000619 const uint8_t* alpha = fMask->getAddr8(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000620 const uint8_t* mulp = alpha + size;
621 const uint8_t* addp = mulp + size;
622
reed@google.com82065d62011-02-07 15:30:46 +0000623 if (fProxy) {
624 for (int i = 0; i < count; i++) {
625 if (alpha[i]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000626 SkPMColor c = span[i];
reed@google.com82065d62011-02-07 15:30:46 +0000627 if (c) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 unsigned a = SkGetPackedA32(c);
629 unsigned r = SkGetPackedR32(c);
630 unsigned g = SkGetPackedG32(c);
631 unsigned b = SkGetPackedB32(c);
632
633 unsigned mul = SkAlpha255To256(mulp[i]);
634 unsigned add = addp[i];
635
636 r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
637 g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
638 b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
639
640 span[i] = SkPackARGB32(a, r, g, b);
641 }
reed@google.com82065d62011-02-07 15:30:46 +0000642 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 span[i] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000644 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000645 }
reed@google.com82065d62011-02-07 15:30:46 +0000646 } else { // color
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647 unsigned a = SkGetPackedA32(fPMColor);
648 unsigned r = SkGetPackedR32(fPMColor);
649 unsigned g = SkGetPackedG32(fPMColor);
650 unsigned b = SkGetPackedB32(fPMColor);
reed@google.com82065d62011-02-07 15:30:46 +0000651 for (int i = 0; i < count; i++) {
652 if (alpha[i]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000653 unsigned mul = SkAlpha255To256(mulp[i]);
654 unsigned add = addp[i];
655
656 span[i] = SkPackARGB32( a,
reed@google.com82065d62011-02-07 15:30:46 +0000657 SkFastMin32(SkAlphaMul(r, mul) + add, a),
658 SkFastMin32(SkAlphaMul(g, mul) + add, a),
659 SkFastMin32(SkAlphaMul(b, mul) + add, a));
660 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 span[i] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000662 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 }
664 }
665 }
reed@google.com82065d62011-02-07 15:30:46 +0000666
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000667#ifdef SK_DEVELOPER
668 virtual void toString(SkString* str) const SK_OVERRIDE {
669 str->append("Sk3DShader: (");
670
671 if (NULL != fProxy) {
672 str->append("Proxy: ");
673 fProxy->toString(str);
674 }
675
676 this->INHERITED::toString(str);
677
678 str->append(")");
679 }
680#endif
681
djsollen@google.comba28d032012-03-26 17:57:35 +0000682 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(Sk3DShader)
683
reed@android.com8a1c16f2008-12-17 15:59:43 +0000684protected:
djsollen@google.com54924242012-03-29 15:18:04 +0000685 Sk3DShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
reed@google.com35348222013-10-16 13:05:06 +0000686 fProxy = buffer.readShader();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000687 fPMColor = buffer.readColor();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000688 fMask = NULL;
689 }
reed@google.com82065d62011-02-07 15:30:46 +0000690
djsollen@google.com54924242012-03-29 15:18:04 +0000691 virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000692 this->INHERITED::flatten(buffer);
693 buffer.writeFlattenable(fProxy);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000694 buffer.writeColor(fPMColor);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 }
reed@google.com82065d62011-02-07 15:30:46 +0000696
reed@android.com8a1c16f2008-12-17 15:59:43 +0000697private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000698 SkShader* fProxy;
699 SkPMColor fPMColor;
700 const SkMask* fMask;
701
702 typedef SkShader INHERITED;
703};
704
705class Sk3DBlitter : public SkBlitter {
706public:
707 Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*))
reed@google.com82065d62011-02-07 15:30:46 +0000708 : fProxy(proxy), f3DShader(shader), fKillProc(killProc) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709 shader->ref();
710 }
reed@google.com82065d62011-02-07 15:30:46 +0000711
712 virtual ~Sk3DBlitter() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 f3DShader->unref();
714 fKillProc(fProxy);
715 }
716
reed@google.com82065d62011-02-07 15:30:46 +0000717 virtual void blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000718 fProxy->blitH(x, y, width);
719 }
reed@google.com82065d62011-02-07 15:30:46 +0000720
721 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
722 const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000723 fProxy->blitAntiH(x, y, antialias, runs);
724 }
reed@google.com82065d62011-02-07 15:30:46 +0000725
726 virtual void blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000727 fProxy->blitV(x, y, height, alpha);
728 }
reed@google.com82065d62011-02-07 15:30:46 +0000729
730 virtual void blitRect(int x, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000731 fProxy->blitRect(x, y, width, height);
732 }
reed@google.com82065d62011-02-07 15:30:46 +0000733
734 virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
735 if (mask.fFormat == SkMask::k3D_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000736 f3DShader->setMask(&mask);
737
738 ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
739 fProxy->blitMask(mask, clip);
740 ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
741
742 f3DShader->setMask(NULL);
reed@google.com82065d62011-02-07 15:30:46 +0000743 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744 fProxy->blitMask(mask, clip);
reed@google.com82065d62011-02-07 15:30:46 +0000745 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000746 }
reed@google.com82065d62011-02-07 15:30:46 +0000747
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748private:
749 SkBlitter* fProxy;
750 Sk3DShader* f3DShader;
751 void (*fKillProc)(void*);
752};
753
reed@google.com82065d62011-02-07 15:30:46 +0000754///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755
756#include "SkCoreBlitters.h"
757
reed@android.com8a1c16f2008-12-17 15:59:43 +0000758class SkAutoCallProc {
759public:
760 typedef void (*Proc)(void*);
reed@google.com82065d62011-02-07 15:30:46 +0000761
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762 SkAutoCallProc(void* obj, Proc proc)
reed@google.com82065d62011-02-07 15:30:46 +0000763 : fObj(obj), fProc(proc) {}
764
765 ~SkAutoCallProc() {
766 if (fObj && fProc) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000767 fProc(fObj);
reed@google.com82065d62011-02-07 15:30:46 +0000768 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000769 }
reed@google.com82065d62011-02-07 15:30:46 +0000770
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 void* get() const { return fObj; }
reed@google.com82065d62011-02-07 15:30:46 +0000772
773 void* detach() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000774 void* obj = fObj;
775 fObj = NULL;
776 return obj;
777 }
reed@google.com82065d62011-02-07 15:30:46 +0000778
reed@android.com8a1c16f2008-12-17 15:59:43 +0000779private:
780 void* fObj;
781 Proc fProc;
782};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000783#define SkAutoCallProc(...) SK_REQUIRE_LOCAL_VAR(SkAutoCallProc)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000784
reed@google.com82065d62011-02-07 15:30:46 +0000785static void destroy_blitter(void* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000786 ((SkBlitter*)blitter)->~SkBlitter();
787}
788
reed@google.com82065d62011-02-07 15:30:46 +0000789static void delete_blitter(void* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 SkDELETE((SkBlitter*)blitter);
791}
792
reed@android.comd252db02009-04-01 18:31:44 +0000793static bool just_solid_color(const SkPaint& paint) {
794 if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
795 SkShader* shader = paint.getShader();
796 if (NULL == shader ||
797 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
798 return true;
799 }
800 }
801 return false;
802}
reed@google.com82065d62011-02-07 15:30:46 +0000803
reed@android.comd252db02009-04-01 18:31:44 +0000804/** By analyzing the paint (with an xfermode), we may decide we can take
805 special action. This enum lists our possible actions
806 */
807enum XferInterp {
808 kNormal_XferInterp, // no special interpretation, draw normally
809 kSrcOver_XferInterp, // draw as if in srcover mode
810 kSkipDrawing_XferInterp // draw nothing
811};
812
813static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
814 SkBitmap::Config deviceConfig) {
reed@android.com845fdac2009-06-23 03:01:32 +0000815 SkXfermode::Mode mode;
reed@google.com82065d62011-02-07 15:30:46 +0000816
mike@reedtribe.orgbe2aa2a2011-11-17 02:32:04 +0000817 if (SkXfermode::AsMode(xfer, &mode)) {
reed@android.comd252db02009-04-01 18:31:44 +0000818 switch (mode) {
reed@android.com845fdac2009-06-23 03:01:32 +0000819 case SkXfermode::kSrc_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000820 if (just_solid_color(paint)) {
821 return kSrcOver_XferInterp;
822 }
823 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000824 case SkXfermode::kDst_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000825 return kSkipDrawing_XferInterp;
reed@android.com845fdac2009-06-23 03:01:32 +0000826 case SkXfermode::kSrcOver_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000827 return kSrcOver_XferInterp;
reed@android.com845fdac2009-06-23 03:01:32 +0000828 case SkXfermode::kDstOver_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000829 if (SkBitmap::kRGB_565_Config == deviceConfig) {
830 return kSkipDrawing_XferInterp;
831 }
832 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000833 case SkXfermode::kSrcIn_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000834 if (SkBitmap::kRGB_565_Config == deviceConfig &&
835 just_solid_color(paint)) {
836 return kSrcOver_XferInterp;
837 }
838 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000839 case SkXfermode::kDstIn_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000840 if (just_solid_color(paint)) {
841 return kSkipDrawing_XferInterp;
842 }
843 break;
844 default:
845 break;
846 }
847 }
848 return kNormal_XferInterp;
849}
850
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851SkBlitter* SkBlitter::Choose(const SkBitmap& device,
852 const SkMatrix& matrix,
reed@google.com6b7aee32011-04-19 18:36:09 +0000853 const SkPaint& origPaint,
reed@google.com126f7f52013-11-07 16:06:53 +0000854 void* storage, size_t storageSize,
855 bool drawCoverage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856 SkASSERT(storageSize == 0 || storage != NULL);
857
858 SkBlitter* blitter = NULL;
859
860 // which check, in case we're being called by a client with a dummy device
861 // (e.g. they have a bounder that always aborts the draw)
reed@google.com126f7f52013-11-07 16:06:53 +0000862 if (SkBitmap::kNo_Config == device.config() ||
863 (drawCoverage && (SkBitmap::kA8_Config != device.config()))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000864 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
865 return blitter;
866 }
867
reed@google.com45884902012-05-11 14:38:51 +0000868 SkShader* shader = origPaint.getShader();
869 SkColorFilter* cf = origPaint.getColorFilter();
870 SkXfermode* mode = origPaint.getXfermode();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000871 Sk3DShader* shader3D = NULL;
reed@google.com45884902012-05-11 14:38:51 +0000872
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000873 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000874
reed@google.com45884902012-05-11 14:38:51 +0000875 if (origPaint.getMaskFilter() != NULL &&
876 origPaint.getMaskFilter()->getFormat() == SkMask::k3D_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877 shader3D = SkNEW_ARGS(Sk3DShader, (shader));
reed@google.com45884902012-05-11 14:38:51 +0000878 // we know we haven't initialized lazyPaint yet, so just do it
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000879 paint.writable()->setShader(shader3D)->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000880 shader = shader3D;
881 }
882
reed@android.comd252db02009-04-01 18:31:44 +0000883 if (NULL != mode) {
reed@google.com45884902012-05-11 14:38:51 +0000884 switch (interpret_xfermode(*paint, mode, device.config())) {
reed@android.comd252db02009-04-01 18:31:44 +0000885 case kSrcOver_XferInterp:
886 mode = NULL;
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000887 paint.writable()->setXfermode(NULL);
reed@android.comd252db02009-04-01 18:31:44 +0000888 break;
889 case kSkipDrawing_XferInterp:
890 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
891 return blitter;
892 default:
893 break;
894 }
895 }
896
reed@google.com13201e72012-11-16 13:20:41 +0000897 /*
898 * If the xfermode is CLEAR, then we can completely ignore the installed
899 * color/shader/colorfilter, and just pretend we're SRC + color==0. This
900 * will fall into our optimizations for SRC mode.
901 */
902 if (SkXfermode::IsMode(mode, SkXfermode::kClear_Mode)) {
903 SkPaint* p = paint.writable();
904 shader = p->setShader(NULL);
905 cf = p->setColorFilter(NULL);
906 mode = p->setXfermodeMode(SkXfermode::kSrc_Mode);
907 p->setColor(0);
908 }
reed@google.com13201e72012-11-16 13:20:41 +0000909
reed@google.com6b7aee32011-04-19 18:36:09 +0000910 if (NULL == shader) {
reed@google.com6b7aee32011-04-19 18:36:09 +0000911 if (mode) {
reed@google.com6b7aee32011-04-19 18:36:09 +0000912 // xfermodes (and filters) require shaders for our current blitters
913 shader = SkNEW(SkColorShader);
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000914 paint.writable()->setShader(shader)->unref();
reed@google.com6b7aee32011-04-19 18:36:09 +0000915 } else if (cf) {
916 // if no shader && no xfermode, we just apply the colorfilter to
917 // our color and move on.
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000918 SkPaint* writablePaint = paint.writable();
919 writablePaint->setColor(cf->filterColor(paint->getColor()));
920 writablePaint->setColorFilter(NULL);
reed@google.com6b7aee32011-04-19 18:36:09 +0000921 cf = NULL;
922 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 }
reed@google.com82065d62011-02-07 15:30:46 +0000924
reed@google.com6b7aee32011-04-19 18:36:09 +0000925 if (cf) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926 SkASSERT(shader);
reed@google.com6b7aee32011-04-19 18:36:09 +0000927 shader = SkNEW_ARGS(SkFilterShader, (shader, cf));
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000928 paint.writable()->setShader(shader)->unref();
reed@android.com1fc4c602009-10-02 16:34:57 +0000929 // blitters should ignore the presence/absence of a filter, since
930 // if there is one, the shader will take care of it.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931 }
reed@google.com82065d62011-02-07 15:30:46 +0000932
reed@google.coma641f3f2012-12-13 22:16:30 +0000933 /*
934 * We need to have balanced calls to the shader:
935 * setContext
936 * endContext
937 * We make the first call here, in case it fails we can abort the draw.
938 * The endContext() call is made by the blitter (assuming setContext did
939 * not fail) in its destructor.
940 */
reed@google.com45884902012-05-11 14:38:51 +0000941 if (shader && !shader->setContext(device, *paint, matrix)) {
reed@google.coma641f3f2012-12-13 22:16:30 +0000942 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
943 return blitter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944 }
945
skia.committer@gmail.comab7442c2013-11-08 07:01:56 +0000946
reed@google.com44699382013-10-31 17:28:30 +0000947 switch (device.config()) {
reed@google.com82065d62011-02-07 15:30:46 +0000948 case SkBitmap::kA8_Config:
reed@google.com126f7f52013-11-07 16:06:53 +0000949 if (drawCoverage) {
950 SkASSERT(NULL == shader);
951 SkASSERT(NULL == paint->getXfermode());
952 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Coverage_Blitter,
953 storage, storageSize, (device, *paint));
954 } else if (shader) {
reed@google.com82065d62011-02-07 15:30:46 +0000955 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000956 storage, storageSize, (device, *paint));
reed@google.com82065d62011-02-07 15:30:46 +0000957 } else {
958 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000959 storage, storageSize, (device, *paint));
reed@google.com82065d62011-02-07 15:30:46 +0000960 }
961 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962
reed@google.com82065d62011-02-07 15:30:46 +0000963 case SkBitmap::kRGB_565_Config:
reed@google.com45884902012-05-11 14:38:51 +0000964 blitter = SkBlitter_ChooseD565(device, *paint, storage, storageSize);
reed@google.com82065d62011-02-07 15:30:46 +0000965 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966
reed@google.com82065d62011-02-07 15:30:46 +0000967 case SkBitmap::kARGB_8888_Config:
968 if (shader) {
969 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000970 storage, storageSize, (device, *paint));
971 } else if (paint->getColor() == SK_ColorBLACK) {
reed@google.com82065d62011-02-07 15:30:46 +0000972 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000973 storage, storageSize, (device, *paint));
974 } else if (paint->getAlpha() == 0xFF) {
reed@google.com82065d62011-02-07 15:30:46 +0000975 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000976 storage, storageSize, (device, *paint));
reed@google.com82065d62011-02-07 15:30:46 +0000977 } else {
978 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter,
reed@google.com45884902012-05-11 14:38:51 +0000979 storage, storageSize, (device, *paint));
reed@google.com82065d62011-02-07 15:30:46 +0000980 }
981 break;
982
983 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000984 SkDEBUGFAIL("unsupported device config");
reed@google.com82065d62011-02-07 15:30:46 +0000985 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
986 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987 }
988
reed@google.com82065d62011-02-07 15:30:46 +0000989 if (shader3D) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000990 void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter;
991 SkAutoCallProc tmp(blitter, proc);
992
993 blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc));
994 (void)tmp.detach();
995 }
996 return blitter;
997}
998
reed@google.com82065d62011-02-07 15:30:46 +0000999///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000
1001const uint16_t gMask_0F0F = 0xF0F;
1002const uint32_t gMask_00FF00FF = 0xFF00FF;
1003
reed@google.com82065d62011-02-07 15:30:46 +00001004///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005
1006SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
reed@android.com5119bdb2009-06-12 21:27:03 +00001007 : INHERITED(device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 fShader = paint.getShader();
1009 SkASSERT(fShader);
reed@google.coma641f3f2012-12-13 22:16:30 +00001010 SkASSERT(fShader->setContextHasBeenCalled());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001011
1012 fShader->ref();
reed@android.com5119bdb2009-06-12 21:27:03 +00001013 fShaderFlags = fShader->getFlags();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001014}
1015
reed@android.com5119bdb2009-06-12 21:27:03 +00001016SkShaderBlitter::~SkShaderBlitter() {
reed@google.coma641f3f2012-12-13 22:16:30 +00001017 SkASSERT(fShader->setContextHasBeenCalled());
1018 fShader->endContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019 fShader->unref();
1020}