blob: 265ae6b6ef9b78905224c50bc0de1599f4cb0533 [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"
14#include "SkMask.h"
15#include "SkMaskFilter.h"
16#include "SkTemplatesPriv.h"
17#include "SkUtils.h"
18#include "SkXfermode.h"
19
reed@android.com845fdac2009-06-23 03:01:32 +000020SkBlitter::~SkBlitter() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
reed@google.com82065d62011-02-07 15:30:46 +000022const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000023 return NULL;
24}
25
reed@google.com82065d62011-02-07 15:30:46 +000026void SkBlitter::blitH(int x, int y, int width) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000027 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000028}
29
reed@google.com82065d62011-02-07 15:30:46 +000030void SkBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
31 const int16_t runs[]) {
tomhudson@google.com0c00f212011-12-28 14:59:50 +000032 SkDEBUGFAIL("unimplemented");
reed@android.com8a1c16f2008-12-17 15:59:43 +000033}
34
reed@google.com82065d62011-02-07 15:30:46 +000035void SkBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
36 if (alpha == 255) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 this->blitRect(x, y, 1, height);
reed@google.com82065d62011-02-07 15:30:46 +000038 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 int16_t runs[2];
40 runs[0] = 1;
41 runs[1] = 0;
42
reed@google.com82065d62011-02-07 15:30:46 +000043 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 this->blitAntiH(x, y++, &alpha, runs);
reed@google.com82065d62011-02-07 15:30:46 +000045 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 }
47}
48
reed@google.com82065d62011-02-07 15:30:46 +000049void SkBlitter::blitRect(int x, int y, int width, int height) {
tomhudson@google.com47143592011-12-28 17:58:07 +000050 SkASSERT(width >= 0);
reed@google.com82065d62011-02-07 15:30:46 +000051 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000052 this->blitH(x, y++, width);
reed@google.com82065d62011-02-07 15:30:46 +000053 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000054}
55
tomhudson@google.com49eac192011-12-27 13:59:20 +000056/// Default implementation doesn't check for any easy optimizations
57/// such as alpha == 0 or 255; also uses blitV(), which some subclasses
58/// may not support.
59void SkBlitter::blitAntiRect(int x, int y, int width, int height,
60 SkAlpha leftAlpha, SkAlpha rightAlpha) {
tomhudson@google.com47143592011-12-28 17:58:07 +000061 this->blitV(x++, y, height, leftAlpha);
62 if (width >= 0) {
63 this->blitRect(x, y, width, height);
64 x += width;
65 }
66 this->blitV(x, y, height, rightAlpha);
tomhudson@google.com49eac192011-12-27 13:59:20 +000067}
68
reed@android.com8a1c16f2008-12-17 15:59:43 +000069//////////////////////////////////////////////////////////////////////////////
70
reed@google.com82065d62011-02-07 15:30:46 +000071static inline void bits_to_runs(SkBlitter* blitter, int x, int y,
72 const uint8_t bits[],
73 U8CPU left_mask, int rowBytes,
74 U8CPU right_mask) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 int inFill = 0;
76 int pos = 0;
77
reed@google.com82065d62011-02-07 15:30:46 +000078 while (--rowBytes >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 unsigned b = *bits++ & left_mask;
reed@google.com82065d62011-02-07 15:30:46 +000080 if (rowBytes == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 b &= right_mask;
reed@google.com82065d62011-02-07 15:30:46 +000082 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000083
reed@google.com82065d62011-02-07 15:30:46 +000084 for (unsigned test = 0x80; test != 0; test >>= 1) {
85 if (b & test) {
86 if (!inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 pos = x;
88 inFill = true;
89 }
reed@google.com82065d62011-02-07 15:30:46 +000090 } else {
91 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 blitter->blitH(pos, y, x - pos);
93 inFill = false;
94 }
95 }
96 x += 1;
97 }
98 left_mask = 0xFF;
99 }
100
101 // final cleanup
reed@google.com82065d62011-02-07 15:30:46 +0000102 if (inFill) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 blitter->blitH(pos, y, x - pos);
reed@google.com82065d62011-02-07 15:30:46 +0000104 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105}
106
reed@google.com82065d62011-02-07 15:30:46 +0000107void SkBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108 SkASSERT(mask.fBounds.contains(clip));
109
reed@google.com82065d62011-02-07 15:30:46 +0000110 if (mask.fFormat == SkMask::kBW_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 int cx = clip.fLeft;
112 int cy = clip.fTop;
113 int maskLeft = mask.fBounds.fLeft;
114 int mask_rowBytes = mask.fRowBytes;
115 int height = clip.height();
116
117 const uint8_t* bits = mask.getAddr1(cx, cy);
118
reed@google.com82065d62011-02-07 15:30:46 +0000119 if (cx == maskLeft && clip.fRight == mask.fBounds.fRight) {
120 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 bits_to_runs(this, cx, cy, bits, 0xFF, mask_rowBytes, 0xFF);
122 bits += mask_rowBytes;
123 cy += 1;
124 }
reed@google.com82065d62011-02-07 15:30:46 +0000125 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 int left_edge = cx - maskLeft;
127 SkASSERT(left_edge >= 0);
128 int rite_edge = clip.fRight - maskLeft;
129 SkASSERT(rite_edge > left_edge);
130
131 int left_mask = 0xFF >> (left_edge & 7);
132 int rite_mask = 0xFF << (8 - (rite_edge & 7));
133 int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
134
reed@google.coma89c77b2011-12-01 21:47:26 +0000135 // 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 +0000136 if (rite_mask == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 SkASSERT(full_runs >= 0);
138 full_runs -= 1;
139 rite_mask = 0xFF;
140 }
reed@google.com82065d62011-02-07 15:30:46 +0000141 if (left_mask == 0xFF) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 full_runs -= 1;
reed@google.com82065d62011-02-07 15:30:46 +0000143 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144
reed@google.coma89c77b2011-12-01 21:47:26 +0000145 // back up manually so we can keep in sync with our byte-aligned src
146 // have cx reflect our actual starting x-coord
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 cx -= left_edge & 7;
148
reed@google.com82065d62011-02-07 15:30:46 +0000149 if (full_runs < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 SkASSERT((left_mask & rite_mask) != 0);
reed@google.com82065d62011-02-07 15:30:46 +0000151 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 bits_to_runs(this, cx, cy, bits, left_mask, 1, rite_mask);
153 bits += mask_rowBytes;
154 cy += 1;
155 }
reed@google.com82065d62011-02-07 15:30:46 +0000156 } else {
157 while (--height >= 0) {
reed@google.coma89c77b2011-12-01 21:47:26 +0000158 bits_to_runs(this, cx, cy, bits, left_mask, full_runs + 2, rite_mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 bits += mask_rowBytes;
160 cy += 1;
161 }
162 }
163 }
reed@google.com82065d62011-02-07 15:30:46 +0000164 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 int width = clip.width();
166 SkAutoSTMalloc<64, int16_t> runStorage(width + 1);
167 int16_t* runs = runStorage.get();
reed@google.com79891862011-10-18 15:44:57 +0000168 const uint8_t* aa = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169
170 sk_memset16((uint16_t*)runs, 1, width);
171 runs[width] = 0;
172
173 int height = clip.height();
174 int y = clip.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000175 while (--height >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 this->blitAntiH(clip.fLeft, y, aa, runs);
177 aa += mask.fRowBytes;
178 y += 1;
179 }
180 }
181}
182
183/////////////////////// these guys are not virtual, just a helpers
184
185void SkBlitter::blitMaskRegion(const SkMask& mask, const SkRegion& clip) {
186 if (clip.quickReject(mask.fBounds)) {
187 return;
188 }
reed@google.com82065d62011-02-07 15:30:46 +0000189
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190 SkRegion::Cliperator clipper(clip, mask.fBounds);
reed@google.com82065d62011-02-07 15:30:46 +0000191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 while (!clipper.done()) {
193 const SkIRect& cr = clipper.rect();
194 this->blitMask(mask, cr);
195 clipper.next();
196 }
197}
198
199void SkBlitter::blitRectRegion(const SkIRect& rect, const SkRegion& clip) {
200 SkRegion::Cliperator clipper(clip, rect);
reed@google.com82065d62011-02-07 15:30:46 +0000201
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 while (!clipper.done()) {
203 const SkIRect& cr = clipper.rect();
204 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
205 clipper.next();
206 }
207}
208
209void SkBlitter::blitRegion(const SkRegion& clip) {
210 SkRegion::Iterator iter(clip);
reed@google.com82065d62011-02-07 15:30:46 +0000211
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 while (!iter.done()) {
213 const SkIRect& cr = iter.rect();
214 this->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
215 iter.next();
216 }
217}
218
reed@google.com82065d62011-02-07 15:30:46 +0000219///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220
reed@google.com82065d62011-02-07 15:30:46 +0000221void SkNullBlitter::blitH(int x, int y, int width) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222
reed@google.com82065d62011-02-07 15:30:46 +0000223void SkNullBlitter::blitAntiH(int x, int y, const SkAlpha antialias[],
224 const int16_t runs[]) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225
reed@google.com82065d62011-02-07 15:30:46 +0000226void SkNullBlitter::blitV(int x, int y, int height, SkAlpha alpha) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227
reed@google.com82065d62011-02-07 15:30:46 +0000228void SkNullBlitter::blitRect(int x, int y, int width, int height) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
reed@google.com82065d62011-02-07 15:30:46 +0000230void SkNullBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231
reed@google.com82065d62011-02-07 15:30:46 +0000232const SkBitmap* SkNullBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 return NULL;
234}
235
reed@google.com82065d62011-02-07 15:30:46 +0000236///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237
reed@google.com82065d62011-02-07 15:30:46 +0000238static int compute_anti_width(const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 int width = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000240
241 for (;;) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 int count = runs[0];
reed@google.com82065d62011-02-07 15:30:46 +0000243
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 SkASSERT(count >= 0);
reed@google.com82065d62011-02-07 15:30:46 +0000245 if (count == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 break;
reed@google.com82065d62011-02-07 15:30:46 +0000247 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248 width += count;
249 runs += count;
reed@google.com82065d62011-02-07 15:30:46 +0000250
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 SkASSERT(width < 20000);
252 }
253 return width;
254}
255
reed@google.com82065d62011-02-07 15:30:46 +0000256static inline bool y_in_rect(int y, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257 return (unsigned)(y - rect.fTop) < (unsigned)rect.height();
258}
259
reed@google.com82065d62011-02-07 15:30:46 +0000260static inline bool x_in_rect(int x, const SkIRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width();
262}
263
reed@google.com82065d62011-02-07 15:30:46 +0000264void SkRectClipBlitter::blitH(int left, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 SkASSERT(width > 0);
266
reed@google.com82065d62011-02-07 15:30:46 +0000267 if (!y_in_rect(y, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 return;
reed@google.com82065d62011-02-07 15:30:46 +0000269 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270
271 int right = left + width;
272
reed@google.com82065d62011-02-07 15:30:46 +0000273 if (left < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 left = fClipRect.fLeft;
reed@google.com82065d62011-02-07 15:30:46 +0000275 }
276 if (right > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 right = fClipRect.fRight;
reed@google.com82065d62011-02-07 15:30:46 +0000278 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279
280 width = right - left;
reed@google.com82065d62011-02-07 15:30:46 +0000281 if (width > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 fBlitter->blitH(left, y, width);
reed@google.com82065d62011-02-07 15:30:46 +0000283 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284}
285
reed@google.com82065d62011-02-07 15:30:46 +0000286void SkRectClipBlitter::blitAntiH(int left, int y, const SkAlpha aa[],
287 const int16_t runs[]) {
288 if (!y_in_rect(y, fClipRect) || left >= fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 return;
reed@google.com82065d62011-02-07 15:30:46 +0000290 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291
292 int x0 = left;
293 int x1 = left + compute_anti_width(runs);
294
reed@google.com82065d62011-02-07 15:30:46 +0000295 if (x1 <= fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296 return;
reed@google.com82065d62011-02-07 15:30:46 +0000297 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298
299 SkASSERT(x0 < x1);
reed@google.com82065d62011-02-07 15:30:46 +0000300 if (x0 < fClipRect.fLeft) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 int dx = fClipRect.fLeft - x0;
302 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, dx);
303 runs += dx;
304 aa += dx;
305 x0 = fClipRect.fLeft;
306 }
307
308 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
reed@google.com82065d62011-02-07 15:30:46 +0000309 if (x1 > fClipRect.fRight) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000310 x1 = fClipRect.fRight;
311 SkAlphaRuns::BreakAt((int16_t*)runs, (uint8_t*)aa, x1 - x0);
312 ((int16_t*)runs)[x1 - x0] = 0;
313 }
314
315 SkASSERT(x0 < x1 && runs[x1 - x0] == 0);
316 SkASSERT(compute_anti_width(runs) == x1 - x0);
317
318 fBlitter->blitAntiH(x0, y, aa, runs);
319}
320
reed@google.com82065d62011-02-07 15:30:46 +0000321void SkRectClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 SkASSERT(height > 0);
323
reed@google.com82065d62011-02-07 15:30:46 +0000324 if (!x_in_rect(x, fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 return;
reed@google.com82065d62011-02-07 15:30:46 +0000326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327
328 int y0 = y;
329 int y1 = y + height;
330
reed@google.com82065d62011-02-07 15:30:46 +0000331 if (y0 < fClipRect.fTop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332 y0 = fClipRect.fTop;
reed@google.com82065d62011-02-07 15:30:46 +0000333 }
334 if (y1 > fClipRect.fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 y1 = fClipRect.fBottom;
reed@google.com82065d62011-02-07 15:30:46 +0000336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337
reed@google.com82065d62011-02-07 15:30:46 +0000338 if (y0 < y1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339 fBlitter->blitV(x, y0, y1 - y0, alpha);
reed@google.com82065d62011-02-07 15:30:46 +0000340 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341}
342
reed@google.com82065d62011-02-07 15:30:46 +0000343void SkRectClipBlitter::blitRect(int left, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 SkIRect r;
345
346 r.set(left, y, left + width, y + height);
reed@google.com82065d62011-02-07 15:30:46 +0000347 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
reed@google.com82065d62011-02-07 15:30:46 +0000349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350}
351
tomhudson@google.com49eac192011-12-27 13:59:20 +0000352void SkRectClipBlitter::blitAntiRect(int left, int y, int width, int height,
353 SkAlpha leftAlpha, SkAlpha rightAlpha) {
354 SkIRect r;
355
356 // The *true* width of the rectangle blitted is width+2:
357 r.set(left, y, left + width + 2, y + height);
358 if (r.intersect(fClipRect)) {
359 if (r.fLeft != left) {
360 SkASSERT(r.fLeft > left);
361 leftAlpha = 255;
362 }
363 if (r.fRight != left + width + 2) {
364 SkASSERT(r.fRight < left + width + 2);
365 rightAlpha = 255;
366 }
367 if (255 == leftAlpha && 255 == rightAlpha) {
368 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
369 } else if (1 == r.width()) {
370 if (r.fLeft == left) {
371 fBlitter->blitV(r.fLeft, r.fTop, r.height(), leftAlpha);
372 } else {
373 SkASSERT(r.fLeft == left + width + 1);
374 fBlitter->blitV(r.fLeft, r.fTop, r.height(), rightAlpha);
375 }
376 } else {
377 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
378 leftAlpha, rightAlpha);
379 }
380 }
381}
382
reed@google.com82065d62011-02-07 15:30:46 +0000383void SkRectClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 SkASSERT(mask.fBounds.contains(clip));
385
386 SkIRect r = clip;
387
reed@google.com82065d62011-02-07 15:30:46 +0000388 if (r.intersect(fClipRect)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000389 fBlitter->blitMask(mask, r);
reed@google.com82065d62011-02-07 15:30:46 +0000390 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391}
392
reed@google.com82065d62011-02-07 15:30:46 +0000393const SkBitmap* SkRectClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000394 return fBlitter->justAnOpaqueColor(value);
395}
396
reed@google.com82065d62011-02-07 15:30:46 +0000397///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000398
reed@google.com82065d62011-02-07 15:30:46 +0000399void SkRgnClipBlitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 SkRegion::Spanerator span(*fRgn, y, x, x + width);
401 int left, right;
402
reed@google.com82065d62011-02-07 15:30:46 +0000403 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 SkASSERT(left < right);
405 fBlitter->blitH(left, y, right - left);
406 }
407}
408
reed@google.com82065d62011-02-07 15:30:46 +0000409void SkRgnClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[],
410 const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411 int width = compute_anti_width(runs);
412 SkRegion::Spanerator span(*fRgn, y, x, x + width);
413 int left, right;
414 SkDEBUGCODE(const SkIRect& bounds = fRgn->getBounds();)
reed@google.com82065d62011-02-07 15:30:46 +0000415
reed@android.com8a1c16f2008-12-17 15:59:43 +0000416 int prevRite = x;
reed@google.com82065d62011-02-07 15:30:46 +0000417 while (span.next(&left, &right)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418 SkASSERT(x <= left);
419 SkASSERT(left < right);
420 SkASSERT(left >= bounds.fLeft && right <= bounds.fRight);
reed@google.com82065d62011-02-07 15:30:46 +0000421
reed@android.com8a1c16f2008-12-17 15:59:43 +0000422 SkAlphaRuns::Break((int16_t*)runs, (uint8_t*)aa, left - x, right - left);
423
424 // now zero before left
reed@google.com82065d62011-02-07 15:30:46 +0000425 if (left > prevRite) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426 int index = prevRite - x;
427 ((uint8_t*)aa)[index] = 0; // skip runs after right
428 ((int16_t*)runs)[index] = SkToS16(left - prevRite);
429 }
reed@google.com82065d62011-02-07 15:30:46 +0000430
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431 prevRite = right;
432 }
reed@google.com82065d62011-02-07 15:30:46 +0000433
434 if (prevRite > x) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000435 ((int16_t*)runs)[prevRite - x] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000436
reed@android.com8a1c16f2008-12-17 15:59:43 +0000437 if (x < 0) {
438 int skip = runs[0];
439 SkASSERT(skip >= -x);
440 aa += skip;
441 runs += skip;
442 x += skip;
443 }
444 fBlitter->blitAntiH(x, y, aa, runs);
445 }
446}
447
reed@google.com82065d62011-02-07 15:30:46 +0000448void SkRgnClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449 SkIRect bounds;
450 bounds.set(x, y, x + 1, y + height);
451
452 SkRegion::Cliperator iter(*fRgn, bounds);
453
reed@google.com82065d62011-02-07 15:30:46 +0000454 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000455 const SkIRect& r = iter.rect();
456 SkASSERT(bounds.contains(r));
457
458 fBlitter->blitV(x, r.fTop, r.height(), alpha);
459 iter.next();
460 }
461}
462
reed@google.com82065d62011-02-07 15:30:46 +0000463void SkRgnClipBlitter::blitRect(int x, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000464 SkIRect bounds;
465 bounds.set(x, y, x + width, y + height);
466
467 SkRegion::Cliperator iter(*fRgn, bounds);
468
reed@google.com82065d62011-02-07 15:30:46 +0000469 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000470 const SkIRect& r = iter.rect();
471 SkASSERT(bounds.contains(r));
472
473 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
474 iter.next();
475 }
476}
477
tomhudson@google.com49eac192011-12-27 13:59:20 +0000478void SkRgnClipBlitter::blitAntiRect(int x, int y, int width, int height,
479 SkAlpha leftAlpha, SkAlpha rightAlpha) {
480 // The *true* width of the rectangle to blit is width + 2
481 SkIRect bounds;
482 bounds.set(x, y, x + width + 2, y + height);
483
484 SkRegion::Cliperator iter(*fRgn, bounds);
485
486 while (!iter.done()) {
487 const SkIRect& r = iter.rect();
488 SkASSERT(bounds.contains(r));
489 SkASSERT(r.fLeft >= x);
490 SkASSERT(r.fRight < x + width + 2);
491
492 SkAlpha effectiveLeftAlpha = (r.fLeft == x) ? leftAlpha : 255;
493 SkAlpha effectiveRightAlpha = (r.fRight == x + width + 2) ?
494 rightAlpha : 255;
495
496 if (255 == effectiveLeftAlpha && 255 == effectiveRightAlpha) {
497 fBlitter->blitRect(r.fLeft, r.fTop, r.width(), r.height());
498 } else if (1 == r.width()) {
499 if (r.fLeft == x) {
500 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
501 effectiveLeftAlpha);
502 } else {
503 SkASSERT(r.fLeft == x + width + 1);
504 fBlitter->blitV(r.fLeft, r.fTop, r.height(),
505 effectiveRightAlpha);
506 }
507 } else {
508 fBlitter->blitAntiRect(r.fLeft, r.fTop, r.width() - 2, r.height(),
509 effectiveLeftAlpha, effectiveRightAlpha);
510 }
511 iter.next();
512 }
513}
514
515
reed@google.com82065d62011-02-07 15:30:46 +0000516void SkRgnClipBlitter::blitMask(const SkMask& mask, const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517 SkASSERT(mask.fBounds.contains(clip));
518
519 SkRegion::Cliperator iter(*fRgn, clip);
520 const SkIRect& r = iter.rect();
521 SkBlitter* blitter = fBlitter;
522
reed@google.com82065d62011-02-07 15:30:46 +0000523 while (!iter.done()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524 blitter->blitMask(mask, r);
525 iter.next();
526 }
527}
528
reed@google.com82065d62011-02-07 15:30:46 +0000529const SkBitmap* SkRgnClipBlitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 return fBlitter->justAnOpaqueColor(value);
531}
532
reed@google.com82065d62011-02-07 15:30:46 +0000533///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000534
reed@google.com82065d62011-02-07 15:30:46 +0000535SkBlitter* SkBlitterClipper::apply(SkBlitter* blitter, const SkRegion* clip,
536 const SkIRect* ir) {
537 if (clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538 const SkIRect& clipR = clip->getBounds();
539
reed@google.com82065d62011-02-07 15:30:46 +0000540 if (clip->isEmpty() || (ir && !SkIRect::Intersects(clipR, *ir))) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541 blitter = &fNullBlitter;
reed@google.com82065d62011-02-07 15:30:46 +0000542 } else if (clip->isRect()) {
543 if (ir == NULL || !clipR.contains(*ir)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 fRectBlitter.init(blitter, clipR);
545 blitter = &fRectBlitter;
546 }
reed@google.com82065d62011-02-07 15:30:46 +0000547 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548 fRgnBlitter.init(blitter, clip);
549 blitter = &fRgnBlitter;
550 }
551 }
552 return blitter;
553}
554
reed@google.com82065d62011-02-07 15:30:46 +0000555///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556
557#include "SkColorShader.h"
558#include "SkColorPriv.h"
559
560class Sk3DShader : public SkShader {
561public:
reed@google.com82065d62011-02-07 15:30:46 +0000562 Sk3DShader(SkShader* proxy) : fProxy(proxy) {
563 SkSafeRef(proxy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564 fMask = NULL;
565 }
reed@google.com82065d62011-02-07 15:30:46 +0000566
567 virtual ~Sk3DShader() {
568 SkSafeUnref(fProxy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000569 }
reed@google.com82065d62011-02-07 15:30:46 +0000570
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571 void setMask(const SkMask* mask) { fMask = mask; }
572
reed@google.com82065d62011-02-07 15:30:46 +0000573 virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
574 const SkMatrix& matrix) {
575 if (fProxy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 return fProxy->setContext(device, paint, matrix);
reed@google.com82065d62011-02-07 15:30:46 +0000577 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578 fPMColor = SkPreMultiplyColor(paint.getColor());
579 return this->INHERITED::setContext(device, paint, matrix);
580 }
581 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582
reed@google.com82065d62011-02-07 15:30:46 +0000583 virtual void shadeSpan(int x, int y, SkPMColor span[], int count) {
584 if (fProxy) {
585 fProxy->shadeSpan(x, y, span, count);
586 }
587
588 if (fMask == NULL) {
589 if (fProxy == NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000590 sk_memset32(span, fPMColor, count);
reed@google.com82065d62011-02-07 15:30:46 +0000591 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000592 return;
593 }
594
595 SkASSERT(fMask->fBounds.contains(x, y));
596 SkASSERT(fMask->fBounds.contains(x + count - 1, y));
597
598 size_t size = fMask->computeImageSize();
reed@google.com79891862011-10-18 15:44:57 +0000599 const uint8_t* alpha = fMask->getAddr8(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000600 const uint8_t* mulp = alpha + size;
601 const uint8_t* addp = mulp + size;
602
reed@google.com82065d62011-02-07 15:30:46 +0000603 if (fProxy) {
604 for (int i = 0; i < count; i++) {
605 if (alpha[i]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000606 SkPMColor c = span[i];
reed@google.com82065d62011-02-07 15:30:46 +0000607 if (c) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000608 unsigned a = SkGetPackedA32(c);
609 unsigned r = SkGetPackedR32(c);
610 unsigned g = SkGetPackedG32(c);
611 unsigned b = SkGetPackedB32(c);
612
613 unsigned mul = SkAlpha255To256(mulp[i]);
614 unsigned add = addp[i];
615
616 r = SkFastMin32(SkAlphaMul(r, mul) + add, a);
617 g = SkFastMin32(SkAlphaMul(g, mul) + add, a);
618 b = SkFastMin32(SkAlphaMul(b, mul) + add, a);
619
620 span[i] = SkPackARGB32(a, r, g, b);
621 }
reed@google.com82065d62011-02-07 15:30:46 +0000622 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000623 span[i] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000624 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 }
reed@google.com82065d62011-02-07 15:30:46 +0000626 } else { // color
reed@android.com8a1c16f2008-12-17 15:59:43 +0000627 unsigned a = SkGetPackedA32(fPMColor);
628 unsigned r = SkGetPackedR32(fPMColor);
629 unsigned g = SkGetPackedG32(fPMColor);
630 unsigned b = SkGetPackedB32(fPMColor);
reed@google.com82065d62011-02-07 15:30:46 +0000631 for (int i = 0; i < count; i++) {
632 if (alpha[i]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000633 unsigned mul = SkAlpha255To256(mulp[i]);
634 unsigned add = addp[i];
635
636 span[i] = SkPackARGB32( a,
reed@google.com82065d62011-02-07 15:30:46 +0000637 SkFastMin32(SkAlphaMul(r, mul) + add, a),
638 SkFastMin32(SkAlphaMul(g, mul) + add, a),
639 SkFastMin32(SkAlphaMul(b, mul) + add, a));
640 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641 span[i] = 0;
reed@google.com82065d62011-02-07 15:30:46 +0000642 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643 }
644 }
645 }
reed@google.com82065d62011-02-07 15:30:46 +0000646
647 virtual void beginSession() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000648 this->INHERITED::beginSession();
reed@google.com82065d62011-02-07 15:30:46 +0000649 if (fProxy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000650 fProxy->beginSession();
reed@google.com82065d62011-02-07 15:30:46 +0000651 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000652 }
reed@google.com82065d62011-02-07 15:30:46 +0000653
654 virtual void endSession() {
655 if (fProxy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000656 fProxy->endSession();
reed@google.com82065d62011-02-07 15:30:46 +0000657 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000658 this->INHERITED::endSession();
659 }
660
661protected:
662 Sk3DShader(SkFlattenableReadBuffer& buffer) :
reed@google.com82065d62011-02-07 15:30:46 +0000663 INHERITED(buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664 fProxy = static_cast<SkShader*>(buffer.readFlattenable());
665 fPMColor = buffer.readU32();
666 fMask = NULL;
667 }
reed@google.com82065d62011-02-07 15:30:46 +0000668
669 virtual void flatten(SkFlattenableWriteBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000670 this->INHERITED::flatten(buffer);
671 buffer.writeFlattenable(fProxy);
672 buffer.write32(fPMColor);
673 }
reed@google.com82065d62011-02-07 15:30:46 +0000674
675 virtual Factory getFactory() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676 return CreateProc;
677 }
678
679private:
reed@google.com82065d62011-02-07 15:30:46 +0000680 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000681 return SkNEW_ARGS(Sk3DShader, (buffer));
682 }
683
684 SkShader* fProxy;
685 SkPMColor fPMColor;
686 const SkMask* fMask;
687
688 typedef SkShader INHERITED;
689};
690
691class Sk3DBlitter : public SkBlitter {
692public:
693 Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader, void (*killProc)(void*))
reed@google.com82065d62011-02-07 15:30:46 +0000694 : fProxy(proxy), f3DShader(shader), fKillProc(killProc) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000695 shader->ref();
696 }
reed@google.com82065d62011-02-07 15:30:46 +0000697
698 virtual ~Sk3DBlitter() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 f3DShader->unref();
700 fKillProc(fProxy);
701 }
702
reed@google.com82065d62011-02-07 15:30:46 +0000703 virtual void blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704 fProxy->blitH(x, y, width);
705 }
reed@google.com82065d62011-02-07 15:30:46 +0000706
707 virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
708 const int16_t runs[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709 fProxy->blitAntiH(x, y, antialias, runs);
710 }
reed@google.com82065d62011-02-07 15:30:46 +0000711
712 virtual void blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 fProxy->blitV(x, y, height, alpha);
714 }
reed@google.com82065d62011-02-07 15:30:46 +0000715
716 virtual void blitRect(int x, int y, int width, int height) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717 fProxy->blitRect(x, y, width, height);
718 }
reed@google.com82065d62011-02-07 15:30:46 +0000719
720 virtual void blitMask(const SkMask& mask, const SkIRect& clip) {
721 if (mask.fFormat == SkMask::k3D_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000722 f3DShader->setMask(&mask);
723
724 ((SkMask*)&mask)->fFormat = SkMask::kA8_Format;
725 fProxy->blitMask(mask, clip);
726 ((SkMask*)&mask)->fFormat = SkMask::k3D_Format;
727
728 f3DShader->setMask(NULL);
reed@google.com82065d62011-02-07 15:30:46 +0000729 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000730 fProxy->blitMask(mask, clip);
reed@google.com82065d62011-02-07 15:30:46 +0000731 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000732 }
reed@google.com82065d62011-02-07 15:30:46 +0000733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734private:
735 SkBlitter* fProxy;
736 Sk3DShader* f3DShader;
737 void (*fKillProc)(void*);
738};
739
reed@google.com82065d62011-02-07 15:30:46 +0000740///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000741
742#include "SkCoreBlitters.h"
743
reed@android.com8a1c16f2008-12-17 15:59:43 +0000744class SkAutoCallProc {
745public:
746 typedef void (*Proc)(void*);
reed@google.com82065d62011-02-07 15:30:46 +0000747
reed@android.com8a1c16f2008-12-17 15:59:43 +0000748 SkAutoCallProc(void* obj, Proc proc)
reed@google.com82065d62011-02-07 15:30:46 +0000749 : fObj(obj), fProc(proc) {}
750
751 ~SkAutoCallProc() {
752 if (fObj && fProc) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000753 fProc(fObj);
reed@google.com82065d62011-02-07 15:30:46 +0000754 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000755 }
reed@google.com82065d62011-02-07 15:30:46 +0000756
reed@android.com8a1c16f2008-12-17 15:59:43 +0000757 void* get() const { return fObj; }
reed@google.com82065d62011-02-07 15:30:46 +0000758
759 void* detach() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 void* obj = fObj;
761 fObj = NULL;
762 return obj;
763 }
reed@google.com82065d62011-02-07 15:30:46 +0000764
reed@android.com8a1c16f2008-12-17 15:59:43 +0000765private:
766 void* fObj;
767 Proc fProc;
768};
769
reed@google.com82065d62011-02-07 15:30:46 +0000770static void destroy_blitter(void* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000771 ((SkBlitter*)blitter)->~SkBlitter();
772}
773
reed@google.com82065d62011-02-07 15:30:46 +0000774static void delete_blitter(void* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000775 SkDELETE((SkBlitter*)blitter);
776}
777
reed@android.comd252db02009-04-01 18:31:44 +0000778static bool just_solid_color(const SkPaint& paint) {
779 if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
780 SkShader* shader = paint.getShader();
781 if (NULL == shader ||
782 (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
783 return true;
784 }
785 }
786 return false;
787}
reed@google.com82065d62011-02-07 15:30:46 +0000788
reed@android.comd252db02009-04-01 18:31:44 +0000789/** By analyzing the paint (with an xfermode), we may decide we can take
790 special action. This enum lists our possible actions
791 */
792enum XferInterp {
793 kNormal_XferInterp, // no special interpretation, draw normally
794 kSrcOver_XferInterp, // draw as if in srcover mode
795 kSkipDrawing_XferInterp // draw nothing
796};
797
798static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
799 SkBitmap::Config deviceConfig) {
reed@android.com845fdac2009-06-23 03:01:32 +0000800 SkXfermode::Mode mode;
reed@google.com82065d62011-02-07 15:30:46 +0000801
mike@reedtribe.orgbe2aa2a2011-11-17 02:32:04 +0000802 if (SkXfermode::AsMode(xfer, &mode)) {
reed@android.comd252db02009-04-01 18:31:44 +0000803 switch (mode) {
reed@android.com845fdac2009-06-23 03:01:32 +0000804 case SkXfermode::kSrc_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000805 if (just_solid_color(paint)) {
806 return kSrcOver_XferInterp;
807 }
808 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000809 case SkXfermode::kDst_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000810 return kSkipDrawing_XferInterp;
reed@android.com845fdac2009-06-23 03:01:32 +0000811 case SkXfermode::kSrcOver_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000812 return kSrcOver_XferInterp;
reed@android.com845fdac2009-06-23 03:01:32 +0000813 case SkXfermode::kDstOver_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000814 if (SkBitmap::kRGB_565_Config == deviceConfig) {
815 return kSkipDrawing_XferInterp;
816 }
817 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000818 case SkXfermode::kSrcIn_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000819 if (SkBitmap::kRGB_565_Config == deviceConfig &&
820 just_solid_color(paint)) {
821 return kSrcOver_XferInterp;
822 }
823 break;
reed@android.com845fdac2009-06-23 03:01:32 +0000824 case SkXfermode::kDstIn_Mode:
reed@android.comd252db02009-04-01 18:31:44 +0000825 if (just_solid_color(paint)) {
826 return kSkipDrawing_XferInterp;
827 }
828 break;
829 default:
830 break;
831 }
832 }
833 return kNormal_XferInterp;
834}
835
reed@android.com8a1c16f2008-12-17 15:59:43 +0000836SkBlitter* SkBlitter::Choose(const SkBitmap& device,
837 const SkMatrix& matrix,
reed@google.com6b7aee32011-04-19 18:36:09 +0000838 const SkPaint& origPaint,
reed@google.com82065d62011-02-07 15:30:46 +0000839 void* storage, size_t storageSize) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000840 SkASSERT(storageSize == 0 || storage != NULL);
841
842 SkBlitter* blitter = NULL;
843
844 // which check, in case we're being called by a client with a dummy device
845 // (e.g. they have a bounder that always aborts the draw)
reed@google.com82065d62011-02-07 15:30:46 +0000846 if (SkBitmap::kNo_Config == device.getConfig()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
848 return blitter;
849 }
850
reed@google.com6b7aee32011-04-19 18:36:09 +0000851 SkPaint paint(origPaint);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000852 SkShader* shader = paint.getShader();
reed@google.com6b7aee32011-04-19 18:36:09 +0000853 SkColorFilter* cf = paint.getColorFilter();
854 SkXfermode* mode = paint.getXfermode();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000855
856 Sk3DShader* shader3D = NULL;
reed@google.com82065d62011-02-07 15:30:46 +0000857 if (paint.getMaskFilter() != NULL &&
858 paint.getMaskFilter()->getFormat() == SkMask::k3D_Format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 shader3D = SkNEW_ARGS(Sk3DShader, (shader));
reed@google.com6b7aee32011-04-19 18:36:09 +0000860 paint.setShader(shader3D)->unref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000861 shader = shader3D;
862 }
863
reed@android.comd252db02009-04-01 18:31:44 +0000864 if (NULL != mode) {
865 switch (interpret_xfermode(paint, mode, device.config())) {
866 case kSrcOver_XferInterp:
867 mode = NULL;
reed@google.com6b7aee32011-04-19 18:36:09 +0000868 paint.setXfermode(NULL);
reed@android.comd252db02009-04-01 18:31:44 +0000869 break;
870 case kSkipDrawing_XferInterp:
871 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
872 return blitter;
873 default:
874 break;
875 }
876 }
877
reed@google.com6b7aee32011-04-19 18:36:09 +0000878 if (NULL == shader) {
879#ifdef SK_IGNORE_CF_OPTIMIZATION
880 if (mode || cf) {
881#else
882 if (mode) {
883#endif
884 // xfermodes (and filters) require shaders for our current blitters
885 shader = SkNEW(SkColorShader);
886 paint.setShader(shader)->unref();
887 } else if (cf) {
888 // if no shader && no xfermode, we just apply the colorfilter to
889 // our color and move on.
890 paint.setColor(cf->filterColor(paint.getColor()));
891 paint.setColorFilter(NULL);
892 cf = NULL;
893 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000894 }
reed@google.com82065d62011-02-07 15:30:46 +0000895
reed@google.com6b7aee32011-04-19 18:36:09 +0000896 if (cf) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897 SkASSERT(shader);
reed@google.com6b7aee32011-04-19 18:36:09 +0000898 shader = SkNEW_ARGS(SkFilterShader, (shader, cf));
899 paint.setShader(shader)->unref();
reed@android.com1fc4c602009-10-02 16:34:57 +0000900 // blitters should ignore the presence/absence of a filter, since
901 // if there is one, the shader will take care of it.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000902 }
reed@google.com82065d62011-02-07 15:30:46 +0000903
reed@android.comcafc9f92009-08-22 03:44:57 +0000904 if (shader && !shader->setContext(device, paint, matrix)) {
905 return SkNEW(SkNullBlitter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000906 }
907
908 switch (device.getConfig()) {
reed@google.com82065d62011-02-07 15:30:46 +0000909 case SkBitmap::kA1_Config:
910 SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter,
911 storage, storageSize, (device, paint));
912 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913
reed@google.com82065d62011-02-07 15:30:46 +0000914 case SkBitmap::kA8_Config:
915 if (shader) {
916 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter,
917 storage, storageSize, (device, paint));
918 } else {
919 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Blitter,
920 storage, storageSize, (device, paint));
921 }
922 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923
reed@google.com82065d62011-02-07 15:30:46 +0000924 case SkBitmap::kARGB_4444_Config:
925 blitter = SkBlitter_ChooseD4444(device, paint, storage, storageSize);
926 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000927
reed@google.com82065d62011-02-07 15:30:46 +0000928 case SkBitmap::kRGB_565_Config:
929 blitter = SkBlitter_ChooseD565(device, paint, storage, storageSize);
930 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000931
reed@google.com82065d62011-02-07 15:30:46 +0000932 case SkBitmap::kARGB_8888_Config:
933 if (shader) {
934 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Shader_Blitter,
935 storage, storageSize, (device, paint));
936 } else if (paint.getColor() == SK_ColorBLACK) {
937 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Black_Blitter,
938 storage, storageSize, (device, paint));
939 } else if (paint.getAlpha() == 0xFF) {
940 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Opaque_Blitter,
941 storage, storageSize, (device, paint));
942 } else {
943 SK_PLACEMENT_NEW_ARGS(blitter, SkARGB32_Blitter,
944 storage, storageSize, (device, paint));
945 }
946 break;
947
948 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000949 SkDEBUGFAIL("unsupported device config");
reed@google.com82065d62011-02-07 15:30:46 +0000950 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
951 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952 }
953
reed@google.com82065d62011-02-07 15:30:46 +0000954 if (shader3D) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000955 void (*proc)(void*) = ((void*)storage == (void*)blitter) ? destroy_blitter : delete_blitter;
956 SkAutoCallProc tmp(blitter, proc);
957
958 blitter = SkNEW_ARGS(Sk3DBlitter, (blitter, shader3D, proc));
959 (void)tmp.detach();
960 }
961 return blitter;
962}
963
reed@google.com82065d62011-02-07 15:30:46 +0000964///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965
966const uint16_t gMask_0F0F = 0xF0F;
967const uint32_t gMask_00FF00FF = 0xFF00FF;
968
reed@google.com82065d62011-02-07 15:30:46 +0000969///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970
971SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
reed@android.com5119bdb2009-06-12 21:27:03 +0000972 : INHERITED(device) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000973 fShader = paint.getShader();
974 SkASSERT(fShader);
975
976 fShader->ref();
977 fShader->beginSession();
reed@android.com5119bdb2009-06-12 21:27:03 +0000978 fShaderFlags = fShader->getFlags();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979}
980
reed@android.com5119bdb2009-06-12 21:27:03 +0000981SkShaderBlitter::~SkShaderBlitter() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000982 fShader->endSession();
983 fShader->unref();
984}
985