1 :
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 :
9 :
10 : #include "SkDraw.h"
11 : #include "SkBlitter.h"
12 : #include "SkBounder.h"
13 : #include "SkCanvas.h"
14 : #include "SkColorPriv.h"
15 : #include "SkDevice.h"
16 : #include "SkMaskFilter.h"
17 : #include "SkPaint.h"
18 : #include "SkPathEffect.h"
19 : #include "SkRasterClip.h"
20 : #include "SkRasterizer.h"
21 : #include "SkScan.h"
22 : #include "SkShader.h"
23 : #include "SkStroke.h"
24 : #include "SkTemplatesPriv.h"
25 : #include "SkTLazy.h"
26 : #include "SkUtils.h"
27 :
28 : #include "SkAutoKern.h"
29 : #include "SkBitmapProcShader.h"
30 : #include "SkDrawProcs.h"
31 :
32 : //#define TRACE_BITMAP_DRAWS
33 :
34 : #define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2)
35 :
36 : /** Helper for allocating small blitters on the stack.
37 : */
38 : class SkAutoBlitterChoose : SkNoncopyable {
39 : public:
40 0 : SkAutoBlitterChoose() {
41 0 : fBlitter = NULL;
42 0 : }
43 0 : SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
44 0 : const SkPaint& paint) {
45 : fBlitter = SkBlitter::Choose(device, matrix, paint,
46 0 : fStorage, sizeof(fStorage));
47 0 : }
48 :
49 : ~SkAutoBlitterChoose();
50 :
51 : SkBlitter* operator->() { return fBlitter; }
52 0 : SkBlitter* get() const { return fBlitter; }
53 :
54 0 : void choose(const SkBitmap& device, const SkMatrix& matrix,
55 : const SkPaint& paint) {
56 0 : SkASSERT(!fBlitter);
57 : fBlitter = SkBlitter::Choose(device, matrix, paint,
58 0 : fStorage, sizeof(fStorage));
59 0 : }
60 :
61 : private:
62 : SkBlitter* fBlitter;
63 : uint32_t fStorage[kBlitterStorageLongCount];
64 : };
65 :
66 0 : SkAutoBlitterChoose::~SkAutoBlitterChoose() {
67 0 : if ((void*)fBlitter == (void*)fStorage) {
68 0 : fBlitter->~SkBlitter();
69 : } else {
70 0 : SkDELETE(fBlitter);
71 : }
72 0 : }
73 :
74 : /**
75 : * Since we are providing the storage for the shader (to avoid the perf cost
76 : * of calling new) we insist that in our destructor we can account for all
77 : * owners of the shader.
78 : */
79 : class SkAutoBitmapShaderInstall : SkNoncopyable {
80 : public:
81 0 : SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint)
82 0 : : fPaint(paint) /* makes a copy of the paint */ {
83 : fPaint.setShader(SkShader::CreateBitmapShader(src,
84 : SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
85 0 : fStorage, sizeof(fStorage)));
86 : // we deliberately left the shader with an owner-count of 2
87 0 : SkASSERT(2 == fPaint.getShader()->getRefCnt());
88 0 : }
89 :
90 0 : ~SkAutoBitmapShaderInstall() {
91 0 : SkShader* shader = fPaint.getShader();
92 : // since we manually destroy shader, we insist that owners == 2
93 0 : SkASSERT(2 == shader->getRefCnt());
94 :
95 0 : fPaint.setShader(NULL); // unref the shader by 1
96 :
97 : // now destroy to take care of the 2nd owner-count
98 0 : if ((void*)shader == (void*)fStorage) {
99 0 : shader->~SkShader();
100 : } else {
101 0 : SkDELETE(shader);
102 : }
103 0 : }
104 :
105 : // return the new paint that has the shader applied
106 0 : const SkPaint& paintWithShader() const { return fPaint; }
107 :
108 : private:
109 : SkPaint fPaint; // copy of caller's paint (which we then modify)
110 : uint32_t fStorage[kBlitterStorageLongCount];
111 : };
112 :
113 : ///////////////////////////////////////////////////////////////////////////////
114 :
115 0 : SkDraw::SkDraw() {
116 0 : sk_bzero(this, sizeof(*this));
117 0 : }
118 :
119 0 : SkDraw::SkDraw(const SkDraw& src) {
120 0 : memcpy(this, &src, sizeof(*this));
121 0 : }
122 :
123 : ///////////////////////////////////////////////////////////////////////////////
124 :
125 : typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
126 :
127 0 : static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
128 0 : sk_bzero(pixels, bytes);
129 0 : }
130 :
131 0 : static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
132 :
133 0 : static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
134 0 : sk_memset32((uint32_t*)pixels, data, bytes >> 2);
135 0 : }
136 :
137 0 : static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
138 0 : sk_memset16((uint16_t*)pixels, data, bytes >> 1);
139 0 : }
140 :
141 0 : static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
142 0 : memset(pixels, data, bytes);
143 0 : }
144 :
145 0 : static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap,
146 : const SkPaint& paint,
147 : uint32_t* data) {
148 : // todo: we can apply colorfilter up front if no shader, so we wouldn't
149 : // need to abort this fastpath
150 0 : if (paint.getShader() || paint.getColorFilter()) {
151 0 : return NULL;
152 : }
153 :
154 : SkXfermode::Mode mode;
155 0 : if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
156 0 : return NULL;
157 : }
158 :
159 0 : SkColor color = paint.getColor();
160 :
161 : // collaps modes based on color...
162 0 : if (SkXfermode::kSrcOver_Mode == mode) {
163 0 : unsigned alpha = SkColorGetA(color);
164 0 : if (0 == alpha) {
165 0 : mode = SkXfermode::kDst_Mode;
166 0 : } else if (0xFF == alpha) {
167 0 : mode = SkXfermode::kSrc_Mode;
168 : }
169 : }
170 :
171 0 : switch (mode) {
172 : case SkXfermode::kClear_Mode:
173 : // SkDebugf("--- D_Clear_BitmapXferProc\n");
174 0 : return D_Clear_BitmapXferProc; // ignore data
175 : case SkXfermode::kDst_Mode:
176 : // SkDebugf("--- D_Dst_BitmapXferProc\n");
177 0 : return D_Dst_BitmapXferProc; // ignore data
178 : case SkXfermode::kSrc_Mode: {
179 : /*
180 : should I worry about dithering for the lower depths?
181 : */
182 0 : SkPMColor pmc = SkPreMultiplyColor(color);
183 0 : switch (bitmap.config()) {
184 : case SkBitmap::kARGB_8888_Config:
185 0 : if (data) {
186 0 : *data = pmc;
187 : }
188 : // SkDebugf("--- D32_Src_BitmapXferProc\n");
189 0 : return D32_Src_BitmapXferProc;
190 : case SkBitmap::kARGB_4444_Config:
191 0 : if (data) {
192 0 : *data = SkPixel32ToPixel4444(pmc);
193 : }
194 : // SkDebugf("--- D16_Src_BitmapXferProc\n");
195 0 : return D16_Src_BitmapXferProc;
196 : case SkBitmap::kRGB_565_Config:
197 0 : if (data) {
198 0 : *data = SkPixel32ToPixel16(pmc);
199 : }
200 : // SkDebugf("--- D16_Src_BitmapXferProc\n");
201 0 : return D16_Src_BitmapXferProc;
202 : case SkBitmap::kA8_Config:
203 0 : if (data) {
204 0 : *data = SkGetPackedA32(pmc);
205 : }
206 : // SkDebugf("--- DA8_Src_BitmapXferProc\n");
207 0 : return DA8_Src_BitmapXferProc;
208 : default:
209 : break;
210 : }
211 0 : break;
212 : }
213 : default:
214 0 : break;
215 : }
216 0 : return NULL;
217 : }
218 :
219 0 : static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
220 : BitmapXferProc proc, uint32_t procData) {
221 : int shiftPerPixel;
222 0 : switch (bitmap.config()) {
223 : case SkBitmap::kARGB_8888_Config:
224 0 : shiftPerPixel = 2;
225 0 : break;
226 : case SkBitmap::kARGB_4444_Config:
227 : case SkBitmap::kRGB_565_Config:
228 0 : shiftPerPixel = 1;
229 0 : break;
230 : case SkBitmap::kA8_Config:
231 0 : shiftPerPixel = 0;
232 0 : break;
233 : default:
234 0 : SkDEBUGFAIL("Can't use xferproc on this config");
235 0 : return;
236 : }
237 :
238 0 : uint8_t* pixels = (uint8_t*)bitmap.getPixels();
239 0 : SkASSERT(pixels);
240 0 : const size_t rowBytes = bitmap.rowBytes();
241 0 : const int widthBytes = rect.width() << shiftPerPixel;
242 :
243 : // skip down to the first scanline and X position
244 0 : pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
245 0 : for (int scans = rect.height() - 1; scans >= 0; --scans) {
246 0 : proc(pixels, widthBytes, procData);
247 0 : pixels += rowBytes;
248 : }
249 : }
250 :
251 0 : void SkDraw::drawPaint(const SkPaint& paint) const {
252 0 : SkDEBUGCODE(this->validate();)
253 :
254 0 : if (fRC->isEmpty()) {
255 0 : return;
256 : }
257 :
258 : SkIRect devRect;
259 0 : devRect.set(0, 0, fBitmap->width(), fBitmap->height());
260 0 : if (fBounder && !fBounder->doIRect(devRect)) {
261 0 : return;
262 : }
263 :
264 0 : if (fRC->isBW()) {
265 : /* If we don't have a shader (i.e. we're just a solid color) we may
266 : be faster to operate directly on the device bitmap, rather than invoking
267 : a blitter. Esp. true for xfermodes, which require a colorshader to be
268 : present, which is just redundant work. Since we're drawing everywhere
269 : in the clip, we don't have to worry about antialiasing.
270 : */
271 0 : uint32_t procData = 0; // to avoid the warning
272 0 : BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
273 0 : if (proc) {
274 0 : if (D_Dst_BitmapXferProc == proc) { // nothing to do
275 0 : return;
276 : }
277 :
278 0 : SkRegion::Iterator iter(fRC->bwRgn());
279 0 : while (!iter.done()) {
280 0 : CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
281 0 : iter.next();
282 : }
283 0 : return;
284 : }
285 : }
286 :
287 : // normal case: use a blitter
288 0 : SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
289 0 : SkScan::FillIRect(devRect, *fRC, blitter.get());
290 : }
291 :
292 : ///////////////////////////////////////////////////////////////////////////////
293 :
294 0 : struct PtProcRec {
295 : SkCanvas::PointMode fMode;
296 : const SkPaint* fPaint;
297 : const SkRegion* fClip;
298 : const SkRasterClip* fRC;
299 :
300 : // computed values
301 : SkFixed fRadius;
302 :
303 : typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
304 : SkBlitter*);
305 :
306 : bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
307 : const SkRasterClip*);
308 : Proc chooseProc(SkBlitter** blitter);
309 :
310 : private:
311 : SkAAClipBlitterWrapper fWrapper;
312 : };
313 :
314 0 : static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
315 : int count, SkBlitter* blitter) {
316 0 : SkASSERT(rec.fClip->isRect());
317 0 : const SkIRect& r = rec.fClip->getBounds();
318 :
319 0 : for (int i = 0; i < count; i++) {
320 0 : int x = SkScalarFloor(devPts[i].fX);
321 0 : int y = SkScalarFloor(devPts[i].fY);
322 0 : if (r.contains(x, y)) {
323 0 : blitter->blitH(x, y, 1);
324 : }
325 : }
326 0 : }
327 :
328 0 : static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
329 : const SkPoint devPts[], int count,
330 : SkBlitter* blitter) {
331 0 : SkASSERT(rec.fRC->isRect());
332 0 : const SkIRect& r = rec.fRC->getBounds();
333 : uint32_t value;
334 0 : const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
335 0 : SkASSERT(bitmap);
336 :
337 0 : uint16_t* addr = bitmap->getAddr16(0, 0);
338 0 : int rb = bitmap->rowBytes();
339 :
340 0 : for (int i = 0; i < count; i++) {
341 0 : int x = SkScalarFloor(devPts[i].fX);
342 0 : int y = SkScalarFloor(devPts[i].fY);
343 0 : if (r.contains(x, y)) {
344 : // *bitmap->getAddr16(x, y) = SkToU16(value);
345 0 : ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
346 : }
347 : }
348 0 : }
349 :
350 0 : static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
351 : int count, SkBlitter* blitter) {
352 0 : for (int i = 0; i < count; i++) {
353 0 : int x = SkScalarFloor(devPts[i].fX);
354 0 : int y = SkScalarFloor(devPts[i].fY);
355 0 : if (rec.fClip->contains(x, y)) {
356 0 : blitter->blitH(x, y, 1);
357 : }
358 : }
359 0 : }
360 :
361 0 : static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
362 : int count, SkBlitter* blitter) {
363 0 : for (int i = 0; i < count; i += 2) {
364 0 : SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
365 : }
366 0 : }
367 :
368 0 : static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
369 : int count, SkBlitter* blitter) {
370 0 : for (int i = 0; i < count - 1; i++) {
371 0 : SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
372 : }
373 0 : }
374 :
375 : // aa versions
376 :
377 0 : static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
378 : int count, SkBlitter* blitter) {
379 0 : for (int i = 0; i < count; i += 2) {
380 0 : SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
381 : }
382 0 : }
383 :
384 0 : static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
385 : int count, SkBlitter* blitter) {
386 0 : for (int i = 0; i < count - 1; i++) {
387 0 : SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
388 : }
389 0 : }
390 :
391 : // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
392 :
393 0 : static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
394 : int count, SkBlitter* blitter) {
395 0 : const SkFixed radius = rec.fRadius;
396 0 : for (int i = 0; i < count; i++) {
397 0 : SkFixed x = SkScalarToFixed(devPts[i].fX);
398 0 : SkFixed y = SkScalarToFixed(devPts[i].fY);
399 :
400 : SkXRect r;
401 0 : r.fLeft = x - radius;
402 0 : r.fTop = y - radius;
403 0 : r.fRight = x + radius;
404 0 : r.fBottom = y + radius;
405 :
406 0 : SkScan::FillXRect(r, *rec.fRC, blitter);
407 : }
408 0 : }
409 :
410 0 : static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
411 : int count, SkBlitter* blitter) {
412 0 : const SkFixed radius = rec.fRadius;
413 0 : for (int i = 0; i < count; i++) {
414 0 : SkFixed x = SkScalarToFixed(devPts[i].fX);
415 0 : SkFixed y = SkScalarToFixed(devPts[i].fY);
416 :
417 : SkXRect r;
418 0 : r.fLeft = x - radius;
419 0 : r.fTop = y - radius;
420 0 : r.fRight = x + radius;
421 0 : r.fBottom = y + radius;
422 :
423 0 : SkScan::AntiFillXRect(r, *rec.fRC, blitter);
424 : }
425 0 : }
426 :
427 : // If this guy returns true, then chooseProc() must return a valid proc
428 0 : bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
429 : const SkMatrix* matrix, const SkRasterClip* rc) {
430 0 : if (paint.getPathEffect()) {
431 0 : return false;
432 : }
433 0 : SkScalar width = paint.getStrokeWidth();
434 0 : if (0 == width) {
435 0 : fMode = mode;
436 0 : fPaint = &paint;
437 0 : fClip = NULL;
438 0 : fRC = rc;
439 0 : fRadius = SK_Fixed1 >> 1;
440 0 : return true;
441 : }
442 0 : if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
443 0 : matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) {
444 0 : SkScalar sx = matrix->get(SkMatrix::kMScaleX);
445 0 : SkScalar sy = matrix->get(SkMatrix::kMScaleY);
446 0 : if (SkScalarNearlyZero(sx - sy)) {
447 0 : if (sx < 0) {
448 0 : sx = -sx;
449 : }
450 :
451 0 : fMode = mode;
452 0 : fPaint = &paint;
453 0 : fClip = NULL;
454 0 : fRC = rc;
455 0 : fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
456 0 : return true;
457 : }
458 : }
459 0 : return false;
460 : }
461 :
462 0 : PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
463 0 : Proc proc = NULL;
464 :
465 0 : SkBlitter* blitter = *blitterPtr;
466 0 : if (fRC->isBW()) {
467 0 : fClip = &fRC->bwRgn();
468 : } else {
469 0 : fWrapper.init(*fRC, blitter);
470 0 : fClip = &fWrapper.getRgn();
471 0 : blitter = fWrapper.getBlitter();
472 0 : *blitterPtr = blitter;
473 : }
474 :
475 : // for our arrays
476 : SkASSERT(0 == SkCanvas::kPoints_PointMode);
477 : SkASSERT(1 == SkCanvas::kLines_PointMode);
478 : SkASSERT(2 == SkCanvas::kPolygon_PointMode);
479 0 : SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
480 :
481 : // first check for hairlines
482 0 : if (0 == fPaint->getStrokeWidth()) {
483 0 : if (fPaint->isAntiAlias()) {
484 : static const Proc gAAProcs[] = {
485 : aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
486 : };
487 0 : proc = gAAProcs[fMode];
488 : } else {
489 0 : if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
490 : uint32_t value;
491 0 : const SkBitmap* bm = blitter->justAnOpaqueColor(&value);
492 0 : if (bm && bm->config() == SkBitmap::kRGB_565_Config) {
493 0 : proc = bw_pt_rect_16_hair_proc;
494 : } else {
495 0 : proc = bw_pt_rect_hair_proc;
496 : }
497 : } else {
498 : static Proc gBWProcs[] = {
499 : bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
500 : };
501 0 : proc = gBWProcs[fMode];
502 : }
503 : }
504 0 : } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
505 0 : SkASSERT(SkCanvas::kPoints_PointMode == fMode);
506 0 : if (fPaint->isAntiAlias()) {
507 0 : proc = aa_square_proc;
508 : } else {
509 0 : proc = bw_square_proc;
510 : }
511 : }
512 0 : return proc;
513 : }
514 :
515 0 : static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode,
516 : size_t count, const SkPoint pts[],
517 : const SkPaint& paint, const SkMatrix& matrix) {
518 : SkIRect ibounds;
519 : SkRect bounds;
520 0 : SkScalar inset = paint.getStrokeWidth();
521 :
522 0 : bounds.set(pts, count);
523 0 : bounds.inset(-inset, -inset);
524 0 : matrix.mapRect(&bounds);
525 :
526 0 : bounds.roundOut(&ibounds);
527 0 : return bounder->doIRect(ibounds);
528 : }
529 :
530 : // each of these costs 8-bytes of stack space, so don't make it too large
531 : // must be even for lines/polygon to work
532 : #define MAX_DEV_PTS 32
533 :
534 0 : void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
535 : const SkPoint pts[], const SkPaint& paint,
536 : bool forceUseDevice) const {
537 : // if we're in lines mode, force count to be even
538 0 : if (SkCanvas::kLines_PointMode == mode) {
539 0 : count &= ~(size_t)1;
540 : }
541 :
542 0 : if ((long)count <= 0) {
543 0 : return;
544 : }
545 :
546 0 : SkASSERT(pts != NULL);
547 0 : SkDEBUGCODE(this->validate();)
548 :
549 : // nothing to draw
550 0 : if (fRC->isEmpty()) {
551 0 : return;
552 : }
553 :
554 0 : if (fBounder) {
555 0 : if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) {
556 0 : return;
557 : }
558 :
559 : // clear the bounder and call this again, so we don't invoke the bounder
560 : // later if we happen to call ourselves for drawRect, drawPath, etc.
561 0 : SkDraw noBounder(*this);
562 0 : noBounder.fBounder = NULL;
563 0 : noBounder.drawPoints(mode, count, pts, paint, forceUseDevice);
564 0 : return;
565 : }
566 :
567 0 : PtProcRec rec;
568 0 : if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
569 0 : SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
570 :
571 : SkPoint devPts[MAX_DEV_PTS];
572 0 : const SkMatrix* matrix = fMatrix;
573 0 : SkBlitter* bltr = blitter.get();
574 0 : PtProcRec::Proc proc = rec.chooseProc(&bltr);
575 : // we have to back up subsequent passes if we're in polygon mode
576 0 : const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
577 :
578 0 : do {
579 0 : size_t n = count;
580 0 : if (n > MAX_DEV_PTS) {
581 0 : n = MAX_DEV_PTS;
582 : }
583 0 : matrix->mapPoints(devPts, pts, n);
584 0 : proc(rec, devPts, n, bltr);
585 0 : pts += n - backup;
586 0 : SkASSERT(count >= n);
587 0 : count -= n;
588 0 : if (count > 0) {
589 0 : count += backup;
590 : }
591 : } while (count != 0);
592 : } else {
593 0 : switch (mode) {
594 : case SkCanvas::kPoints_PointMode: {
595 : // temporarily mark the paint as filling.
596 0 : SkPaint newPaint(paint);
597 0 : newPaint.setStyle(SkPaint::kFill_Style);
598 :
599 0 : SkScalar width = newPaint.getStrokeWidth();
600 0 : SkScalar radius = SkScalarHalf(width);
601 :
602 0 : if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
603 0 : SkPath path;
604 : SkMatrix preMatrix;
605 :
606 0 : path.addCircle(0, 0, radius);
607 0 : for (size_t i = 0; i < count; i++) {
608 0 : preMatrix.setTranslate(pts[i].fX, pts[i].fY);
609 : // pass true for the last point, since we can modify
610 : // then path then
611 0 : if (fDevice) {
612 : fDevice->drawPath(*this, path, newPaint, &preMatrix,
613 0 : (count-1) == i);
614 : } else {
615 : this->drawPath(path, newPaint, &preMatrix,
616 0 : (count-1) == i);
617 : }
618 : }
619 : } else {
620 : SkRect r;
621 :
622 0 : for (size_t i = 0; i < count; i++) {
623 0 : r.fLeft = pts[i].fX - radius;
624 0 : r.fTop = pts[i].fY - radius;
625 0 : r.fRight = r.fLeft + width;
626 0 : r.fBottom = r.fTop + width;
627 0 : if (fDevice) {
628 0 : fDevice->drawRect(*this, r, newPaint);
629 : } else {
630 0 : this->drawRect(r, newPaint);
631 : }
632 : }
633 : }
634 : break;
635 : }
636 : case SkCanvas::kLines_PointMode:
637 : case SkCanvas::kPolygon_PointMode: {
638 0 : count -= 1;
639 0 : SkPath path;
640 0 : SkPaint p(paint);
641 0 : p.setStyle(SkPaint::kStroke_Style);
642 0 : size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
643 0 : for (size_t i = 0; i < count; i += inc) {
644 0 : path.moveTo(pts[i]);
645 0 : path.lineTo(pts[i+1]);
646 0 : if (fDevice) {
647 0 : fDevice->drawPath(*this, path, p, NULL, true);
648 : } else {
649 0 : this->drawPath(path, p, NULL, true);
650 : }
651 0 : path.rewind();
652 : }
653 : break;
654 : }
655 : }
656 : }
657 : }
658 :
659 : static inline SkPoint* as_lefttop(SkRect* r) {
660 : return (SkPoint*)(void*)r;
661 : }
662 :
663 : static inline SkPoint* as_rightbottom(SkRect* r) {
664 : return ((SkPoint*)(void*)r) + 1;
665 : }
666 :
667 0 : static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
668 : SkPoint* strokeSize) {
669 0 : if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
670 0 : paint.getStrokeMiter() < SK_ScalarSqrt2) {
671 0 : return false;
672 : }
673 :
674 0 : SkASSERT(matrix.rectStaysRect());
675 0 : SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
676 0 : matrix.mapVectors(strokeSize, &pt, 1);
677 0 : strokeSize->fX = SkScalarAbs(strokeSize->fX);
678 0 : strokeSize->fY = SkScalarAbs(strokeSize->fY);
679 0 : return true;
680 : }
681 :
682 0 : SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
683 : const SkMatrix& matrix,
684 : SkPoint* strokeSize) {
685 : RectType rtype;
686 0 : const SkScalar width = paint.getStrokeWidth();
687 0 : const bool zeroWidth = (0 == width);
688 0 : SkPaint::Style style = paint.getStyle();
689 :
690 0 : if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
691 0 : style = SkPaint::kFill_Style;
692 : }
693 :
694 0 : if (paint.getPathEffect() || paint.getMaskFilter() ||
695 0 : paint.getRasterizer() || !matrix.rectStaysRect() ||
696 : SkPaint::kStrokeAndFill_Style == style) {
697 0 : rtype = kPath_RectType;
698 0 : } else if (SkPaint::kFill_Style == style) {
699 0 : rtype = kFill_RectType;
700 0 : } else if (zeroWidth) {
701 0 : rtype = kHair_RectType;
702 0 : } else if (easy_rect_join(paint, matrix, strokeSize)) {
703 0 : rtype = kStroke_RectType;
704 : } else {
705 0 : rtype = kPath_RectType;
706 : }
707 0 : return rtype;
708 : }
709 :
710 0 : static SkPoint* rect_points(SkRect& r, int index) {
711 0 : SkASSERT((unsigned)index < 2);
712 0 : return &((SkPoint*)(void*)&r)[index];
713 : }
714 :
715 0 : void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
716 0 : SkDEBUGCODE(this->validate();)
717 :
718 : // nothing to draw
719 0 : if (fRC->isEmpty()) {
720 0 : return;
721 : }
722 :
723 : SkPoint strokeSize;
724 0 : RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
725 :
726 : #ifdef SK_DISABLE_FAST_AA_STROKE_RECT
727 : if (kStroke_RectType == rtype && paint.isAntiAlias()) {
728 : rtype = kPath_RectType;
729 : }
730 : #endif
731 :
732 0 : if (kPath_RectType == rtype) {
733 0 : SkPath tmp;
734 0 : tmp.addRect(rect);
735 0 : tmp.setFillType(SkPath::kWinding_FillType);
736 0 : this->drawPath(tmp, paint, NULL, true);
737 : return;
738 : }
739 :
740 0 : const SkMatrix& matrix = *fMatrix;
741 : SkRect devRect;
742 :
743 : // transform rect into devRect
744 : {
745 0 : matrix.mapXY(rect.fLeft, rect.fTop, rect_points(devRect, 0));
746 0 : matrix.mapXY(rect.fRight, rect.fBottom, rect_points(devRect, 1));
747 0 : devRect.sort();
748 : }
749 :
750 0 : if (fBounder && !fBounder->doRect(devRect, paint)) {
751 0 : return;
752 : }
753 :
754 : // look for the quick exit, before we build a blitter
755 : {
756 : SkIRect ir;
757 0 : devRect.roundOut(&ir);
758 0 : if (paint.getStyle() != SkPaint::kFill_Style) {
759 : // extra space for hairlines
760 0 : ir.inset(-1, -1);
761 : }
762 0 : if (fRC->quickReject(ir))
763 0 : return;
764 : }
765 :
766 0 : SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint);
767 0 : const SkRasterClip& clip = *fRC;
768 0 : SkBlitter* blitter = blitterStorage.get();
769 :
770 : // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
771 : // case we are also hairline (if we've gotten to here), which devolves to
772 : // effectively just kFill
773 0 : switch (rtype) {
774 : case kFill_RectType:
775 0 : if (paint.isAntiAlias()) {
776 0 : SkScan::AntiFillRect(devRect, clip, blitter);
777 : } else {
778 0 : SkScan::FillRect(devRect, clip, blitter);
779 : }
780 0 : break;
781 : case kStroke_RectType:
782 0 : if (paint.isAntiAlias()) {
783 0 : SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
784 : } else {
785 0 : SkScan::FrameRect(devRect, strokeSize, clip, blitter);
786 : }
787 0 : break;
788 : case kHair_RectType:
789 0 : if (paint.isAntiAlias()) {
790 0 : SkScan::AntiHairRect(devRect, clip, blitter);
791 : } else {
792 0 : SkScan::HairRect(devRect, clip, blitter);
793 : }
794 0 : break;
795 : default:
796 0 : SkDEBUGFAIL("bad rtype");
797 : }
798 : }
799 :
800 0 : void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
801 0 : if (srcM.fBounds.isEmpty()) {
802 0 : return;
803 : }
804 :
805 0 : const SkMask* mask = &srcM;
806 :
807 : SkMask dstM;
808 0 : if (paint.getMaskFilter() &&
809 0 : paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) {
810 0 : mask = &dstM;
811 : } else {
812 0 : dstM.fImage = NULL;
813 : }
814 0 : SkAutoMaskFreeImage ami(dstM.fImage);
815 :
816 0 : if (fBounder && !fBounder->doIRect(mask->fBounds)) {
817 : return;
818 : }
819 :
820 0 : SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint);
821 0 : SkBlitter* blitter = blitterChooser.get();
822 :
823 0 : SkAAClipBlitterWrapper wrapper;
824 : const SkRegion* clipRgn;
825 :
826 0 : if (fRC->isBW()) {
827 0 : clipRgn = &fRC->bwRgn();
828 : } else {
829 0 : wrapper.init(*fRC, blitter);
830 0 : clipRgn = &wrapper.getRgn();
831 0 : blitter = wrapper.getBlitter();
832 : }
833 0 : blitter->blitMaskRegion(*mask, *clipRgn);
834 : }
835 :
836 0 : static SkScalar fast_len(const SkVector& vec) {
837 0 : SkScalar x = SkScalarAbs(vec.fX);
838 0 : SkScalar y = SkScalarAbs(vec.fY);
839 0 : if (x < y) {
840 0 : SkTSwap(x, y);
841 : }
842 0 : return x + SkScalarHalf(y);
843 : }
844 :
845 0 : static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) {
846 : SkXfermode::Coeff dc;
847 0 : if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) {
848 0 : return false;
849 : }
850 :
851 0 : switch (dc) {
852 : case SkXfermode::kOne_Coeff:
853 : case SkXfermode::kISA_Coeff:
854 : case SkXfermode::kISC_Coeff:
855 0 : return true;
856 : default:
857 0 : return false;
858 : }
859 : }
860 :
861 0 : bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
862 : SkAlpha* newAlpha) {
863 0 : SkASSERT(newAlpha);
864 0 : if (SkPaint::kStroke_Style != paint.getStyle()) {
865 0 : return false;
866 : }
867 0 : SkScalar strokeWidth = paint.getStrokeWidth();
868 0 : if (0 == strokeWidth) {
869 0 : *newAlpha = paint.getAlpha();
870 0 : return true;
871 : }
872 :
873 : // if we get here, we need to try to fake a thick-stroke with a modulated
874 : // hairline
875 :
876 0 : if (!paint.isAntiAlias()) {
877 0 : return false;
878 : }
879 0 : if (!xfermodeSupportsCoverageAsAlpha(paint.getXfermode())) {
880 0 : return false;
881 : }
882 0 : if (matrix.hasPerspective()) {
883 0 : return false;
884 : }
885 :
886 : SkVector src[2], dst[2];
887 0 : src[0].set(strokeWidth, 0);
888 0 : src[1].set(0, strokeWidth);
889 0 : matrix.mapVectors(dst, src, 2);
890 0 : SkScalar len0 = fast_len(dst[0]);
891 0 : SkScalar len1 = fast_len(dst[1]);
892 0 : if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
893 0 : SkScalar modulate = SkScalarAve(len0, len1);
894 : #if 0
895 : *newAlpha = SkToU8(SkScalarRoundToInt(modulate * paint.getAlpha()));
896 : #else
897 : // this is the old technique, which we preserve for now so we don't
898 : // change previous results (testing)
899 : // the new way seems fine, its just (a tiny bit) different
900 0 : int scale = (int)SkScalarMul(modulate, 256);
901 0 : *newAlpha = paint.getAlpha() * scale >> 8;
902 : #endif
903 0 : return true;
904 : }
905 0 : return false;
906 : }
907 :
908 0 : void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
909 : const SkMatrix* prePathMatrix, bool pathIsMutable) const {
910 0 : SkDEBUGCODE(this->validate();)
911 :
912 : // nothing to draw
913 0 : if (fRC->isEmpty()) {
914 0 : return;
915 : }
916 :
917 0 : SkPath* pathPtr = (SkPath*)&origSrcPath;
918 0 : bool doFill = true;
919 0 : SkPath tmpPath;
920 : SkMatrix tmpMatrix;
921 0 : const SkMatrix* matrix = fMatrix;
922 :
923 0 : if (prePathMatrix) {
924 0 : if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
925 0 : origPaint.getRasterizer()) {
926 0 : SkPath* result = pathPtr;
927 :
928 0 : if (!pathIsMutable) {
929 0 : result = &tmpPath;
930 0 : pathIsMutable = true;
931 : }
932 0 : pathPtr->transform(*prePathMatrix, result);
933 0 : pathPtr = result;
934 : } else {
935 0 : if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) {
936 : // overflow
937 : return;
938 : }
939 0 : matrix = &tmpMatrix;
940 : }
941 : }
942 : // at this point we're done with prePathMatrix
943 0 : SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
944 :
945 0 : const SkPaint* paint = &origPaint;
946 0 : SkTLazy<SkPaint> lazyPaint;
947 :
948 : {
949 : SkAlpha newAlpha;
950 0 : if (SkDrawTreatAsHairline(origPaint, *matrix, &newAlpha)) {
951 0 : lazyPaint.set(origPaint);
952 0 : lazyPaint.get()->setAlpha(newAlpha);
953 0 : lazyPaint.get()->setStrokeWidth(0);
954 0 : paint = lazyPaint.get();
955 : }
956 : }
957 :
958 0 : if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
959 0 : doFill = paint->getFillPath(*pathPtr, &tmpPath);
960 0 : pathPtr = &tmpPath;
961 : }
962 :
963 0 : if (paint->getRasterizer()) {
964 : SkMask mask;
965 0 : if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
966 0 : &fRC->getBounds(), paint->getMaskFilter(), &mask,
967 0 : SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
968 0 : this->drawDevMask(mask, *paint);
969 0 : SkMask::FreeImage(mask.fImage);
970 : }
971 : return;
972 : }
973 :
974 : // avoid possibly allocating a new path in transform if we can
975 0 : SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
976 :
977 : // transform the path into device space
978 0 : pathPtr->transform(*matrix, devPathPtr);
979 :
980 0 : SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint);
981 :
982 : // how does filterPath() know to fill or hairline the path??? <mrr>
983 0 : if (paint->getMaskFilter() &&
984 : paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC,
985 0 : fBounder, blitter.get())) {
986 : return; // filterPath() called the blitter, so we're done
987 : }
988 :
989 0 : if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) {
990 : return;
991 : }
992 :
993 : void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
994 0 : if (doFill) {
995 0 : if (paint->isAntiAlias()) {
996 0 : proc = SkScan::AntiFillPath;
997 : } else {
998 0 : proc = SkScan::FillPath;
999 : }
1000 : } else { // hairline
1001 0 : if (paint->isAntiAlias()) {
1002 0 : proc = SkScan::AntiHairPath;
1003 : } else {
1004 0 : proc = SkScan::HairPath;
1005 : }
1006 : }
1007 0 : proc(*devPathPtr, *fRC, blitter.get());
1008 : }
1009 :
1010 : /** For the purposes of drawing bitmaps, if a matrix is "almost" translate
1011 : go ahead and treat it as if it were, so that subsequent code can go fast.
1012 : */
1013 0 : static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) {
1014 0 : SkMatrix::TypeMask mask = matrix.getType();
1015 :
1016 0 : if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
1017 0 : return false;
1018 : }
1019 0 : if (mask & SkMatrix::kScale_Mask) {
1020 0 : SkScalar sx = matrix[SkMatrix::kMScaleX];
1021 0 : SkScalar sy = matrix[SkMatrix::kMScaleY];
1022 0 : int w = bitmap.width();
1023 0 : int h = bitmap.height();
1024 0 : int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
1025 0 : int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
1026 0 : return sw == w && sh == h;
1027 : }
1028 : // if we got here, we're either kTranslate_Mask or identity
1029 0 : return true;
1030 : }
1031 :
1032 0 : void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
1033 : const SkPaint& paint) const {
1034 0 : SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config);
1035 :
1036 0 : if (just_translate(*fMatrix, bitmap)) {
1037 0 : int ix = SkScalarRound(fMatrix->getTranslateX());
1038 0 : int iy = SkScalarRound(fMatrix->getTranslateY());
1039 :
1040 : SkMask mask;
1041 0 : mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1042 0 : mask.fFormat = SkMask::kA8_Format;
1043 0 : mask.fRowBytes = bitmap.rowBytes();
1044 0 : mask.fImage = bitmap.getAddr8(0, 0);
1045 :
1046 0 : this->drawDevMask(mask, paint);
1047 : } else { // need to xform the bitmap first
1048 : SkRect r;
1049 : SkMask mask;
1050 :
1051 : r.set(0, 0,
1052 0 : SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1053 0 : fMatrix->mapRect(&r);
1054 0 : r.round(&mask.fBounds);
1055 :
1056 : // set the mask's bounds to the transformed bitmap-bounds,
1057 : // clipped to the actual device
1058 : {
1059 : SkIRect devBounds;
1060 0 : devBounds.set(0, 0, fBitmap->width(), fBitmap->height());
1061 : // need intersect(l, t, r, b) on irect
1062 0 : if (!mask.fBounds.intersect(devBounds)) {
1063 0 : return;
1064 : }
1065 : }
1066 :
1067 0 : mask.fFormat = SkMask::kA8_Format;
1068 0 : mask.fRowBytes = SkAlign4(mask.fBounds.width());
1069 0 : size_t size = mask.computeImageSize();
1070 0 : if (0 == size) {
1071 : // the mask is too big to allocated, draw nothing
1072 0 : return;
1073 : }
1074 :
1075 : // allocate (and clear) our temp buffer to hold the transformed bitmap
1076 0 : SkAutoMalloc storage(size);
1077 0 : mask.fImage = (uint8_t*)storage.get();
1078 0 : memset(mask.fImage, 0, size);
1079 :
1080 : // now draw our bitmap(src) into mask(dst), transformed by the matrix
1081 : {
1082 0 : SkBitmap device;
1083 : device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
1084 0 : mask.fBounds.height(), mask.fRowBytes);
1085 0 : device.setPixels(mask.fImage);
1086 :
1087 0 : SkCanvas c(device);
1088 : // need the unclipped top/left for the translate
1089 0 : c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1090 0 : -SkIntToScalar(mask.fBounds.fTop));
1091 0 : c.concat(*fMatrix);
1092 :
1093 : // We can't call drawBitmap, or we'll infinitely recurse. Instead
1094 : // we manually build a shader and draw that into our new mask
1095 0 : SkPaint tmpPaint;
1096 0 : tmpPaint.setFlags(paint.getFlags());
1097 0 : SkAutoBitmapShaderInstall install(bitmap, tmpPaint);
1098 : SkRect rr;
1099 : rr.set(0, 0, SkIntToScalar(bitmap.width()),
1100 0 : SkIntToScalar(bitmap.height()));
1101 0 : c.drawRect(rr, install.paintWithShader());
1102 : }
1103 0 : this->drawDevMask(mask, paint);
1104 : }
1105 : }
1106 :
1107 0 : static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1108 : const SkRect& srcR) {
1109 : SkRect dstR;
1110 : SkIRect devIR;
1111 :
1112 0 : m.mapRect(&dstR, srcR);
1113 0 : dstR.roundOut(&devIR);
1114 0 : return c.quickReject(devIR);
1115 : }
1116 :
1117 0 : static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1118 : int width, int height) {
1119 : SkRect r;
1120 0 : r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1121 0 : return clipped_out(matrix, clip, r);
1122 : }
1123 :
1124 0 : static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y,
1125 : const SkBitmap& bitmap) {
1126 0 : return clip.isBW() ||
1127 0 : clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height());
1128 : }
1129 :
1130 0 : void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1131 : const SkPaint& origPaint) const {
1132 0 : SkDEBUGCODE(this->validate();)
1133 :
1134 : // nothing to draw
1135 0 : if (fRC->isEmpty() ||
1136 0 : bitmap.width() == 0 || bitmap.height() == 0 ||
1137 0 : bitmap.getConfig() == SkBitmap::kNo_Config) {
1138 0 : return;
1139 : }
1140 :
1141 : #ifndef SK_ALLOW_OVER_32K_BITMAPS
1142 : // run away on too-big bitmaps for now (exceed 16.16)
1143 0 : if (bitmap.width() > 32767 || bitmap.height() > 32767) {
1144 0 : return;
1145 : }
1146 : #endif
1147 :
1148 0 : SkPaint paint(origPaint);
1149 0 : paint.setStyle(SkPaint::kFill_Style);
1150 :
1151 : SkMatrix matrix;
1152 0 : if (!matrix.setConcat(*fMatrix, prematrix)) {
1153 : return;
1154 : }
1155 :
1156 0 : if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1157 : return;
1158 : }
1159 :
1160 0 : if (fBounder && just_translate(matrix, bitmap)) {
1161 : SkIRect ir;
1162 0 : int32_t ix = SkScalarRound(matrix.getTranslateX());
1163 0 : int32_t iy = SkScalarRound(matrix.getTranslateY());
1164 0 : ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1165 0 : if (!fBounder->doIRect(ir)) {
1166 : return;
1167 : }
1168 : }
1169 :
1170 : // only lock the pixels if we passed the clip and bounder tests
1171 0 : SkAutoLockPixels alp(bitmap);
1172 : // after the lock, check if we are valid
1173 0 : if (!bitmap.readyToDraw()) {
1174 : return;
1175 : }
1176 :
1177 0 : if (bitmap.getConfig() != SkBitmap::kA8_Config &&
1178 0 : just_translate(matrix, bitmap)) {
1179 0 : int ix = SkScalarRound(matrix.getTranslateX());
1180 0 : int iy = SkScalarRound(matrix.getTranslateY());
1181 0 : if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
1182 : uint32_t storage[kBlitterStorageLongCount];
1183 : SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1184 0 : ix, iy, storage, sizeof(storage));
1185 0 : if (blitter) {
1186 0 : SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
1187 :
1188 : SkIRect ir;
1189 0 : ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1190 :
1191 0 : SkScan::FillIRect(ir, *fRC, blitter);
1192 : return;
1193 : }
1194 : }
1195 : }
1196 :
1197 : // now make a temp draw on the stack, and use it
1198 : //
1199 0 : SkDraw draw(*this);
1200 0 : draw.fMatrix = &matrix;
1201 :
1202 0 : if (bitmap.getConfig() == SkBitmap::kA8_Config) {
1203 0 : draw.drawBitmapAsMask(bitmap, paint);
1204 : } else {
1205 0 : SkAutoBitmapShaderInstall install(bitmap, paint);
1206 :
1207 : SkRect r;
1208 : r.set(0, 0, SkIntToScalar(bitmap.width()),
1209 0 : SkIntToScalar(bitmap.height()));
1210 : // is this ok if paint has a rasterizer?
1211 0 : draw.drawRect(r, install.paintWithShader());
1212 : }
1213 : }
1214 :
1215 0 : void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
1216 : const SkPaint& origPaint) const {
1217 0 : SkDEBUGCODE(this->validate();)
1218 :
1219 : // nothing to draw
1220 0 : if (fRC->isEmpty() ||
1221 0 : bitmap.width() == 0 || bitmap.height() == 0 ||
1222 0 : bitmap.getConfig() == SkBitmap::kNo_Config) {
1223 0 : return;
1224 : }
1225 :
1226 : SkIRect bounds;
1227 0 : bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
1228 :
1229 0 : if (fRC->quickReject(bounds)) {
1230 0 : return; // nothing to draw
1231 : }
1232 :
1233 0 : SkPaint paint(origPaint);
1234 0 : paint.setStyle(SkPaint::kFill_Style);
1235 :
1236 0 : if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
1237 : uint32_t storage[kBlitterStorageLongCount];
1238 : SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1239 0 : x, y, storage, sizeof(storage));
1240 :
1241 0 : if (blitter) {
1242 0 : SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
1243 :
1244 0 : if (fBounder && !fBounder->doIRect(bounds)) {
1245 : return;
1246 : }
1247 :
1248 0 : SkScan::FillIRect(bounds, *fRC, blitter);
1249 : return;
1250 : }
1251 : }
1252 :
1253 0 : SkAutoBitmapShaderInstall install(bitmap, paint);
1254 0 : const SkPaint& shaderPaint = install.paintWithShader();
1255 :
1256 : SkMatrix matrix;
1257 : SkRect r;
1258 :
1259 : // get a scalar version of our rect
1260 0 : r.set(bounds);
1261 :
1262 : // tell the shader our offset
1263 0 : matrix.setTranslate(r.fLeft, r.fTop);
1264 0 : shaderPaint.getShader()->setLocalMatrix(matrix);
1265 :
1266 0 : SkDraw draw(*this);
1267 0 : matrix.reset();
1268 0 : draw.fMatrix = &matrix;
1269 : // call ourself with a rect
1270 : // is this OK if paint has a rasterizer?
1271 0 : draw.drawRect(r, shaderPaint);
1272 : }
1273 :
1274 : ///////////////////////////////////////////////////////////////////////////////
1275 :
1276 : #include "SkScalerContext.h"
1277 : #include "SkGlyphCache.h"
1278 : #include "SkUtils.h"
1279 :
1280 0 : static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
1281 : const char text[], size_t byteLength, SkVector* stopVector) {
1282 0 : SkFixed x = 0, y = 0;
1283 0 : const char* stop = text + byteLength;
1284 :
1285 0 : SkAutoKern autokern;
1286 :
1287 0 : while (text < stop) {
1288 : // don't need x, y here, since all subpixel variants will have the
1289 : // same advance
1290 0 : const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1291 :
1292 0 : x += autokern.adjust(glyph) + glyph.fAdvanceX;
1293 0 : y += glyph.fAdvanceY;
1294 : }
1295 0 : stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
1296 :
1297 0 : SkASSERT(text == stop);
1298 0 : }
1299 :
1300 0 : void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1301 : SkScalar x, SkScalar y,
1302 : const SkPaint& paint) const {
1303 0 : SkDEBUGCODE(this->validate();)
1304 :
1305 0 : SkTextToPathIter iter(text, byteLength, paint, true, true);
1306 :
1307 : SkMatrix matrix;
1308 0 : matrix.setScale(iter.getPathScale(), iter.getPathScale());
1309 0 : matrix.postTranslate(x, y);
1310 :
1311 : const SkPath* iterPath;
1312 0 : SkScalar xpos, prevXPos = 0;
1313 :
1314 0 : while ((iterPath = iter.next(&xpos)) != NULL) {
1315 0 : matrix.postTranslate(xpos - prevXPos, 0);
1316 0 : const SkPaint& pnt = iter.getPaint();
1317 0 : if (fDevice) {
1318 0 : fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1319 : } else {
1320 0 : this->drawPath(*iterPath, pnt, &matrix, false);
1321 : }
1322 0 : prevXPos = xpos;
1323 : }
1324 0 : }
1325 :
1326 : // disable warning : local variable used without having been initialized
1327 : #if defined _WIN32 && _MSC_VER >= 1300
1328 : #pragma warning ( push )
1329 : #pragma warning ( disable : 4701 )
1330 : #endif
1331 :
1332 : //////////////////////////////////////////////////////////////////////////////
1333 :
1334 0 : static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
1335 : SkFixed fx, SkFixed fy,
1336 : const SkGlyph& glyph) {
1337 0 : int left = SkFixedFloor(fx);
1338 0 : int top = SkFixedFloor(fy);
1339 0 : SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1340 0 : SkASSERT(NULL == state.fBounder);
1341 0 : SkASSERT((NULL == state.fClip && state.fAAClip) ||
1342 : (state.fClip && NULL == state.fAAClip && state.fClip->isRect()));
1343 :
1344 0 : left += glyph.fLeft;
1345 0 : top += glyph.fTop;
1346 :
1347 0 : int right = left + glyph.fWidth;
1348 0 : int bottom = top + glyph.fHeight;
1349 :
1350 : SkMask mask;
1351 : SkIRect storage;
1352 0 : SkIRect* bounds = &mask.fBounds;
1353 :
1354 0 : mask.fBounds.set(left, top, right, bottom);
1355 :
1356 : // this extra test is worth it, assuming that most of the time it succeeds
1357 : // since we can avoid writing to storage
1358 0 : if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
1359 0 : if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
1360 0 : return;
1361 0 : bounds = &storage;
1362 : }
1363 :
1364 0 : uint8_t* aa = (uint8_t*)glyph.fImage;
1365 0 : if (NULL == aa) {
1366 0 : aa = (uint8_t*)state.fCache->findImage(glyph);
1367 0 : if (NULL == aa) {
1368 0 : return; // can't rasterize glyph
1369 : }
1370 : }
1371 :
1372 0 : mask.fRowBytes = glyph.rowBytes();
1373 0 : mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1374 0 : mask.fImage = aa;
1375 0 : state.fBlitter->blitMask(mask, *bounds);
1376 : }
1377 :
1378 0 : static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
1379 : SkFixed fx, SkFixed fy,
1380 : const SkGlyph& glyph) {
1381 0 : int left = SkFixedFloor(fx);
1382 0 : int top = SkFixedFloor(fy);
1383 0 : SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1384 0 : SkASSERT(!state.fClip->isRect());
1385 0 : SkASSERT(NULL == state.fBounder);
1386 :
1387 : SkMask mask;
1388 :
1389 0 : left += glyph.fLeft;
1390 0 : top += glyph.fTop;
1391 :
1392 0 : mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1393 0 : SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1394 :
1395 0 : if (!clipper.done()) {
1396 0 : const SkIRect& cr = clipper.rect();
1397 0 : const uint8_t* aa = (const uint8_t*)glyph.fImage;
1398 0 : if (NULL == aa) {
1399 0 : aa = (uint8_t*)state.fCache->findImage(glyph);
1400 0 : if (NULL == aa) {
1401 0 : return;
1402 : }
1403 : }
1404 :
1405 0 : mask.fRowBytes = glyph.rowBytes();
1406 0 : mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1407 0 : mask.fImage = (uint8_t*)aa;
1408 0 : do {
1409 0 : state.fBlitter->blitMask(mask, cr);
1410 0 : clipper.next();
1411 0 : } while (!clipper.done());
1412 : }
1413 : }
1414 :
1415 0 : static void D1G_Bounder(const SkDraw1Glyph& state,
1416 : SkFixed fx, SkFixed fy,
1417 : const SkGlyph& glyph) {
1418 0 : int left = SkFixedFloor(fx);
1419 0 : int top = SkFixedFloor(fy);
1420 0 : SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1421 :
1422 : SkMask mask;
1423 :
1424 0 : left += glyph.fLeft;
1425 0 : top += glyph.fTop;
1426 :
1427 0 : mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1428 0 : SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1429 :
1430 0 : if (!clipper.done()) {
1431 0 : const SkIRect& cr = clipper.rect();
1432 0 : const uint8_t* aa = (const uint8_t*)glyph.fImage;
1433 0 : if (NULL == aa) {
1434 0 : aa = (uint8_t*)state.fCache->findImage(glyph);
1435 0 : if (NULL == aa) {
1436 0 : return;
1437 : }
1438 : }
1439 :
1440 : // we need to pass the origin, which we approximate with our
1441 : // (unadjusted) left,top coordinates (the caller called fixedfloor)
1442 0 : if (state.fBounder->doIRectGlyph(cr,
1443 : left - glyph.fLeft,
1444 0 : top - glyph.fTop, glyph)) {
1445 0 : mask.fRowBytes = glyph.rowBytes();
1446 0 : mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1447 0 : mask.fImage = (uint8_t*)aa;
1448 0 : do {
1449 0 : state.fBlitter->blitMask(mask, cr);
1450 0 : clipper.next();
1451 0 : } while (!clipper.done());
1452 : }
1453 : }
1454 : }
1455 :
1456 0 : static void D1G_Bounder_AAClip(const SkDraw1Glyph& state,
1457 : SkFixed fx, SkFixed fy,
1458 : const SkGlyph& glyph) {
1459 0 : int left = SkFixedFloor(fx);
1460 0 : int top = SkFixedFloor(fy);
1461 : SkIRect bounds;
1462 0 : bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1463 :
1464 0 : if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) {
1465 0 : D1G_NoBounder_RectClip(state, fx, fy, glyph);
1466 : }
1467 0 : }
1468 :
1469 0 : static bool hasCustomD1GProc(const SkDraw& draw) {
1470 0 : return draw.fProcs && draw.fProcs->fD1GProc;
1471 : }
1472 :
1473 0 : static bool needsRasterTextBlit(const SkDraw& draw) {
1474 0 : return !hasCustomD1GProc(draw);
1475 : }
1476 :
1477 0 : SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
1478 : SkGlyphCache* cache) {
1479 0 : fDraw = draw;
1480 0 : fBounder = draw->fBounder;
1481 0 : fBlitter = blitter;
1482 0 : fCache = cache;
1483 :
1484 0 : if (hasCustomD1GProc(*draw)) {
1485 : // todo: fix this assumption about clips w/ custom
1486 0 : fClip = draw->fClip;
1487 0 : fClipBounds = fClip->getBounds();
1488 0 : return draw->fProcs->fD1GProc;
1489 : }
1490 :
1491 0 : if (draw->fRC->isBW()) {
1492 0 : fAAClip = NULL;
1493 0 : fClip = &draw->fRC->bwRgn();
1494 0 : fClipBounds = fClip->getBounds();
1495 0 : if (NULL == fBounder) {
1496 0 : if (fClip->isRect()) {
1497 0 : return D1G_NoBounder_RectClip;
1498 : } else {
1499 0 : return D1G_NoBounder_RgnClip;
1500 : }
1501 : } else {
1502 0 : return D1G_Bounder;
1503 : }
1504 : } else { // aaclip
1505 0 : fAAClip = &draw->fRC->aaRgn();
1506 0 : fClip = NULL;
1507 0 : fClipBounds = fAAClip->getBounds();
1508 0 : if (NULL == fBounder) {
1509 0 : return D1G_NoBounder_RectClip;
1510 : } else {
1511 0 : return D1G_Bounder_AAClip;
1512 : }
1513 : }
1514 : }
1515 :
1516 : ///////////////////////////////////////////////////////////////////////////////
1517 :
1518 0 : void SkDraw::drawText(const char text[], size_t byteLength,
1519 : SkScalar x, SkScalar y, const SkPaint& paint) const {
1520 0 : SkASSERT(byteLength == 0 || text != NULL);
1521 :
1522 0 : SkDEBUGCODE(this->validate();)
1523 :
1524 : // nothing to draw
1525 0 : if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1526 0 : return;
1527 : }
1528 :
1529 0 : if (/*paint.isLinearText() ||*/
1530 0 : (fMatrix->hasPerspective())) {
1531 0 : this->drawText_asPaths(text, byteLength, x, y, paint);
1532 0 : return;
1533 : }
1534 :
1535 0 : SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1536 :
1537 0 : const SkMatrix* matrix = fMatrix;
1538 0 : if (hasCustomD1GProc(*this)) {
1539 : // only support the fMVMatrix (for now) for the GPU case, which also
1540 : // sets the fD1GProc
1541 0 : if (fMVMatrix) {
1542 0 : matrix = fMVMatrix;
1543 : }
1544 : }
1545 :
1546 0 : SkAutoGlyphCache autoCache(paint, matrix);
1547 0 : SkGlyphCache* cache = autoCache.getCache();
1548 :
1549 : // transform our starting point
1550 : {
1551 : SkPoint loc;
1552 0 : matrix->mapXY(x, y, &loc);
1553 0 : x = loc.fX;
1554 0 : y = loc.fY;
1555 : }
1556 :
1557 : // need to measure first
1558 0 : if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1559 : SkVector stop;
1560 :
1561 0 : measure_text(cache, glyphCacheProc, text, byteLength, &stop);
1562 :
1563 0 : SkScalar stopX = stop.fX;
1564 0 : SkScalar stopY = stop.fY;
1565 :
1566 0 : if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1567 0 : stopX = SkScalarHalf(stopX);
1568 0 : stopY = SkScalarHalf(stopY);
1569 : }
1570 0 : x -= stopX;
1571 0 : y -= stopY;
1572 : }
1573 :
1574 0 : SkFixed fx = SkScalarToFixed(x);
1575 0 : SkFixed fy = SkScalarToFixed(y);
1576 0 : const char* stop = text + byteLength;
1577 :
1578 0 : SkFixed fxMask = ~0;
1579 0 : SkFixed fyMask = ~0;
1580 0 : if (paint.isSubpixelText()) {
1581 0 : SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*matrix);
1582 0 : if (kX_SkAxisAlignment == baseline) {
1583 0 : fyMask = 0;
1584 0 : } else if (kY_SkAxisAlignment == baseline) {
1585 0 : fxMask = 0;
1586 : }
1587 : }
1588 : // apply the bias here, so we don't have to add 1/2 in the loop
1589 0 : fx += SK_FixedHalf;
1590 0 : fy += SK_FixedHalf;
1591 :
1592 0 : SkAAClipBlitter aaBlitter;
1593 0 : SkAutoBlitterChoose blitterChooser;
1594 0 : SkBlitter* blitter = NULL;
1595 0 : if (needsRasterTextBlit(*this)) {
1596 0 : blitterChooser.choose(*fBitmap, *matrix, paint);
1597 0 : blitter = blitterChooser.get();
1598 0 : if (fRC->isAA()) {
1599 0 : aaBlitter.init(blitter, &fRC->aaRgn());
1600 0 : blitter = &aaBlitter;
1601 : }
1602 : }
1603 :
1604 0 : SkAutoKern autokern;
1605 : SkDraw1Glyph d1g;
1606 0 : SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
1607 :
1608 0 : while (text < stop) {
1609 0 : const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
1610 :
1611 0 : fx += autokern.adjust(glyph);
1612 :
1613 0 : if (glyph.fWidth) {
1614 0 : proc(d1g, fx, fy, glyph);
1615 : }
1616 0 : fx += glyph.fAdvanceX;
1617 0 : fy += glyph.fAdvanceY;
1618 : }
1619 : }
1620 :
1621 : // last parameter is interpreted as SkFixed [x, y]
1622 : // return the fixed position, which may be rounded or not by the caller
1623 : // e.g. subpixel doesn't round
1624 : typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
1625 :
1626 0 : static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1627 : SkIPoint* dst) {
1628 0 : dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
1629 0 : }
1630 :
1631 0 : static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1632 : SkIPoint* dst) {
1633 : dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
1634 0 : SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
1635 0 : }
1636 :
1637 0 : static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1638 : SkIPoint* dst) {
1639 : dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
1640 0 : SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
1641 0 : }
1642 :
1643 0 : static AlignProc pick_align_proc(SkPaint::Align align) {
1644 : static const AlignProc gProcs[] = {
1645 : leftAlignProc, centerAlignProc, rightAlignProc
1646 : };
1647 :
1648 0 : SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
1649 :
1650 0 : return gProcs[align];
1651 : }
1652 :
1653 : class TextMapState {
1654 : public:
1655 : mutable SkPoint fLoc;
1656 :
1657 0 : TextMapState(const SkMatrix& matrix, SkScalar y)
1658 0 : : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
1659 :
1660 : typedef void (*Proc)(const TextMapState&, const SkScalar pos[]);
1661 :
1662 : Proc pickProc(int scalarsPerPosition);
1663 :
1664 : private:
1665 : const SkMatrix& fMatrix;
1666 : SkMatrix::MapXYProc fProc;
1667 : SkScalar fY; // ignored by MapXYProc
1668 : // these are only used by Only... procs
1669 : SkScalar fScaleX, fTransX, fTransformedY;
1670 :
1671 0 : static void MapXProc(const TextMapState& state, const SkScalar pos[]) {
1672 0 : state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
1673 0 : }
1674 :
1675 0 : static void MapXYProc(const TextMapState& state, const SkScalar pos[]) {
1676 0 : state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
1677 0 : }
1678 :
1679 0 : static void MapOnlyScaleXProc(const TextMapState& state,
1680 : const SkScalar pos[]) {
1681 : state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
1682 0 : state.fTransformedY);
1683 0 : }
1684 :
1685 0 : static void MapOnlyTransXProc(const TextMapState& state,
1686 : const SkScalar pos[]) {
1687 0 : state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
1688 0 : }
1689 : };
1690 :
1691 0 : TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) {
1692 0 : SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1693 :
1694 0 : if (1 == scalarsPerPosition) {
1695 0 : unsigned mtype = fMatrix.getType();
1696 0 : if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
1697 0 : return MapXProc;
1698 : } else {
1699 0 : fScaleX = fMatrix.getScaleX();
1700 0 : fTransX = fMatrix.getTranslateX();
1701 0 : fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
1702 0 : fMatrix.getTranslateY();
1703 : return (mtype & SkMatrix::kScale_Mask) ?
1704 0 : MapOnlyScaleXProc : MapOnlyTransXProc;
1705 : }
1706 : } else {
1707 0 : return MapXYProc;
1708 : }
1709 : }
1710 :
1711 : //////////////////////////////////////////////////////////////////////////////
1712 :
1713 0 : void SkDraw::drawPosText(const char text[], size_t byteLength,
1714 : const SkScalar pos[], SkScalar constY,
1715 : int scalarsPerPosition, const SkPaint& paint) const {
1716 0 : SkASSERT(byteLength == 0 || text != NULL);
1717 0 : SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1718 :
1719 0 : SkDEBUGCODE(this->validate();)
1720 :
1721 : // nothing to draw
1722 0 : if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1723 0 : return;
1724 : }
1725 :
1726 0 : if (/*paint.isLinearText() ||*/
1727 0 : (fMatrix->hasPerspective())) {
1728 : // TODO !!!!
1729 : // this->drawText_asPaths(text, byteLength, x, y, paint);
1730 0 : return;
1731 : }
1732 :
1733 0 : const SkMatrix* matrix = fMatrix;
1734 0 : if (hasCustomD1GProc(*this)) {
1735 : // only support the fMVMatrix (for now) for the GPU case, which also
1736 : // sets the fD1GProc
1737 0 : if (fMVMatrix) {
1738 0 : matrix = fMVMatrix;
1739 : }
1740 : }
1741 :
1742 0 : SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1743 0 : SkAutoGlyphCache autoCache(paint, matrix);
1744 0 : SkGlyphCache* cache = autoCache.getCache();
1745 :
1746 0 : SkAAClipBlitterWrapper wrapper;
1747 0 : SkAutoBlitterChoose blitterChooser;
1748 0 : SkBlitter* blitter = NULL;
1749 0 : if (needsRasterTextBlit(*this)) {
1750 0 : blitterChooser.choose(*fBitmap, *matrix, paint);
1751 0 : blitter = blitterChooser.get();
1752 0 : if (fRC->isAA()) {
1753 0 : wrapper.init(*fRC, blitter);
1754 0 : blitter = wrapper.getBlitter();
1755 : }
1756 : }
1757 :
1758 0 : const char* stop = text + byteLength;
1759 0 : AlignProc alignProc = pick_align_proc(paint.getTextAlign());
1760 : SkDraw1Glyph d1g;
1761 0 : SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache);
1762 0 : TextMapState tms(*matrix, constY);
1763 0 : TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
1764 :
1765 0 : if (paint.isSubpixelText()) {
1766 : // maybe we should skip the rounding if linearText is set
1767 0 : SkAxisAlignment roundBaseline = SkComputeAxisAlignmentForHText(*matrix);
1768 :
1769 0 : if (SkPaint::kLeft_Align == paint.getTextAlign()) {
1770 0 : while (text < stop) {
1771 :
1772 0 : tmsProc(tms, pos);
1773 :
1774 0 : SkFixed fx = SkScalarToFixed(tms.fLoc.fX);
1775 0 : SkFixed fy = SkScalarToFixed(tms.fLoc.fY);
1776 0 : SkFixed fxMask = ~0;
1777 0 : SkFixed fyMask = ~0;
1778 :
1779 0 : if (kX_SkAxisAlignment == roundBaseline) {
1780 0 : fyMask = 0;
1781 0 : } else if (kY_SkAxisAlignment == roundBaseline) {
1782 0 : fxMask = 0;
1783 : }
1784 :
1785 : const SkGlyph& glyph = glyphCacheProc(cache, &text,
1786 0 : fx & fxMask, fy & fyMask);
1787 :
1788 0 : if (glyph.fWidth) {
1789 0 : proc(d1g, fx, fy, glyph);
1790 : }
1791 0 : pos += scalarsPerPosition;
1792 : }
1793 : } else {
1794 0 : while (text < stop) {
1795 0 : const char* currentText = text;
1796 0 : const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0);
1797 :
1798 0 : if (glyph->fWidth) {
1799 0 : SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;)
1800 0 : SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;)
1801 :
1802 : SkFixed fx, fy;
1803 0 : SkFixed fxMask = ~0;
1804 0 : SkFixed fyMask = ~0;
1805 0 : tmsProc(tms, pos);
1806 :
1807 : {
1808 : SkIPoint fixedLoc;
1809 0 : alignProc(tms.fLoc, *glyph, &fixedLoc);
1810 0 : fx = fixedLoc.fX;
1811 0 : fy = fixedLoc.fY;
1812 :
1813 0 : if (kX_SkAxisAlignment == roundBaseline) {
1814 0 : fyMask = 0;
1815 0 : } else if (kY_SkAxisAlignment == roundBaseline) {
1816 0 : fxMask = 0;
1817 : }
1818 : }
1819 :
1820 : // have to call again, now that we've been "aligned"
1821 : glyph = &glyphCacheProc(cache, ¤tText,
1822 0 : fx & fxMask, fy & fyMask);
1823 : // the assumption is that the advance hasn't changed
1824 0 : SkASSERT(prevAdvX == glyph->fAdvanceX);
1825 0 : SkASSERT(prevAdvY == glyph->fAdvanceY);
1826 :
1827 0 : proc(d1g, fx, fy, *glyph);
1828 : }
1829 0 : pos += scalarsPerPosition;
1830 : }
1831 : }
1832 : } else { // not subpixel
1833 0 : while (text < stop) {
1834 : // the last 2 parameters are ignored
1835 0 : const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1836 :
1837 0 : if (glyph.fWidth) {
1838 0 : tmsProc(tms, pos);
1839 :
1840 : SkIPoint fixedLoc;
1841 0 : alignProc(tms.fLoc, glyph, &fixedLoc);
1842 :
1843 : proc(d1g, fixedLoc.fX + SK_FixedHalf,
1844 0 : fixedLoc.fY + SK_FixedHalf, glyph);
1845 : }
1846 0 : pos += scalarsPerPosition;
1847 : }
1848 : }
1849 : }
1850 :
1851 : #if defined _WIN32 && _MSC_VER >= 1300
1852 : #pragma warning ( pop )
1853 : #endif
1854 :
1855 : ///////////////////////////////////////////////////////////////////////////////
1856 :
1857 : #include "SkPathMeasure.h"
1858 :
1859 0 : static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
1860 : SkPathMeasure& meas, const SkMatrix& matrix) {
1861 0 : SkMatrix::MapXYProc proc = matrix.getMapXYProc();
1862 :
1863 0 : for (int i = 0; i < count; i++) {
1864 : SkPoint pos;
1865 : SkVector tangent;
1866 :
1867 0 : proc(matrix, src[i].fX, src[i].fY, &pos);
1868 0 : SkScalar sx = pos.fX;
1869 0 : SkScalar sy = pos.fY;
1870 :
1871 0 : meas.getPosTan(sx, &pos, &tangent);
1872 :
1873 : /* This is the old way (that explains our approach but is way too slow
1874 : SkMatrix matrix;
1875 : SkPoint pt;
1876 :
1877 : pt.set(sx, sy);
1878 : matrix.setSinCos(tangent.fY, tangent.fX);
1879 : matrix.preTranslate(-sx, 0);
1880 : matrix.postTranslate(pos.fX, pos.fY);
1881 : matrix.mapPoints(&dst[i], &pt, 1);
1882 : */
1883 : dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy),
1884 0 : pos.fY + SkScalarMul(tangent.fX, sy));
1885 : }
1886 0 : }
1887 :
1888 : /* TODO
1889 :
1890 : Need differentially more subdivisions when the follow-path is curvy. Not sure how to
1891 : determine that, but we need it. I guess a cheap answer is let the caller tell us,
1892 : but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
1893 : */
1894 0 : static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
1895 : const SkMatrix& matrix) {
1896 0 : SkPath::Iter iter(src, false);
1897 : SkPoint srcP[4], dstP[3];
1898 : SkPath::Verb verb;
1899 :
1900 0 : while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
1901 0 : switch (verb) {
1902 : case SkPath::kMove_Verb:
1903 0 : morphpoints(dstP, srcP, 1, meas, matrix);
1904 0 : dst->moveTo(dstP[0]);
1905 0 : break;
1906 : case SkPath::kLine_Verb:
1907 : // turn lines into quads to look bendy
1908 0 : srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX);
1909 0 : srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY);
1910 0 : morphpoints(dstP, srcP, 2, meas, matrix);
1911 0 : dst->quadTo(dstP[0], dstP[1]);
1912 0 : break;
1913 : case SkPath::kQuad_Verb:
1914 0 : morphpoints(dstP, &srcP[1], 2, meas, matrix);
1915 0 : dst->quadTo(dstP[0], dstP[1]);
1916 0 : break;
1917 : case SkPath::kCubic_Verb:
1918 0 : morphpoints(dstP, &srcP[1], 3, meas, matrix);
1919 0 : dst->cubicTo(dstP[0], dstP[1], dstP[2]);
1920 0 : break;
1921 : case SkPath::kClose_Verb:
1922 0 : dst->close();
1923 0 : break;
1924 : default:
1925 0 : SkDEBUGFAIL("unknown verb");
1926 0 : break;
1927 : }
1928 : }
1929 0 : }
1930 :
1931 0 : void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
1932 : const SkPath& follow, const SkMatrix* matrix,
1933 : const SkPaint& paint) const {
1934 0 : SkASSERT(byteLength == 0 || text != NULL);
1935 :
1936 : // nothing to draw
1937 0 : if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1938 0 : return;
1939 : }
1940 :
1941 0 : SkTextToPathIter iter(text, byteLength, paint, true, true);
1942 0 : SkPathMeasure meas(follow, false);
1943 0 : SkScalar hOffset = 0;
1944 :
1945 : // need to measure first
1946 0 : if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1947 0 : SkScalar pathLen = meas.getLength();
1948 0 : if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1949 0 : pathLen = SkScalarHalf(pathLen);
1950 : }
1951 0 : hOffset += pathLen;
1952 : }
1953 :
1954 : const SkPath* iterPath;
1955 : SkScalar xpos;
1956 : SkMatrix scaledMatrix;
1957 0 : SkScalar scale = iter.getPathScale();
1958 :
1959 0 : scaledMatrix.setScale(scale, scale);
1960 :
1961 0 : while ((iterPath = iter.next(&xpos)) != NULL) {
1962 0 : SkPath tmp;
1963 0 : SkMatrix m(scaledMatrix);
1964 :
1965 0 : m.postTranslate(xpos + hOffset, 0);
1966 0 : if (matrix) {
1967 0 : m.postConcat(*matrix);
1968 : }
1969 0 : morphpath(&tmp, *iterPath, meas, m);
1970 0 : if (fDevice) {
1971 0 : fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true);
1972 : } else {
1973 0 : this->drawPath(tmp, iter.getPaint(), NULL, true);
1974 : }
1975 : }
1976 : }
1977 :
1978 : #ifdef SK_BUILD_FOR_ANDROID
1979 : void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength,
1980 : const SkPoint pos[], const SkPaint& paint,
1981 : const SkPath& path, const SkMatrix* matrix) const {
1982 : // nothing to draw
1983 : if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1984 : return;
1985 : }
1986 :
1987 : SkMatrix scaledMatrix;
1988 : SkPathMeasure meas(path, false);
1989 :
1990 : SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(
1991 : SkPaint::kForward_TextBufferDirection, true);
1992 :
1993 : // Copied (modified) from SkTextToPathIter constructor to setup paint
1994 : SkPaint tempPaint(paint);
1995 :
1996 : tempPaint.setLinearText(true);
1997 : tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
1998 :
1999 : if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0
2000 : && tempPaint.getStyle() != SkPaint::kFill_Style)) {
2001 : tempPaint.setStyle(SkPaint::kFill_Style);
2002 : tempPaint.setPathEffect(NULL);
2003 : }
2004 : // End copied from SkTextToPathIter constructor
2005 :
2006 : // detach cache
2007 : SkGlyphCache* cache = tempPaint.detachCache(NULL);
2008 :
2009 : // Must set scale, even if 1
2010 : SkScalar scale = SK_Scalar1;
2011 : scaledMatrix.setScale(scale, scale);
2012 :
2013 : // Loop over all glyph ids
2014 : for (const char* stop = text + byteLength; text < stop; pos++) {
2015 :
2016 : const SkGlyph& glyph = glyphCacheProc(cache, &text);
2017 : SkPath tmp;
2018 :
2019 : const SkPath* glyphPath = cache->findPath(glyph);
2020 : if (glyphPath == NULL) {
2021 : continue;
2022 : }
2023 :
2024 : SkMatrix m(scaledMatrix);
2025 : m.postTranslate(pos->fX, 0);
2026 :
2027 : if (matrix) {
2028 : m.postConcat(*matrix);
2029 : }
2030 :
2031 : morphpath(&tmp, *glyphPath, meas, m);
2032 : this->drawPath(tmp, tempPaint);
2033 :
2034 : }
2035 :
2036 : // re-attach cache
2037 : SkGlyphCache::AttachCache(cache);
2038 : }
2039 : #endif
2040 :
2041 : ///////////////////////////////////////////////////////////////////////////////
2042 :
2043 : struct VertState {
2044 : int f0, f1, f2;
2045 :
2046 0 : VertState(int vCount, const uint16_t indices[], int indexCount)
2047 0 : : fIndices(indices) {
2048 0 : fCurrIndex = 0;
2049 0 : if (indices) {
2050 0 : fCount = indexCount;
2051 : } else {
2052 0 : fCount = vCount;
2053 : }
2054 0 : }
2055 :
2056 : typedef bool (*Proc)(VertState*);
2057 : Proc chooseProc(SkCanvas::VertexMode mode);
2058 :
2059 : private:
2060 : int fCount;
2061 : int fCurrIndex;
2062 : const uint16_t* fIndices;
2063 :
2064 : static bool Triangles(VertState*);
2065 : static bool TrianglesX(VertState*);
2066 : static bool TriangleStrip(VertState*);
2067 : static bool TriangleStripX(VertState*);
2068 : static bool TriangleFan(VertState*);
2069 : static bool TriangleFanX(VertState*);
2070 : };
2071 :
2072 0 : bool VertState::Triangles(VertState* state) {
2073 0 : int index = state->fCurrIndex;
2074 0 : if (index + 3 > state->fCount) {
2075 0 : return false;
2076 : }
2077 0 : state->f0 = index + 0;
2078 0 : state->f1 = index + 1;
2079 0 : state->f2 = index + 2;
2080 0 : state->fCurrIndex = index + 3;
2081 0 : return true;
2082 : }
2083 :
2084 0 : bool VertState::TrianglesX(VertState* state) {
2085 0 : const uint16_t* indices = state->fIndices;
2086 0 : int index = state->fCurrIndex;
2087 0 : if (index + 3 > state->fCount) {
2088 0 : return false;
2089 : }
2090 0 : state->f0 = indices[index + 0];
2091 0 : state->f1 = indices[index + 1];
2092 0 : state->f2 = indices[index + 2];
2093 0 : state->fCurrIndex = index + 3;
2094 0 : return true;
2095 : }
2096 :
2097 0 : bool VertState::TriangleStrip(VertState* state) {
2098 0 : int index = state->fCurrIndex;
2099 0 : if (index + 3 > state->fCount) {
2100 0 : return false;
2101 : }
2102 0 : state->f2 = index + 2;
2103 0 : if (index & 1) {
2104 0 : state->f0 = index + 1;
2105 0 : state->f1 = index + 0;
2106 : } else {
2107 0 : state->f0 = index + 0;
2108 0 : state->f1 = index + 1;
2109 : }
2110 0 : state->fCurrIndex = index + 1;
2111 0 : return true;
2112 : }
2113 :
2114 0 : bool VertState::TriangleStripX(VertState* state) {
2115 0 : const uint16_t* indices = state->fIndices;
2116 0 : int index = state->fCurrIndex;
2117 0 : if (index + 3 > state->fCount) {
2118 0 : return false;
2119 : }
2120 0 : state->f2 = indices[index + 2];
2121 0 : if (index & 1) {
2122 0 : state->f0 = indices[index + 1];
2123 0 : state->f1 = indices[index + 0];
2124 : } else {
2125 0 : state->f0 = indices[index + 0];
2126 0 : state->f1 = indices[index + 1];
2127 : }
2128 0 : state->fCurrIndex = index + 1;
2129 0 : return true;
2130 : }
2131 :
2132 0 : bool VertState::TriangleFan(VertState* state) {
2133 0 : int index = state->fCurrIndex;
2134 0 : if (index + 3 > state->fCount) {
2135 0 : return false;
2136 : }
2137 0 : state->f0 = 0;
2138 0 : state->f1 = index + 1;
2139 0 : state->f2 = index + 2;
2140 0 : state->fCurrIndex = index + 1;
2141 0 : return true;
2142 : }
2143 :
2144 0 : bool VertState::TriangleFanX(VertState* state) {
2145 0 : const uint16_t* indices = state->fIndices;
2146 0 : int index = state->fCurrIndex;
2147 0 : if (index + 3 > state->fCount) {
2148 0 : return false;
2149 : }
2150 0 : state->f0 = indices[0];
2151 0 : state->f1 = indices[index + 1];
2152 0 : state->f2 = indices[index + 2];
2153 0 : state->fCurrIndex = index + 1;
2154 0 : return true;
2155 : }
2156 :
2157 0 : VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
2158 0 : switch (mode) {
2159 : case SkCanvas::kTriangles_VertexMode:
2160 0 : return fIndices ? TrianglesX : Triangles;
2161 : case SkCanvas::kTriangleStrip_VertexMode:
2162 0 : return fIndices ? TriangleStripX : TriangleStrip;
2163 : case SkCanvas::kTriangleFan_VertexMode:
2164 0 : return fIndices ? TriangleFanX : TriangleFan;
2165 : default:
2166 0 : return NULL;
2167 : }
2168 : }
2169 :
2170 : typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&,
2171 : SkBlitter*);
2172 :
2173 0 : static HairProc ChooseHairProc(bool doAntiAlias) {
2174 0 : return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
2175 : }
2176 :
2177 0 : static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
2178 : const SkPoint texs[], SkMatrix* matrix) {
2179 : SkPoint src[3], dst[3];
2180 :
2181 0 : src[0] = texs[state.f0];
2182 0 : src[1] = texs[state.f1];
2183 0 : src[2] = texs[state.f2];
2184 0 : dst[0] = verts[state.f0];
2185 0 : dst[1] = verts[state.f1];
2186 0 : dst[2] = verts[state.f2];
2187 0 : return matrix->setPolyToPoly(src, dst, 3);
2188 : }
2189 :
2190 0 : class SkTriColorShader : public SkShader {
2191 : public:
2192 0 : SkTriColorShader() {}
2193 :
2194 : bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
2195 :
2196 : virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
2197 :
2198 : protected:
2199 0 : SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {}
2200 :
2201 0 : virtual Factory getFactory() { return CreateProc; }
2202 :
2203 : private:
2204 : SkMatrix fDstToUnit;
2205 : SkPMColor fColors[3];
2206 :
2207 0 : static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2208 0 : return SkNEW_ARGS(SkTriColorShader, (buffer));
2209 : }
2210 : typedef SkShader INHERITED;
2211 : };
2212 :
2213 0 : bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
2214 : int index0, int index1, int index2) {
2215 :
2216 0 : fColors[0] = SkPreMultiplyColor(colors[index0]);
2217 0 : fColors[1] = SkPreMultiplyColor(colors[index1]);
2218 0 : fColors[2] = SkPreMultiplyColor(colors[index2]);
2219 :
2220 : SkMatrix m, im;
2221 0 : m.reset();
2222 0 : m.set(0, pts[index1].fX - pts[index0].fX);
2223 0 : m.set(1, pts[index2].fX - pts[index0].fX);
2224 0 : m.set(2, pts[index0].fX);
2225 0 : m.set(3, pts[index1].fY - pts[index0].fY);
2226 0 : m.set(4, pts[index2].fY - pts[index0].fY);
2227 0 : m.set(5, pts[index0].fY);
2228 0 : if (!m.invert(&im)) {
2229 0 : return false;
2230 : }
2231 0 : return fDstToUnit.setConcat(im, this->getTotalInverse());
2232 : }
2233 :
2234 : #include "SkColorPriv.h"
2235 : #include "SkComposeShader.h"
2236 :
2237 0 : static int ScalarTo256(SkScalar v) {
2238 0 : int scale = SkScalarToFixed(v) >> 8;
2239 0 : if (scale < 0) {
2240 0 : scale = 0;
2241 : }
2242 0 : if (scale > 255) {
2243 0 : scale = 255;
2244 : }
2245 0 : return SkAlpha255To256(scale);
2246 : }
2247 :
2248 0 : void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
2249 : SkPoint src;
2250 :
2251 0 : for (int i = 0; i < count; i++) {
2252 0 : fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
2253 0 : x += 1;
2254 :
2255 0 : int scale1 = ScalarTo256(src.fX);
2256 0 : int scale2 = ScalarTo256(src.fY);
2257 0 : int scale0 = 256 - scale1 - scale2;
2258 0 : if (scale0 < 0) {
2259 0 : if (scale1 > scale2) {
2260 0 : scale2 = 256 - scale1;
2261 : } else {
2262 0 : scale1 = 256 - scale2;
2263 : }
2264 0 : scale0 = 0;
2265 : }
2266 :
2267 0 : dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
2268 0 : SkAlphaMulQ(fColors[1], scale1) +
2269 0 : SkAlphaMulQ(fColors[2], scale2);
2270 : }
2271 0 : }
2272 :
2273 0 : void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
2274 : const SkPoint vertices[], const SkPoint textures[],
2275 : const SkColor colors[], SkXfermode* xmode,
2276 : const uint16_t indices[], int indexCount,
2277 : const SkPaint& paint) const {
2278 0 : SkASSERT(0 == count || NULL != vertices);
2279 :
2280 : // abort early if there is nothing to draw
2281 0 : if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
2282 0 : return;
2283 : }
2284 :
2285 : // transform out vertices into device coordinates
2286 0 : SkAutoSTMalloc<16, SkPoint> storage(count);
2287 0 : SkPoint* devVerts = storage.get();
2288 0 : fMatrix->mapPoints(devVerts, vertices, count);
2289 :
2290 0 : if (fBounder) {
2291 : SkRect bounds;
2292 0 : bounds.set(devVerts, count);
2293 0 : if (!fBounder->doRect(bounds, paint)) {
2294 : return;
2295 : }
2296 : }
2297 :
2298 : /*
2299 : We can draw the vertices in 1 of 4 ways:
2300 :
2301 : - solid color (no shader/texture[], no colors[])
2302 : - just colors (no shader/texture[], has colors[])
2303 : - just texture (has shader/texture[], no colors[])
2304 : - colors * texture (has shader/texture[], has colors[])
2305 :
2306 : Thus for texture drawing, we need both texture[] and a shader.
2307 : */
2308 :
2309 0 : SkTriColorShader triShader; // must be above declaration of p
2310 0 : SkPaint p(paint);
2311 :
2312 0 : SkShader* shader = p.getShader();
2313 0 : if (NULL == shader) {
2314 : // if we have no shader, we ignore the texture coordinates
2315 0 : textures = NULL;
2316 0 : } else if (NULL == textures) {
2317 : // if we don't have texture coordinates, ignore the shader
2318 0 : p.setShader(NULL);
2319 0 : shader = NULL;
2320 : }
2321 :
2322 : // setup the custom shader (if needed)
2323 0 : if (NULL != colors) {
2324 0 : if (NULL == textures) {
2325 : // just colors (no texture)
2326 0 : p.setShader(&triShader);
2327 : } else {
2328 : // colors * texture
2329 0 : SkASSERT(shader);
2330 0 : bool releaseMode = false;
2331 0 : if (NULL == xmode) {
2332 0 : xmode = SkXfermode::Create(SkXfermode::kMultiply_Mode);
2333 0 : releaseMode = true;
2334 : }
2335 0 : SkShader* compose = SkNEW_ARGS(SkComposeShader,
2336 : (&triShader, shader, xmode));
2337 0 : p.setShader(compose)->unref();
2338 0 : if (releaseMode) {
2339 0 : xmode->unref();
2340 : }
2341 : }
2342 : }
2343 :
2344 0 : SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
2345 : // setup our state and function pointer for iterating triangles
2346 0 : VertState state(count, indices, indexCount);
2347 0 : VertState::Proc vertProc = state.chooseProc(vmode);
2348 :
2349 0 : if (NULL != textures || NULL != colors) {
2350 : SkMatrix localM, tempM;
2351 0 : bool hasLocalM = shader && shader->getLocalMatrix(&localM);
2352 :
2353 0 : if (NULL != colors) {
2354 0 : if (!triShader.setContext(*fBitmap, p, *fMatrix)) {
2355 0 : colors = NULL;
2356 : }
2357 : }
2358 :
2359 0 : while (vertProc(&state)) {
2360 0 : if (NULL != textures) {
2361 0 : if (texture_to_matrix(state, vertices, textures, &tempM)) {
2362 0 : if (hasLocalM) {
2363 0 : tempM.postConcat(localM);
2364 : }
2365 0 : shader->setLocalMatrix(tempM);
2366 : // need to recal setContext since we changed the local matrix
2367 0 : if (!shader->setContext(*fBitmap, p, *fMatrix)) {
2368 0 : continue;
2369 : }
2370 : }
2371 : }
2372 0 : if (NULL != colors) {
2373 0 : if (!triShader.setup(vertices, colors,
2374 0 : state.f0, state.f1, state.f2)) {
2375 0 : continue;
2376 : }
2377 : }
2378 :
2379 : SkPoint tmp[] = {
2380 : devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
2381 0 : };
2382 0 : SkScan::FillTriangle(tmp, *fRC, blitter.get());
2383 : }
2384 : // now restore the shader's original local matrix
2385 0 : if (NULL != shader) {
2386 0 : if (hasLocalM) {
2387 0 : shader->setLocalMatrix(localM);
2388 : } else {
2389 0 : shader->resetLocalMatrix();
2390 : }
2391 0 : }
2392 : } else {
2393 : // no colors[] and no texture
2394 0 : HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
2395 0 : const SkRasterClip& clip = *fRC;
2396 0 : while (vertProc(&state)) {
2397 0 : hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get());
2398 0 : hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get());
2399 0 : hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get());
2400 : }
2401 : }
2402 : }
2403 :
2404 : ///////////////////////////////////////////////////////////////////////////////
2405 : ///////////////////////////////////////////////////////////////////////////////
2406 :
2407 : #ifdef SK_DEBUG
2408 :
2409 0 : void SkDraw::validate() const {
2410 0 : SkASSERT(fBitmap != NULL);
2411 0 : SkASSERT(fMatrix != NULL);
2412 0 : SkASSERT(fClip != NULL);
2413 0 : SkASSERT(fRC != NULL);
2414 :
2415 0 : const SkIRect& cr = fRC->getBounds();
2416 : SkIRect br;
2417 :
2418 0 : br.set(0, 0, fBitmap->width(), fBitmap->height());
2419 0 : SkASSERT(cr.isEmpty() || br.contains(cr));
2420 :
2421 : // assert that both are null, or both are not-null
2422 0 : SkASSERT(!fMVMatrix == !fExtMatrix);
2423 0 : }
2424 :
2425 : #endif
2426 :
2427 : ///////////////////////////////////////////////////////////////////////////////
2428 :
2429 0 : SkBounder::SkBounder() {
2430 : // initialize up front. This gets reset by SkCanvas before each draw call.
2431 0 : fClip = &SkRegion::GetEmptyRegion();
2432 0 : }
2433 :
2434 0 : bool SkBounder::doIRect(const SkIRect& r) {
2435 : SkIRect rr;
2436 0 : return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr);
2437 : }
2438 :
2439 : // TODO: change the prototype to take fixed, and update the callers
2440 0 : bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y,
2441 : const SkGlyph& glyph) {
2442 : SkIRect rr;
2443 0 : if (!rr.intersect(fClip->getBounds(), r)) {
2444 0 : return false;
2445 : }
2446 : GlyphRec rec;
2447 0 : rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y));
2448 : rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX,
2449 0 : rec.fLSB.fY + glyph.fAdvanceY);
2450 0 : rec.fGlyphID = glyph.getGlyphID();
2451 0 : rec.fFlags = 0;
2452 0 : return this->onIRectGlyph(rr, rec);
2453 : }
2454 :
2455 0 : bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1,
2456 : const SkPaint& paint) {
2457 : SkIRect r;
2458 : SkScalar v0, v1;
2459 :
2460 0 : v0 = pt0.fX;
2461 0 : v1 = pt1.fX;
2462 0 : if (v0 > v1) {
2463 0 : SkTSwap<SkScalar>(v0, v1);
2464 : }
2465 0 : r.fLeft = SkScalarFloor(v0);
2466 0 : r.fRight = SkScalarCeil(v1);
2467 :
2468 0 : v0 = pt0.fY;
2469 0 : v1 = pt1.fY;
2470 0 : if (v0 > v1) {
2471 0 : SkTSwap<SkScalar>(v0, v1);
2472 : }
2473 0 : r.fTop = SkScalarFloor(v0);
2474 0 : r.fBottom = SkScalarCeil(v1);
2475 :
2476 0 : if (paint.isAntiAlias()) {
2477 0 : r.inset(-1, -1);
2478 : }
2479 0 : return this->doIRect(r);
2480 : }
2481 :
2482 0 : bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) {
2483 : SkIRect r;
2484 :
2485 0 : if (paint.getStyle() == SkPaint::kFill_Style) {
2486 0 : rect.round(&r);
2487 : } else {
2488 0 : int rad = -1;
2489 0 : rect.roundOut(&r);
2490 0 : if (paint.isAntiAlias()) {
2491 0 : rad = -2;
2492 : }
2493 0 : r.inset(rad, rad);
2494 : }
2495 0 : return this->doIRect(r);
2496 : }
2497 :
2498 0 : bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) {
2499 : SkIRect r;
2500 0 : const SkRect& bounds = path.getBounds();
2501 :
2502 0 : if (doFill) {
2503 0 : bounds.round(&r);
2504 : } else { // hairline
2505 0 : bounds.roundOut(&r);
2506 : }
2507 :
2508 0 : if (paint.isAntiAlias()) {
2509 0 : r.inset(-1, -1);
2510 : }
2511 0 : return this->doIRect(r);
2512 : }
2513 :
2514 0 : void SkBounder::commit() {
2515 : // override in subclass
2516 0 : }
2517 :
2518 : ////////////////////////////////////////////////////////////////////////////////////////////////
2519 :
2520 : #include "SkPath.h"
2521 : #include "SkDraw.h"
2522 : #include "SkRegion.h"
2523 : #include "SkBlitter.h"
2524 :
2525 0 : static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2526 : SkMaskFilter* filter, const SkMatrix* filterMatrix,
2527 : SkIRect* bounds) {
2528 0 : if (devPath.isEmpty()) {
2529 0 : return false;
2530 : }
2531 :
2532 : // init our bounds from the path
2533 : {
2534 0 : SkRect pathBounds = devPath.getBounds();
2535 0 : pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
2536 0 : pathBounds.roundOut(bounds);
2537 : }
2538 :
2539 0 : SkIPoint margin = SkIPoint::Make(0, 0);
2540 0 : if (filter) {
2541 0 : SkASSERT(filterMatrix);
2542 :
2543 : SkMask srcM, dstM;
2544 :
2545 0 : srcM.fBounds = *bounds;
2546 0 : srcM.fFormat = SkMask::kA8_Format;
2547 0 : srcM.fImage = NULL;
2548 0 : if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2549 0 : return false;
2550 : }
2551 : }
2552 :
2553 : // (possibly) trim the bounds to reflect the clip
2554 : // (plus whatever slop the filter needs)
2555 0 : if (clipBounds) {
2556 0 : SkIRect tmp = *clipBounds;
2557 : // Ugh. Guard against gigantic margins from wacky filters. Without this
2558 : // check we can request arbitrary amounts of slop beyond our visible
2559 : // clip, and bring down the renderer (at least on finite RAM machines
2560 : // like handsets, etc.). Need to balance this invented value between
2561 : // quality of large filters like blurs, and the corresponding memory
2562 : // requests.
2563 : static const int MAX_MARGIN = 128;
2564 0 : tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
2565 0 : -SkMin32(margin.fY, MAX_MARGIN));
2566 0 : if (!bounds->intersect(tmp)) {
2567 0 : return false;
2568 : }
2569 : }
2570 :
2571 0 : return true;
2572 : }
2573 :
2574 0 : static void draw_into_mask(const SkMask& mask, const SkPath& devPath) {
2575 0 : SkBitmap bm;
2576 0 : SkDraw draw;
2577 0 : SkRasterClip clip;
2578 : SkMatrix matrix;
2579 0 : SkPaint paint;
2580 :
2581 0 : bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
2582 0 : bm.setPixels(mask.fImage);
2583 :
2584 0 : clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
2585 0 : matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2586 0 : -SkIntToScalar(mask.fBounds.fTop));
2587 :
2588 0 : draw.fBitmap = &bm;
2589 0 : draw.fRC = &clip;
2590 0 : draw.fClip = &clip.bwRgn();
2591 0 : draw.fMatrix = &matrix;
2592 0 : draw.fBounder = NULL;
2593 0 : paint.setAntiAlias(true);
2594 0 : draw.drawPath(devPath, paint);
2595 0 : }
2596 :
2597 0 : bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2598 : SkMaskFilter* filter, const SkMatrix* filterMatrix,
2599 : SkMask* mask, SkMask::CreateMode mode) {
2600 0 : if (SkMask::kJustRenderImage_CreateMode != mode) {
2601 0 : if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2602 0 : return false;
2603 : }
2604 :
2605 0 : if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2606 0 : mask->fFormat = SkMask::kA8_Format;
2607 0 : mask->fRowBytes = mask->fBounds.width();
2608 0 : size_t size = mask->computeImageSize();
2609 0 : if (0 == size) {
2610 : // we're too big to allocate the mask, abort
2611 0 : return false;
2612 : }
2613 0 : mask->fImage = SkMask::AllocImage(size);
2614 0 : memset(mask->fImage, 0, mask->computeImageSize());
2615 : }
2616 :
2617 0 : if (SkMask::kJustComputeBounds_CreateMode != mode) {
2618 0 : draw_into_mask(*mask, devPath);
2619 : }
2620 :
2621 0 : return true;
2622 : }
|