Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
8 #include "SkDraw.h"
9 #include "SkBlitter.h"
10 #include "SkBounder.h"
11 #include "SkCanvas.h"
12 #include "SkColorPriv.h"
13 #include "SkDevice.h"
14 #include "SkDeviceLooper.h"
15 #include "SkFixed.h"
16 #include "SkMaskFilter.h"
17 #include "SkPaint.h"
18 #include "SkPathEffect.h"
19 #include "SkRasterClip.h"
20 #include "SkRasterizer.h"
21 #include "SkRRect.h"
22 #include "SkScan.h"
23 #include "SkShader.h"
24 #include "SkSmallAllocator.h"
25 #include "SkString.h"
26 #include "SkStroke.h"
27 #include "SkTLazy.h"
28 #include "SkUtils.h"
30 #include "SkAutoKern.h"
31 #include "SkBitmapProcShader.h"
32 #include "SkDrawProcs.h"
33 #include "SkMatrixUtils.h"
36 //#define TRACE_BITMAP_DRAWS
39 /** Helper for allocating small blitters on the stack.
40 */
41 class SkAutoBlitterChoose : SkNoncopyable {
42 public:
43 SkAutoBlitterChoose() {
44 fBlitter = NULL;
45 }
46 SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
47 const SkPaint& paint, bool drawCoverage = false) {
48 fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator,
49 drawCoverage);
50 }
52 SkBlitter* operator->() { return fBlitter; }
53 SkBlitter* get() const { return fBlitter; }
55 void choose(const SkBitmap& device, const SkMatrix& matrix,
56 const SkPaint& paint) {
57 SkASSERT(!fBlitter);
58 fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator);
59 }
61 private:
62 // Owned by fAllocator, which will handle the delete.
63 SkBlitter* fBlitter;
64 SkTBlitterAllocator fAllocator;
65 };
66 #define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose)
68 /**
69 * Since we are providing the storage for the shader (to avoid the perf cost
70 * of calling new) we insist that in our destructor we can account for all
71 * owners of the shader.
72 */
73 class SkAutoBitmapShaderInstall : SkNoncopyable {
74 public:
75 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint)
76 : fPaint(paint) /* makes a copy of the paint */ {
77 fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode,
78 SkShader::kClamp_TileMode,
79 &fAllocator));
80 // we deliberately left the shader with an owner-count of 2
81 SkASSERT(2 == fPaint.getShader()->getRefCnt());
82 }
84 ~SkAutoBitmapShaderInstall() {
85 // since fAllocator will destroy shader, we insist that owners == 2
86 SkASSERT(2 == fPaint.getShader()->getRefCnt());
88 fPaint.setShader(NULL); // unref the shader by 1
90 }
92 // return the new paint that has the shader applied
93 const SkPaint& paintWithShader() const { return fPaint; }
95 private:
96 // copy of caller's paint (which we then modify)
97 SkPaint fPaint;
98 // Stores the shader.
99 SkTBlitterAllocator fAllocator;
100 };
101 #define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall)
103 ///////////////////////////////////////////////////////////////////////////////
105 SkDraw::SkDraw() {
106 sk_bzero(this, sizeof(*this));
107 }
109 SkDraw::SkDraw(const SkDraw& src) {
110 memcpy(this, &src, sizeof(*this));
111 }
113 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
114 if (fRC->isEmpty()) {
115 return false;
116 }
118 SkMatrix inverse;
119 if (!fMatrix->invert(&inverse)) {
120 return false;
121 }
123 SkIRect devBounds = fRC->getBounds();
124 // outset to have slop for antialasing and hairlines
125 devBounds.outset(1, 1);
126 inverse.mapRect(localBounds, SkRect::Make(devBounds));
127 return true;
128 }
130 ///////////////////////////////////////////////////////////////////////////////
132 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
134 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
135 sk_bzero(pixels, bytes);
136 }
138 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
140 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
141 sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
142 }
144 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
145 sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
146 }
148 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
149 memset(pixels, data, bytes);
150 }
152 static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap,
153 const SkPaint& paint,
154 uint32_t* data) {
155 // todo: we can apply colorfilter up front if no shader, so we wouldn't
156 // need to abort this fastpath
157 if (paint.getShader() || paint.getColorFilter()) {
158 return NULL;
159 }
161 SkXfermode::Mode mode;
162 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) {
163 return NULL;
164 }
166 SkColor color = paint.getColor();
168 // collaps modes based on color...
169 if (SkXfermode::kSrcOver_Mode == mode) {
170 unsigned alpha = SkColorGetA(color);
171 if (0 == alpha) {
172 mode = SkXfermode::kDst_Mode;
173 } else if (0xFF == alpha) {
174 mode = SkXfermode::kSrc_Mode;
175 }
176 }
178 switch (mode) {
179 case SkXfermode::kClear_Mode:
180 // SkDebugf("--- D_Clear_BitmapXferProc\n");
181 return D_Clear_BitmapXferProc; // ignore data
182 case SkXfermode::kDst_Mode:
183 // SkDebugf("--- D_Dst_BitmapXferProc\n");
184 return D_Dst_BitmapXferProc; // ignore data
185 case SkXfermode::kSrc_Mode: {
186 /*
187 should I worry about dithering for the lower depths?
188 */
189 SkPMColor pmc = SkPreMultiplyColor(color);
190 switch (bitmap.colorType()) {
191 case kPMColor_SkColorType:
192 if (data) {
193 *data = pmc;
194 }
195 // SkDebugf("--- D32_Src_BitmapXferProc\n");
196 return D32_Src_BitmapXferProc;
197 case kRGB_565_SkColorType:
198 if (data) {
199 *data = SkPixel32ToPixel16(pmc);
200 }
201 // SkDebugf("--- D16_Src_BitmapXferProc\n");
202 return D16_Src_BitmapXferProc;
203 case kAlpha_8_SkColorType:
204 if (data) {
205 *data = SkGetPackedA32(pmc);
206 }
207 // SkDebugf("--- DA8_Src_BitmapXferProc\n");
208 return DA8_Src_BitmapXferProc;
209 default:
210 break;
211 }
212 break;
213 }
214 default:
215 break;
216 }
217 return NULL;
218 }
220 static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
221 BitmapXferProc proc, uint32_t procData) {
222 int shiftPerPixel;
223 switch (bitmap.colorType()) {
224 case kPMColor_SkColorType:
225 shiftPerPixel = 2;
226 break;
227 case kRGB_565_SkColorType:
228 shiftPerPixel = 1;
229 break;
230 case kAlpha_8_SkColorType:
231 shiftPerPixel = 0;
232 break;
233 default:
234 SkDEBUGFAIL("Can't use xferproc on this config");
235 return;
236 }
238 uint8_t* pixels = (uint8_t*)bitmap.getPixels();
239 SkASSERT(pixels);
240 const size_t rowBytes = bitmap.rowBytes();
241 const int widthBytes = rect.width() << shiftPerPixel;
243 // skip down to the first scanline and X position
244 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
245 for (int scans = rect.height() - 1; scans >= 0; --scans) {
246 proc(pixels, widthBytes, procData);
247 pixels += rowBytes;
248 }
249 }
251 void SkDraw::drawPaint(const SkPaint& paint) const {
252 SkDEBUGCODE(this->validate();)
254 if (fRC->isEmpty()) {
255 return;
256 }
258 SkIRect devRect;
259 devRect.set(0, 0, fBitmap->width(), fBitmap->height());
260 if (fBounder && !fBounder->doIRect(devRect)) {
261 return;
262 }
264 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 uint32_t procData = 0; // to avoid the warning
272 BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
273 if (proc) {
274 if (D_Dst_BitmapXferProc == proc) { // nothing to do
275 return;
276 }
278 SkRegion::Iterator iter(fRC->bwRgn());
279 while (!iter.done()) {
280 CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
281 iter.next();
282 }
283 return;
284 }
285 }
287 // normal case: use a blitter
288 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
289 SkScan::FillIRect(devRect, *fRC, blitter.get());
290 }
292 ///////////////////////////////////////////////////////////////////////////////
294 struct PtProcRec {
295 SkCanvas::PointMode fMode;
296 const SkPaint* fPaint;
297 const SkRegion* fClip;
298 const SkRasterClip* fRC;
300 // computed values
301 SkFixed fRadius;
303 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
304 SkBlitter*);
306 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
307 const SkRasterClip*);
308 Proc chooseProc(SkBlitter** blitter);
310 private:
311 SkAAClipBlitterWrapper fWrapper;
312 };
314 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
315 int count, SkBlitter* blitter) {
316 SkASSERT(rec.fClip->isRect());
317 const SkIRect& r = rec.fClip->getBounds();
319 for (int i = 0; i < count; i++) {
320 int x = SkScalarFloorToInt(devPts[i].fX);
321 int y = SkScalarFloorToInt(devPts[i].fY);
322 if (r.contains(x, y)) {
323 blitter->blitH(x, y, 1);
324 }
325 }
326 }
328 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
329 const SkPoint devPts[], int count,
330 SkBlitter* blitter) {
331 SkASSERT(rec.fRC->isRect());
332 const SkIRect& r = rec.fRC->getBounds();
333 uint32_t value;
334 const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
335 SkASSERT(bitmap);
337 uint16_t* addr = bitmap->getAddr16(0, 0);
338 size_t rb = bitmap->rowBytes();
340 for (int i = 0; i < count; i++) {
341 int x = SkScalarFloorToInt(devPts[i].fX);
342 int y = SkScalarFloorToInt(devPts[i].fY);
343 if (r.contains(x, y)) {
344 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
345 }
346 }
347 }
349 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
350 const SkPoint devPts[], int count,
351 SkBlitter* blitter) {
352 SkASSERT(rec.fRC->isRect());
353 const SkIRect& r = rec.fRC->getBounds();
354 uint32_t value;
355 const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
356 SkASSERT(bitmap);
358 SkPMColor* addr = bitmap->getAddr32(0, 0);
359 size_t rb = bitmap->rowBytes();
361 for (int i = 0; i < count; i++) {
362 int x = SkScalarFloorToInt(devPts[i].fX);
363 int y = SkScalarFloorToInt(devPts[i].fY);
364 if (r.contains(x, y)) {
365 ((SkPMColor*)((char*)addr + y * rb))[x] = value;
366 }
367 }
368 }
370 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
371 int count, SkBlitter* blitter) {
372 for (int i = 0; i < count; i++) {
373 int x = SkScalarFloorToInt(devPts[i].fX);
374 int y = SkScalarFloorToInt(devPts[i].fY);
375 if (rec.fClip->contains(x, y)) {
376 blitter->blitH(x, y, 1);
377 }
378 }
379 }
381 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
382 int count, SkBlitter* blitter) {
383 for (int i = 0; i < count; i += 2) {
384 SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
385 }
386 }
388 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
389 int count, SkBlitter* blitter) {
390 for (int i = 0; i < count - 1; i++) {
391 SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
392 }
393 }
395 // aa versions
397 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
398 int count, SkBlitter* blitter) {
399 for (int i = 0; i < count; i += 2) {
400 SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
401 }
402 }
404 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
405 int count, SkBlitter* blitter) {
406 for (int i = 0; i < count - 1; i++) {
407 SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter);
408 }
409 }
411 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
413 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
414 int count, SkBlitter* blitter) {
415 const SkFixed radius = rec.fRadius;
416 for (int i = 0; i < count; i++) {
417 SkFixed x = SkScalarToFixed(devPts[i].fX);
418 SkFixed y = SkScalarToFixed(devPts[i].fY);
420 SkXRect r;
421 r.fLeft = x - radius;
422 r.fTop = y - radius;
423 r.fRight = x + radius;
424 r.fBottom = y + radius;
426 SkScan::FillXRect(r, *rec.fRC, blitter);
427 }
428 }
430 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
431 int count, SkBlitter* blitter) {
432 const SkFixed radius = rec.fRadius;
433 for (int i = 0; i < count; i++) {
434 SkFixed x = SkScalarToFixed(devPts[i].fX);
435 SkFixed y = SkScalarToFixed(devPts[i].fY);
437 SkXRect r;
438 r.fLeft = x - radius;
439 r.fTop = y - radius;
440 r.fRight = x + radius;
441 r.fBottom = y + radius;
443 SkScan::AntiFillXRect(r, *rec.fRC, blitter);
444 }
445 }
447 // If this guy returns true, then chooseProc() must return a valid proc
448 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
449 const SkMatrix* matrix, const SkRasterClip* rc) {
450 if (paint.getPathEffect()) {
451 return false;
452 }
453 SkScalar width = paint.getStrokeWidth();
454 if (0 == width) {
455 fMode = mode;
456 fPaint = &paint;
457 fClip = NULL;
458 fRC = rc;
459 fRadius = SK_FixedHalf;
460 return true;
461 }
462 if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
463 matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) {
464 SkScalar sx = matrix->get(SkMatrix::kMScaleX);
465 SkScalar sy = matrix->get(SkMatrix::kMScaleY);
466 if (SkScalarNearlyZero(sx - sy)) {
467 if (sx < 0) {
468 sx = -sx;
469 }
471 fMode = mode;
472 fPaint = &paint;
473 fClip = NULL;
474 fRC = rc;
475 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
476 return true;
477 }
478 }
479 return false;
480 }
482 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
483 Proc proc = NULL;
485 SkBlitter* blitter = *blitterPtr;
486 if (fRC->isBW()) {
487 fClip = &fRC->bwRgn();
488 } else {
489 fWrapper.init(*fRC, blitter);
490 fClip = &fWrapper.getRgn();
491 blitter = fWrapper.getBlitter();
492 *blitterPtr = blitter;
493 }
495 // for our arrays
496 SkASSERT(0 == SkCanvas::kPoints_PointMode);
497 SkASSERT(1 == SkCanvas::kLines_PointMode);
498 SkASSERT(2 == SkCanvas::kPolygon_PointMode);
499 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
501 if (fPaint->isAntiAlias()) {
502 if (0 == fPaint->getStrokeWidth()) {
503 static const Proc gAAProcs[] = {
504 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
505 };
506 proc = gAAProcs[fMode];
507 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
508 SkASSERT(SkCanvas::kPoints_PointMode == fMode);
509 proc = aa_square_proc;
510 }
511 } else { // BW
512 if (fRadius <= SK_FixedHalf) { // small radii and hairline
513 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
514 uint32_t value;
515 const SkBitmap* bm = blitter->justAnOpaqueColor(&value);
516 if (bm && kRGB_565_SkColorType == bm->colorType()) {
517 proc = bw_pt_rect_16_hair_proc;
518 } else if (bm && kPMColor_SkColorType == bm->colorType()) {
519 proc = bw_pt_rect_32_hair_proc;
520 } else {
521 proc = bw_pt_rect_hair_proc;
522 }
523 } else {
524 static Proc gBWProcs[] = {
525 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
526 };
527 proc = gBWProcs[fMode];
528 }
529 } else {
530 proc = bw_square_proc;
531 }
532 }
533 return proc;
534 }
536 static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode,
537 size_t count, const SkPoint pts[],
538 const SkPaint& paint, const SkMatrix& matrix) {
539 SkIRect ibounds;
540 SkRect bounds;
541 SkScalar inset = paint.getStrokeWidth();
543 bounds.set(pts, SkToInt(count));
544 bounds.inset(-inset, -inset);
545 matrix.mapRect(&bounds);
547 bounds.roundOut(&ibounds);
548 return bounder->doIRect(ibounds);
549 }
551 // each of these costs 8-bytes of stack space, so don't make it too large
552 // must be even for lines/polygon to work
553 #define MAX_DEV_PTS 32
555 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
556 const SkPoint pts[], const SkPaint& paint,
557 bool forceUseDevice) const {
558 // if we're in lines mode, force count to be even
559 if (SkCanvas::kLines_PointMode == mode) {
560 count &= ~(size_t)1;
561 }
563 if ((long)count <= 0) {
564 return;
565 }
567 SkASSERT(pts != NULL);
568 SkDEBUGCODE(this->validate();)
570 // nothing to draw
571 if (fRC->isEmpty()) {
572 return;
573 }
575 if (fBounder) {
576 if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) {
577 return;
578 }
580 // clear the bounder and call this again, so we don't invoke the bounder
581 // later if we happen to call ourselves for drawRect, drawPath, etc.
582 SkDraw noBounder(*this);
583 noBounder.fBounder = NULL;
584 noBounder.drawPoints(mode, count, pts, paint, forceUseDevice);
585 return;
586 }
588 PtProcRec rec;
589 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) {
590 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
592 SkPoint devPts[MAX_DEV_PTS];
593 const SkMatrix* matrix = fMatrix;
594 SkBlitter* bltr = blitter.get();
595 PtProcRec::Proc proc = rec.chooseProc(&bltr);
596 // we have to back up subsequent passes if we're in polygon mode
597 const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
599 do {
600 int n = SkToInt(count);
601 if (n > MAX_DEV_PTS) {
602 n = MAX_DEV_PTS;
603 }
604 matrix->mapPoints(devPts, pts, n);
605 proc(rec, devPts, n, bltr);
606 pts += n - backup;
607 SkASSERT(SkToInt(count) >= n);
608 count -= n;
609 if (count > 0) {
610 count += backup;
611 }
612 } while (count != 0);
613 } else {
614 switch (mode) {
615 case SkCanvas::kPoints_PointMode: {
616 // temporarily mark the paint as filling.
617 SkPaint newPaint(paint);
618 newPaint.setStyle(SkPaint::kFill_Style);
620 SkScalar width = newPaint.getStrokeWidth();
621 SkScalar radius = SkScalarHalf(width);
623 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
624 SkPath path;
625 SkMatrix preMatrix;
627 path.addCircle(0, 0, radius);
628 for (size_t i = 0; i < count; i++) {
629 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
630 // pass true for the last point, since we can modify
631 // then path then
632 if (fDevice) {
633 fDevice->drawPath(*this, path, newPaint, &preMatrix,
634 (count-1) == i);
635 } else {
636 this->drawPath(path, newPaint, &preMatrix,
637 (count-1) == i);
638 }
639 }
640 } else {
641 SkRect r;
643 for (size_t i = 0; i < count; i++) {
644 r.fLeft = pts[i].fX - radius;
645 r.fTop = pts[i].fY - radius;
646 r.fRight = r.fLeft + width;
647 r.fBottom = r.fTop + width;
648 if (fDevice) {
649 fDevice->drawRect(*this, r, newPaint);
650 } else {
651 this->drawRect(r, newPaint);
652 }
653 }
654 }
655 break;
656 }
657 case SkCanvas::kLines_PointMode:
658 #ifndef SK_DISABLE_DASHING_OPTIMIZATION
659 if (2 == count && NULL != paint.getPathEffect()) {
660 // most likely a dashed line - see if it is one of the ones
661 // we can accelerate
662 SkStrokeRec rec(paint);
663 SkPathEffect::PointData pointData;
665 SkPath path;
666 path.moveTo(pts[0]);
667 path.lineTo(pts[1]);
669 SkRect cullRect = SkRect::Make(fRC->getBounds());
671 if (paint.getPathEffect()->asPoints(&pointData, path, rec,
672 *fMatrix, &cullRect)) {
673 // 'asPoints' managed to find some fast path
675 SkPaint newP(paint);
676 newP.setPathEffect(NULL);
677 newP.setStyle(SkPaint::kFill_Style);
679 if (!pointData.fFirst.isEmpty()) {
680 if (fDevice) {
681 fDevice->drawPath(*this, pointData.fFirst, newP);
682 } else {
683 this->drawPath(pointData.fFirst, newP);
684 }
685 }
687 if (!pointData.fLast.isEmpty()) {
688 if (fDevice) {
689 fDevice->drawPath(*this, pointData.fLast, newP);
690 } else {
691 this->drawPath(pointData.fLast, newP);
692 }
693 }
695 if (pointData.fSize.fX == pointData.fSize.fY) {
696 // The rest of the dashed line can just be drawn as points
697 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
699 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
700 newP.setStrokeCap(SkPaint::kRound_Cap);
701 } else {
702 newP.setStrokeCap(SkPaint::kButt_Cap);
703 }
705 if (fDevice) {
706 fDevice->drawPoints(*this,
707 SkCanvas::kPoints_PointMode,
708 pointData.fNumPoints,
709 pointData.fPoints,
710 newP);
711 } else {
712 this->drawPoints(SkCanvas::kPoints_PointMode,
713 pointData.fNumPoints,
714 pointData.fPoints,
715 newP,
716 forceUseDevice);
717 }
718 break;
719 } else {
720 // The rest of the dashed line must be drawn as rects
721 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
722 pointData.fFlags));
724 SkRect r;
726 for (int i = 0; i < pointData.fNumPoints; ++i) {
727 r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
728 pointData.fPoints[i].fY - pointData.fSize.fY,
729 pointData.fPoints[i].fX + pointData.fSize.fX,
730 pointData.fPoints[i].fY + pointData.fSize.fY);
731 if (fDevice) {
732 fDevice->drawRect(*this, r, newP);
733 } else {
734 this->drawRect(r, newP);
735 }
736 }
737 }
739 break;
740 }
741 }
742 #endif // DISABLE_DASHING_OPTIMIZATION
743 // couldn't take fast path so fall through!
744 case SkCanvas::kPolygon_PointMode: {
745 count -= 1;
746 SkPath path;
747 SkPaint p(paint);
748 p.setStyle(SkPaint::kStroke_Style);
749 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
750 for (size_t i = 0; i < count; i += inc) {
751 path.moveTo(pts[i]);
752 path.lineTo(pts[i+1]);
753 if (fDevice) {
754 fDevice->drawPath(*this, path, p, NULL, true);
755 } else {
756 this->drawPath(path, p, NULL, true);
757 }
758 path.rewind();
759 }
760 break;
761 }
762 }
763 }
764 }
766 static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
767 SkPoint* strokeSize) {
768 if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
769 paint.getStrokeMiter() < SK_ScalarSqrt2) {
770 return false;
771 }
773 SkASSERT(matrix.rectStaysRect());
774 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
775 matrix.mapVectors(strokeSize, &pt, 1);
776 strokeSize->fX = SkScalarAbs(strokeSize->fX);
777 strokeSize->fY = SkScalarAbs(strokeSize->fY);
778 return true;
779 }
781 SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
782 const SkMatrix& matrix,
783 SkPoint* strokeSize) {
784 RectType rtype;
785 const SkScalar width = paint.getStrokeWidth();
786 const bool zeroWidth = (0 == width);
787 SkPaint::Style style = paint.getStyle();
789 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
790 style = SkPaint::kFill_Style;
791 }
793 if (paint.getPathEffect() || paint.getMaskFilter() ||
794 paint.getRasterizer() || !matrix.rectStaysRect() ||
795 SkPaint::kStrokeAndFill_Style == style) {
796 rtype = kPath_RectType;
797 } else if (SkPaint::kFill_Style == style) {
798 rtype = kFill_RectType;
799 } else if (zeroWidth) {
800 rtype = kHair_RectType;
801 } else if (easy_rect_join(paint, matrix, strokeSize)) {
802 rtype = kStroke_RectType;
803 } else {
804 rtype = kPath_RectType;
805 }
806 return rtype;
807 }
809 static const SkPoint* rect_points(const SkRect& r) {
810 return SkTCast<const SkPoint*>(&r);
811 }
813 static SkPoint* rect_points(SkRect& r) {
814 return SkTCast<SkPoint*>(&r);
815 }
817 void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
818 SkDEBUGCODE(this->validate();)
820 // nothing to draw
821 if (fRC->isEmpty()) {
822 return;
823 }
825 SkPoint strokeSize;
826 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
828 if (kPath_RectType == rtype) {
829 SkPath tmp;
830 tmp.addRect(rect);
831 tmp.setFillType(SkPath::kWinding_FillType);
832 this->drawPath(tmp, paint, NULL, true);
833 return;
834 }
836 const SkMatrix& matrix = *fMatrix;
837 SkRect devRect;
839 // transform rect into devRect
840 matrix.mapPoints(rect_points(devRect), rect_points(rect), 2);
841 devRect.sort();
843 if (fBounder && !fBounder->doRect(devRect, paint)) {
844 return;
845 }
847 // look for the quick exit, before we build a blitter
848 SkIRect ir;
849 devRect.roundOut(&ir);
850 if (paint.getStyle() != SkPaint::kFill_Style) {
851 // extra space for hairlines
852 ir.inset(-1, -1);
853 }
854 if (fRC->quickReject(ir)) {
855 return;
856 }
858 SkDeviceLooper looper(*fBitmap, *fRC, ir, paint.isAntiAlias());
859 while (looper.next()) {
860 SkRect localDevRect;
861 looper.mapRect(&localDevRect, devRect);
862 SkMatrix localMatrix;
863 looper.mapMatrix(&localMatrix, matrix);
865 SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix,
866 paint);
867 const SkRasterClip& clip = looper.getRC();
868 SkBlitter* blitter = blitterStorage.get();
870 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
871 // case we are also hairline (if we've gotten to here), which devolves to
872 // effectively just kFill
873 switch (rtype) {
874 case kFill_RectType:
875 if (paint.isAntiAlias()) {
876 SkScan::AntiFillRect(localDevRect, clip, blitter);
877 } else {
878 SkScan::FillRect(localDevRect, clip, blitter);
879 }
880 break;
881 case kStroke_RectType:
882 if (paint.isAntiAlias()) {
883 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
884 } else {
885 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
886 }
887 break;
888 case kHair_RectType:
889 if (paint.isAntiAlias()) {
890 SkScan::AntiHairRect(localDevRect, clip, blitter);
891 } else {
892 SkScan::HairRect(localDevRect, clip, blitter);
893 }
894 break;
895 default:
896 SkDEBUGFAIL("bad rtype");
897 }
898 }
899 }
901 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
902 if (srcM.fBounds.isEmpty()) {
903 return;
904 }
906 const SkMask* mask = &srcM;
908 SkMask dstM;
909 if (paint.getMaskFilter() &&
910 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) {
911 mask = &dstM;
912 } else {
913 dstM.fImage = NULL;
914 }
915 SkAutoMaskFreeImage ami(dstM.fImage);
917 if (fBounder && !fBounder->doIRect(mask->fBounds)) {
918 return;
919 }
921 SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint);
922 SkBlitter* blitter = blitterChooser.get();
924 SkAAClipBlitterWrapper wrapper;
925 const SkRegion* clipRgn;
927 if (fRC->isBW()) {
928 clipRgn = &fRC->bwRgn();
929 } else {
930 wrapper.init(*fRC, blitter);
931 clipRgn = &wrapper.getRgn();
932 blitter = wrapper.getBlitter();
933 }
934 blitter->blitMaskRegion(*mask, *clipRgn);
935 }
937 static SkScalar fast_len(const SkVector& vec) {
938 SkScalar x = SkScalarAbs(vec.fX);
939 SkScalar y = SkScalarAbs(vec.fY);
940 if (x < y) {
941 SkTSwap(x, y);
942 }
943 return x + SkScalarHalf(y);
944 }
946 static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) {
947 SkXfermode::Coeff dc;
948 if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) {
949 return false;
950 }
952 switch (dc) {
953 case SkXfermode::kOne_Coeff:
954 case SkXfermode::kISA_Coeff:
955 case SkXfermode::kISC_Coeff:
956 return true;
957 default:
958 return false;
959 }
960 }
962 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
963 SkScalar* coverage) {
964 SkASSERT(strokeWidth > 0);
965 // We need to try to fake a thick-stroke with a modulated hairline.
967 if (matrix.hasPerspective()) {
968 return false;
969 }
971 SkVector src[2], dst[2];
972 src[0].set(strokeWidth, 0);
973 src[1].set(0, strokeWidth);
974 matrix.mapVectors(dst, src, 2);
975 SkScalar len0 = fast_len(dst[0]);
976 SkScalar len1 = fast_len(dst[1]);
977 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
978 if (NULL != coverage) {
979 *coverage = SkScalarAve(len0, len1);
980 }
981 return true;
982 }
983 return false;
984 }
986 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
987 SkDEBUGCODE(this->validate());
989 if (fRC->isEmpty()) {
990 return;
991 }
993 {
994 // TODO: Investigate optimizing these options. They are in the same
995 // order as SkDraw::drawPath, which handles each case. It may be
996 // that there is no way to optimize for these using the SkRRect path.
997 SkScalar coverage;
998 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
999 goto DRAW_PATH;
1000 }
1002 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
1003 goto DRAW_PATH;
1004 }
1006 if (paint.getRasterizer()) {
1007 goto DRAW_PATH;
1008 }
1009 }
1011 if (paint.getMaskFilter()) {
1012 // Transform the rrect into device space.
1013 SkRRect devRRect;
1014 if (rrect.transform(*fMatrix, &devRRect)) {
1015 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
1016 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC,
1017 fBounder, blitter.get(),
1018 SkPaint::kFill_Style)) {
1019 return; // filterRRect() called the blitter, so we're done
1020 }
1021 }
1022 }
1024 DRAW_PATH:
1025 // Now fall back to the default case of using a path.
1026 SkPath path;
1027 path.addRRect(rrect);
1028 this->drawPath(path, paint, NULL, true);
1029 }
1031 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1032 const SkMatrix* prePathMatrix, bool pathIsMutable,
1033 bool drawCoverage) const {
1034 SkDEBUGCODE(this->validate();)
1036 // nothing to draw
1037 if (fRC->isEmpty()) {
1038 return;
1039 }
1041 SkPath* pathPtr = (SkPath*)&origSrcPath;
1042 bool doFill = true;
1043 SkPath tmpPath;
1044 SkMatrix tmpMatrix;
1045 const SkMatrix* matrix = fMatrix;
1047 if (prePathMatrix) {
1048 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style ||
1049 origPaint.getRasterizer()) {
1050 SkPath* result = pathPtr;
1052 if (!pathIsMutable) {
1053 result = &tmpPath;
1054 pathIsMutable = true;
1055 }
1056 pathPtr->transform(*prePathMatrix, result);
1057 pathPtr = result;
1058 } else {
1059 if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) {
1060 // overflow
1061 return;
1062 }
1063 matrix = &tmpMatrix;
1064 }
1065 }
1066 // at this point we're done with prePathMatrix
1067 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1069 SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1071 {
1072 SkScalar coverage;
1073 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1074 if (SK_Scalar1 == coverage) {
1075 paint.writable()->setStrokeWidth(0);
1076 } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) {
1077 U8CPU newAlpha;
1078 #if 0
1079 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1080 origPaint.getAlpha()));
1081 #else
1082 // this is the old technique, which we preserve for now so
1083 // we don't change previous results (testing)
1084 // the new way seems fine, its just (a tiny bit) different
1085 int scale = (int)SkScalarMul(coverage, 256);
1086 newAlpha = origPaint.getAlpha() * scale >> 8;
1087 #endif
1088 SkPaint* writablePaint = paint.writable();
1089 writablePaint->setStrokeWidth(0);
1090 writablePaint->setAlpha(newAlpha);
1091 }
1092 }
1093 }
1095 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1096 SkRect cullRect;
1097 const SkRect* cullRectPtr = NULL;
1098 if (this->computeConservativeLocalClipBounds(&cullRect)) {
1099 cullRectPtr = &cullRect;
1100 }
1101 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr);
1102 pathPtr = &tmpPath;
1103 }
1105 if (paint->getRasterizer()) {
1106 SkMask mask;
1107 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix,
1108 &fRC->getBounds(), paint->getMaskFilter(), &mask,
1109 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
1110 this->drawDevMask(mask, *paint);
1111 SkMask::FreeImage(mask.fImage);
1112 }
1113 return;
1114 }
1116 // avoid possibly allocating a new path in transform if we can
1117 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1119 // transform the path into device space
1120 pathPtr->transform(*matrix, devPathPtr);
1122 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint, drawCoverage);
1124 if (paint->getMaskFilter()) {
1125 SkPaint::Style style = doFill ? SkPaint::kFill_Style :
1126 SkPaint::kStroke_Style;
1127 if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC,
1128 fBounder, blitter.get(),
1129 style)) {
1130 return; // filterPath() called the blitter, so we're done
1131 }
1132 }
1134 if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) {
1135 return;
1136 }
1138 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
1139 if (doFill) {
1140 if (paint->isAntiAlias()) {
1141 proc = SkScan::AntiFillPath;
1142 } else {
1143 proc = SkScan::FillPath;
1144 }
1145 } else { // hairline
1146 if (paint->isAntiAlias()) {
1147 proc = SkScan::AntiHairPath;
1148 } else {
1149 proc = SkScan::HairPath;
1150 }
1151 }
1152 proc(*devPathPtr, *fRC, blitter.get());
1153 }
1155 /** For the purposes of drawing bitmaps, if a matrix is "almost" translate
1156 go ahead and treat it as if it were, so that subsequent code can go fast.
1157 */
1158 static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) {
1159 unsigned bits = 0; // TODO: find a way to allow the caller to tell us to
1160 // respect filtering.
1161 return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits);
1162 }
1164 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
1165 const SkPaint& paint) const {
1166 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1168 if (just_translate(*fMatrix, bitmap)) {
1169 int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1170 int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1172 SkAutoLockPixels alp(bitmap);
1173 if (!bitmap.readyToDraw()) {
1174 return;
1175 }
1177 SkMask mask;
1178 mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1179 mask.fFormat = SkMask::kA8_Format;
1180 mask.fRowBytes = SkToU32(bitmap.rowBytes());
1181 mask.fImage = bitmap.getAddr8(0, 0);
1183 this->drawDevMask(mask, paint);
1184 } else { // need to xform the bitmap first
1185 SkRect r;
1186 SkMask mask;
1188 r.set(0, 0,
1189 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1190 fMatrix->mapRect(&r);
1191 r.round(&mask.fBounds);
1193 // set the mask's bounds to the transformed bitmap-bounds,
1194 // clipped to the actual device
1195 {
1196 SkIRect devBounds;
1197 devBounds.set(0, 0, fBitmap->width(), fBitmap->height());
1198 // need intersect(l, t, r, b) on irect
1199 if (!mask.fBounds.intersect(devBounds)) {
1200 return;
1201 }
1202 }
1204 mask.fFormat = SkMask::kA8_Format;
1205 mask.fRowBytes = SkAlign4(mask.fBounds.width());
1206 size_t size = mask.computeImageSize();
1207 if (0 == size) {
1208 // the mask is too big to allocated, draw nothing
1209 return;
1210 }
1212 // allocate (and clear) our temp buffer to hold the transformed bitmap
1213 SkAutoMalloc storage(size);
1214 mask.fImage = (uint8_t*)storage.get();
1215 memset(mask.fImage, 0, size);
1217 // now draw our bitmap(src) into mask(dst), transformed by the matrix
1218 {
1219 SkBitmap device;
1220 device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
1221 mask.fBounds.height(), mask.fRowBytes);
1222 device.setPixels(mask.fImage);
1224 SkCanvas c(device);
1225 // need the unclipped top/left for the translate
1226 c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1227 -SkIntToScalar(mask.fBounds.fTop));
1228 c.concat(*fMatrix);
1230 // We can't call drawBitmap, or we'll infinitely recurse. Instead
1231 // we manually build a shader and draw that into our new mask
1232 SkPaint tmpPaint;
1233 tmpPaint.setFlags(paint.getFlags());
1234 SkAutoBitmapShaderInstall install(bitmap, tmpPaint);
1235 SkRect rr;
1236 rr.set(0, 0, SkIntToScalar(bitmap.width()),
1237 SkIntToScalar(bitmap.height()));
1238 c.drawRect(rr, install.paintWithShader());
1239 }
1240 this->drawDevMask(mask, paint);
1241 }
1242 }
1244 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1245 const SkRect& srcR) {
1246 SkRect dstR;
1247 SkIRect devIR;
1249 m.mapRect(&dstR, srcR);
1250 dstR.roundOut(&devIR);
1251 return c.quickReject(devIR);
1252 }
1254 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1255 int width, int height) {
1256 SkRect r;
1257 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1258 return clipped_out(matrix, clip, r);
1259 }
1261 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y,
1262 const SkBitmap& bitmap) {
1263 return clip.isBW() ||
1264 clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height());
1265 }
1267 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1268 const SkPaint& origPaint) const {
1269 SkDEBUGCODE(this->validate();)
1271 // nothing to draw
1272 if (fRC->isEmpty() ||
1273 bitmap.width() == 0 || bitmap.height() == 0 ||
1274 bitmap.colorType() == kUnknown_SkColorType) {
1275 return;
1276 }
1278 SkPaint paint(origPaint);
1279 paint.setStyle(SkPaint::kFill_Style);
1281 SkMatrix matrix;
1282 if (!matrix.setConcat(*fMatrix, prematrix)) {
1283 return;
1284 }
1286 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1287 return;
1288 }
1290 if (fBounder && just_translate(matrix, bitmap)) {
1291 SkIRect ir;
1292 int32_t ix = SkScalarRoundToInt(matrix.getTranslateX());
1293 int32_t iy = SkScalarRoundToInt(matrix.getTranslateY());
1294 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1295 if (!fBounder->doIRect(ir)) {
1296 return;
1297 }
1298 }
1300 if (bitmap.colorType() != kAlpha_8_SkColorType &&
1301 just_translate(matrix, bitmap)) {
1302 //
1303 // It is safe to call lock pixels now, since we know the matrix is
1304 // (more or less) identity.
1305 //
1306 SkAutoLockPixels alp(bitmap);
1307 if (!bitmap.readyToDraw()) {
1308 return;
1309 }
1310 int ix = SkScalarRoundToInt(matrix.getTranslateX());
1311 int iy = SkScalarRoundToInt(matrix.getTranslateY());
1312 if (clipHandlesSprite(*fRC, ix, iy, bitmap)) {
1313 SkTBlitterAllocator allocator;
1314 // blitter will be owned by the allocator.
1315 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1316 ix, iy, &allocator);
1317 if (blitter) {
1318 SkIRect ir;
1319 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1321 SkScan::FillIRect(ir, *fRC, blitter);
1322 return;
1323 }
1324 }
1325 }
1327 // now make a temp draw on the stack, and use it
1328 //
1329 SkDraw draw(*this);
1330 draw.fMatrix = &matrix;
1332 if (bitmap.colorType() == kAlpha_8_SkColorType) {
1333 draw.drawBitmapAsMask(bitmap, paint);
1334 } else {
1335 SkAutoBitmapShaderInstall install(bitmap, paint);
1337 SkRect r;
1338 r.set(0, 0, SkIntToScalar(bitmap.width()),
1339 SkIntToScalar(bitmap.height()));
1340 // is this ok if paint has a rasterizer?
1341 draw.drawRect(r, install.paintWithShader());
1342 }
1343 }
1345 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
1346 const SkPaint& origPaint) const {
1347 SkDEBUGCODE(this->validate();)
1349 // nothing to draw
1350 if (fRC->isEmpty() ||
1351 bitmap.width() == 0 || bitmap.height() == 0 ||
1352 bitmap.colorType() == kUnknown_SkColorType) {
1353 return;
1354 }
1356 SkIRect bounds;
1357 bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
1359 if (fRC->quickReject(bounds)) {
1360 return; // nothing to draw
1361 }
1363 SkPaint paint(origPaint);
1364 paint.setStyle(SkPaint::kFill_Style);
1366 if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) {
1367 SkTBlitterAllocator allocator;
1368 // blitter will be owned by the allocator.
1369 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1370 x, y, &allocator);
1372 if (blitter) {
1373 if (fBounder && !fBounder->doIRect(bounds)) {
1374 return;
1375 }
1377 SkScan::FillIRect(bounds, *fRC, blitter);
1378 return;
1379 }
1380 }
1382 SkAutoBitmapShaderInstall install(bitmap, paint);
1383 const SkPaint& shaderPaint = install.paintWithShader();
1385 SkMatrix matrix;
1386 SkRect r;
1388 // get a scalar version of our rect
1389 r.set(bounds);
1391 // tell the shader our offset
1392 matrix.setTranslate(r.fLeft, r.fTop);
1393 shaderPaint.getShader()->setLocalMatrix(matrix);
1395 SkDraw draw(*this);
1396 matrix.reset();
1397 draw.fMatrix = &matrix;
1398 // call ourself with a rect
1399 // is this OK if paint has a rasterizer?
1400 draw.drawRect(r, shaderPaint);
1401 }
1403 ///////////////////////////////////////////////////////////////////////////////
1405 #include "SkScalerContext.h"
1406 #include "SkGlyphCache.h"
1407 #include "SkTextToPathIter.h"
1408 #include "SkUtils.h"
1410 static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
1411 const char text[], size_t byteLength, SkVector* stopVector) {
1412 SkFixed x = 0, y = 0;
1413 const char* stop = text + byteLength;
1415 SkAutoKern autokern;
1417 while (text < stop) {
1418 // don't need x, y here, since all subpixel variants will have the
1419 // same advance
1420 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1422 x += autokern.adjust(glyph) + glyph.fAdvanceX;
1423 y += glyph.fAdvanceY;
1424 }
1425 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
1427 SkASSERT(text == stop);
1428 }
1430 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) {
1431 // hairline glyphs are fast enough so we don't need to cache them
1432 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1433 return true;
1434 }
1436 // we don't cache perspective
1437 if (ctm.hasPerspective()) {
1438 return true;
1439 }
1441 SkMatrix textM;
1442 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM));
1443 }
1445 void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1446 SkScalar x, SkScalar y,
1447 const SkPaint& paint) const {
1448 SkDEBUGCODE(this->validate();)
1450 SkTextToPathIter iter(text, byteLength, paint, true);
1452 SkMatrix matrix;
1453 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1454 matrix.postTranslate(x, y);
1456 const SkPath* iterPath;
1457 SkScalar xpos, prevXPos = 0;
1459 while (iter.next(&iterPath, &xpos)) {
1460 matrix.postTranslate(xpos - prevXPos, 0);
1461 if (iterPath) {
1462 const SkPaint& pnt = iter.getPaint();
1463 if (fDevice) {
1464 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false);
1465 } else {
1466 this->drawPath(*iterPath, pnt, &matrix, false);
1467 }
1468 }
1469 prevXPos = xpos;
1470 }
1471 }
1473 // disable warning : local variable used without having been initialized
1474 #if defined _WIN32 && _MSC_VER >= 1300
1475 #pragma warning ( push )
1476 #pragma warning ( disable : 4701 )
1477 #endif
1479 //////////////////////////////////////////////////////////////////////////////
1481 static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
1482 SkFixed fx, SkFixed fy,
1483 const SkGlyph& glyph) {
1484 int left = SkFixedFloorToInt(fx);
1485 int top = SkFixedFloorToInt(fy);
1486 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1487 SkASSERT(NULL == state.fBounder);
1488 SkASSERT((NULL == state.fClip && state.fAAClip) ||
1489 (state.fClip && NULL == state.fAAClip && state.fClip->isRect()));
1491 left += glyph.fLeft;
1492 top += glyph.fTop;
1494 int right = left + glyph.fWidth;
1495 int bottom = top + glyph.fHeight;
1497 SkMask mask;
1498 SkIRect storage;
1499 SkIRect* bounds = &mask.fBounds;
1501 mask.fBounds.set(left, top, right, bottom);
1503 // this extra test is worth it, assuming that most of the time it succeeds
1504 // since we can avoid writing to storage
1505 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
1506 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
1507 return;
1508 bounds = &storage;
1509 }
1511 uint8_t* aa = (uint8_t*)glyph.fImage;
1512 if (NULL == aa) {
1513 aa = (uint8_t*)state.fCache->findImage(glyph);
1514 if (NULL == aa) {
1515 return; // can't rasterize glyph
1516 }
1517 }
1519 mask.fRowBytes = glyph.rowBytes();
1520 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1521 mask.fImage = aa;
1522 state.blitMask(mask, *bounds);
1523 }
1525 static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
1526 SkFixed fx, SkFixed fy,
1527 const SkGlyph& glyph) {
1528 int left = SkFixedFloorToInt(fx);
1529 int top = SkFixedFloorToInt(fy);
1530 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1531 SkASSERT(!state.fClip->isRect());
1532 SkASSERT(NULL == state.fBounder);
1534 SkMask mask;
1536 left += glyph.fLeft;
1537 top += glyph.fTop;
1539 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1540 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1542 if (!clipper.done()) {
1543 const SkIRect& cr = clipper.rect();
1544 const uint8_t* aa = (const uint8_t*)glyph.fImage;
1545 if (NULL == aa) {
1546 aa = (uint8_t*)state.fCache->findImage(glyph);
1547 if (NULL == aa) {
1548 return;
1549 }
1550 }
1552 mask.fRowBytes = glyph.rowBytes();
1553 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1554 mask.fImage = (uint8_t*)aa;
1555 do {
1556 state.blitMask(mask, cr);
1557 clipper.next();
1558 } while (!clipper.done());
1559 }
1560 }
1562 static void D1G_Bounder(const SkDraw1Glyph& state,
1563 SkFixed fx, SkFixed fy,
1564 const SkGlyph& glyph) {
1565 int left = SkFixedFloorToInt(fx);
1566 int top = SkFixedFloorToInt(fy);
1567 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1569 SkMask mask;
1571 left += glyph.fLeft;
1572 top += glyph.fTop;
1574 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1575 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1577 if (!clipper.done()) {
1578 const SkIRect& cr = clipper.rect();
1579 const uint8_t* aa = (const uint8_t*)glyph.fImage;
1580 if (NULL == aa) {
1581 aa = (uint8_t*)state.fCache->findImage(glyph);
1582 if (NULL == aa) {
1583 return;
1584 }
1585 }
1587 // we need to pass the origin, which we approximate with our
1588 // (unadjusted) left,top coordinates (the caller called fixedfloor)
1589 if (state.fBounder->doIRectGlyph(cr,
1590 left - glyph.fLeft,
1591 top - glyph.fTop, glyph)) {
1592 mask.fRowBytes = glyph.rowBytes();
1593 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1594 mask.fImage = (uint8_t*)aa;
1595 do {
1596 state.blitMask(mask, cr);
1597 clipper.next();
1598 } while (!clipper.done());
1599 }
1600 }
1601 }
1603 static void D1G_Bounder_AAClip(const SkDraw1Glyph& state,
1604 SkFixed fx, SkFixed fy,
1605 const SkGlyph& glyph) {
1606 int left = SkFixedFloorToInt(fx);
1607 int top = SkFixedFloorToInt(fy);
1608 SkIRect bounds;
1609 bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1611 if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) {
1612 D1G_NoBounder_RectClip(state, fx, fy, glyph);
1613 }
1614 }
1616 static bool hasCustomD1GProc(const SkDraw& draw) {
1617 return draw.fProcs && draw.fProcs->fD1GProc;
1618 }
1620 static bool needsRasterTextBlit(const SkDraw& draw) {
1621 return !hasCustomD1GProc(draw);
1622 }
1624 SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
1625 SkGlyphCache* cache, const SkPaint& pnt) {
1626 fDraw = draw;
1627 fBounder = draw->fBounder;
1628 fBlitter = blitter;
1629 fCache = cache;
1630 fPaint = &pnt;
1632 if (cache->isSubpixel()) {
1633 fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
1634 } else {
1635 fHalfSampleX = fHalfSampleY = SK_FixedHalf;
1636 }
1638 if (hasCustomD1GProc(*draw)) {
1639 // todo: fix this assumption about clips w/ custom
1640 fClip = draw->fClip;
1641 fClipBounds = fClip->getBounds();
1642 return draw->fProcs->fD1GProc;
1643 }
1645 if (draw->fRC->isBW()) {
1646 fAAClip = NULL;
1647 fClip = &draw->fRC->bwRgn();
1648 fClipBounds = fClip->getBounds();
1649 if (NULL == fBounder) {
1650 if (fClip->isRect()) {
1651 return D1G_NoBounder_RectClip;
1652 } else {
1653 return D1G_NoBounder_RgnClip;
1654 }
1655 } else {
1656 return D1G_Bounder;
1657 }
1658 } else { // aaclip
1659 fAAClip = &draw->fRC->aaRgn();
1660 fClip = NULL;
1661 fClipBounds = fAAClip->getBounds();
1662 if (NULL == fBounder) {
1663 return D1G_NoBounder_RectClip;
1664 } else {
1665 return D1G_Bounder_AAClip;
1666 }
1667 }
1668 }
1670 void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const {
1671 SkASSERT(SkMask::kARGB32_Format == mask.fFormat);
1673 SkBitmap bm;
1674 bm.setConfig(SkBitmap::kARGB_8888_Config,
1675 mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
1676 bm.setPixels((SkPMColor*)mask.fImage);
1678 fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint);
1679 }
1681 ///////////////////////////////////////////////////////////////////////////////
1683 void SkDraw::drawText(const char text[], size_t byteLength,
1684 SkScalar x, SkScalar y, const SkPaint& paint) const {
1685 SkASSERT(byteLength == 0 || text != NULL);
1687 SkDEBUGCODE(this->validate();)
1689 // nothing to draw
1690 if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1691 return;
1692 }
1694 // SkScalarRec doesn't currently have a way of representing hairline stroke and
1695 // will fill if its frame-width is 0.
1696 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1697 this->drawText_asPaths(text, byteLength, x, y, paint);
1698 return;
1699 }
1701 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1703 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix);
1704 SkGlyphCache* cache = autoCache.getCache();
1706 // transform our starting point
1707 {
1708 SkPoint loc;
1709 fMatrix->mapXY(x, y, &loc);
1710 x = loc.fX;
1711 y = loc.fY;
1712 }
1714 // need to measure first
1715 if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1716 SkVector stop;
1718 measure_text(cache, glyphCacheProc, text, byteLength, &stop);
1720 SkScalar stopX = stop.fX;
1721 SkScalar stopY = stop.fY;
1723 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1724 stopX = SkScalarHalf(stopX);
1725 stopY = SkScalarHalf(stopY);
1726 }
1727 x -= stopX;
1728 y -= stopY;
1729 }
1731 const char* stop = text + byteLength;
1733 SkAAClipBlitter aaBlitter;
1734 SkAutoBlitterChoose blitterChooser;
1735 SkBlitter* blitter = NULL;
1736 if (needsRasterTextBlit(*this)) {
1737 blitterChooser.choose(*fBitmap, *fMatrix, paint);
1738 blitter = blitterChooser.get();
1739 if (fRC->isAA()) {
1740 aaBlitter.init(blitter, &fRC->aaRgn());
1741 blitter = &aaBlitter;
1742 }
1743 }
1745 SkAutoKern autokern;
1746 SkDraw1Glyph d1g;
1747 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint);
1749 SkFixed fxMask = ~0;
1750 SkFixed fyMask = ~0;
1751 if (cache->isSubpixel()) {
1752 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix);
1753 if (kX_SkAxisAlignment == baseline) {
1754 fyMask = 0;
1755 d1g.fHalfSampleY = SK_FixedHalf;
1756 } else if (kY_SkAxisAlignment == baseline) {
1757 fxMask = 0;
1758 d1g.fHalfSampleX = SK_FixedHalf;
1759 }
1760 }
1762 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX;
1763 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY;
1765 while (text < stop) {
1766 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
1768 fx += autokern.adjust(glyph);
1770 if (glyph.fWidth) {
1771 proc(d1g, fx, fy, glyph);
1772 }
1774 fx += glyph.fAdvanceX;
1775 fy += glyph.fAdvanceY;
1776 }
1777 }
1779 // last parameter is interpreted as SkFixed [x, y]
1780 // return the fixed position, which may be rounded or not by the caller
1781 // e.g. subpixel doesn't round
1782 typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
1784 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
1785 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
1786 }
1788 static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
1789 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
1790 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
1791 }
1793 static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
1794 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
1795 SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
1796 }
1798 static AlignProc pick_align_proc(SkPaint::Align align) {
1799 static const AlignProc gProcs[] = {
1800 leftAlignProc, centerAlignProc, rightAlignProc
1801 };
1803 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
1805 return gProcs[align];
1806 }
1808 typedef void (*AlignProc_scalar)(const SkPoint&, const SkGlyph&, SkPoint*);
1810 static void leftAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) {
1811 dst->set(loc.fX, loc.fY);
1812 }
1814 static void centerAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) {
1815 dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX >> 1),
1816 loc.fY - SkFixedToScalar(glyph.fAdvanceY >> 1));
1817 }
1819 static void rightAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) {
1820 dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX),
1821 loc.fY - SkFixedToScalar(glyph.fAdvanceY));
1822 }
1824 static AlignProc_scalar pick_align_proc_scalar(SkPaint::Align align) {
1825 static const AlignProc_scalar gProcs[] = {
1826 leftAlignProc_scalar, centerAlignProc_scalar, rightAlignProc_scalar
1827 };
1829 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
1831 return gProcs[align];
1832 }
1834 class TextMapState {
1835 public:
1836 mutable SkPoint fLoc;
1838 TextMapState(const SkMatrix& matrix, SkScalar y)
1839 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
1841 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]);
1843 Proc pickProc(int scalarsPerPosition);
1845 private:
1846 const SkMatrix& fMatrix;
1847 SkMatrix::MapXYProc fProc;
1848 SkScalar fY; // ignored by MapXYProc
1849 // these are only used by Only... procs
1850 SkScalar fScaleX, fTransX, fTransformedY;
1852 static void MapXProc(const TextMapState& state, const SkScalar pos[]) {
1853 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
1854 }
1856 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) {
1857 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
1858 }
1860 static void MapOnlyScaleXProc(const TextMapState& state,
1861 const SkScalar pos[]) {
1862 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
1863 state.fTransformedY);
1864 }
1866 static void MapOnlyTransXProc(const TextMapState& state,
1867 const SkScalar pos[]) {
1868 state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
1869 }
1870 };
1872 TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) {
1873 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1875 if (1 == scalarsPerPosition) {
1876 unsigned mtype = fMatrix.getType();
1877 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
1878 return MapXProc;
1879 } else {
1880 fScaleX = fMatrix.getScaleX();
1881 fTransX = fMatrix.getTranslateX();
1882 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
1883 fMatrix.getTranslateY();
1884 return (mtype & SkMatrix::kScale_Mask) ?
1885 MapOnlyScaleXProc : MapOnlyTransXProc;
1886 }
1887 } else {
1888 return MapXYProc;
1889 }
1890 }
1892 //////////////////////////////////////////////////////////////////////////////
1894 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
1895 const SkScalar pos[], SkScalar constY,
1896 int scalarsPerPosition,
1897 const SkPaint& origPaint) const {
1898 // setup our std paint, in hopes of getting hits in the cache
1899 SkPaint paint(origPaint);
1900 SkScalar matrixScale = paint.setupForAsPaths();
1902 SkMatrix matrix;
1903 matrix.setScale(matrixScale, matrixScale);
1905 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1906 SkAutoGlyphCache autoCache(paint, NULL, NULL);
1907 SkGlyphCache* cache = autoCache.getCache();
1909 const char* stop = text + byteLength;
1910 AlignProc_scalar alignProc = pick_align_proc_scalar(paint.getTextAlign());
1911 TextMapState tms(SkMatrix::I(), constY);
1912 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
1914 while (text < stop) {
1915 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1916 if (glyph.fWidth) {
1917 const SkPath* path = cache->findPath(glyph);
1918 if (path) {
1919 tmsProc(tms, pos);
1920 SkPoint loc;
1921 alignProc(tms.fLoc, glyph, &loc);
1923 matrix[SkMatrix::kMTransX] = loc.fX;
1924 matrix[SkMatrix::kMTransY] = loc.fY;
1925 if (fDevice) {
1926 fDevice->drawPath(*this, *path, paint, &matrix, false);
1927 } else {
1928 this->drawPath(*path, paint, &matrix, false);
1929 }
1930 }
1931 }
1932 pos += scalarsPerPosition;
1933 }
1934 }
1936 void SkDraw::drawPosText(const char text[], size_t byteLength,
1937 const SkScalar pos[], SkScalar constY,
1938 int scalarsPerPosition, const SkPaint& paint) const {
1939 SkASSERT(byteLength == 0 || text != NULL);
1940 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1942 SkDEBUGCODE(this->validate();)
1944 // nothing to draw
1945 if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
1946 return;
1947 }
1949 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1950 this->drawPosText_asPaths(text, byteLength, pos, constY,
1951 scalarsPerPosition, paint);
1952 return;
1953 }
1955 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1956 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix);
1957 SkGlyphCache* cache = autoCache.getCache();
1959 SkAAClipBlitterWrapper wrapper;
1960 SkAutoBlitterChoose blitterChooser;
1961 SkBlitter* blitter = NULL;
1962 if (needsRasterTextBlit(*this)) {
1963 blitterChooser.choose(*fBitmap, *fMatrix, paint);
1964 blitter = blitterChooser.get();
1965 if (fRC->isAA()) {
1966 wrapper.init(*fRC, blitter);
1967 blitter = wrapper.getBlitter();
1968 }
1969 }
1971 const char* stop = text + byteLength;
1972 AlignProc alignProc = pick_align_proc(paint.getTextAlign());
1973 SkDraw1Glyph d1g;
1974 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint);
1975 TextMapState tms(*fMatrix, constY);
1976 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
1978 if (cache->isSubpixel()) {
1979 // maybe we should skip the rounding if linearText is set
1980 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix);
1982 SkFixed fxMask = ~0;
1983 SkFixed fyMask = ~0;
1984 if (kX_SkAxisAlignment == baseline) {
1985 fyMask = 0;
1986 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
1987 d1g.fHalfSampleY = SK_FixedHalf;
1988 #endif
1989 } else if (kY_SkAxisAlignment == baseline) {
1990 fxMask = 0;
1991 #ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
1992 d1g.fHalfSampleX = SK_FixedHalf;
1993 #endif
1994 }
1996 if (SkPaint::kLeft_Align == paint.getTextAlign()) {
1997 while (text < stop) {
1998 tmsProc(tms, pos);
1999 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX;
2000 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY;
2002 const SkGlyph& glyph = glyphCacheProc(cache, &text,
2003 fx & fxMask, fy & fyMask);
2005 if (glyph.fWidth) {
2006 proc(d1g, fx, fy, glyph);
2007 }
2008 pos += scalarsPerPosition;
2009 }
2010 } else {
2011 while (text < stop) {
2012 const char* currentText = text;
2013 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
2015 if (metricGlyph.fWidth) {
2016 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
2017 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
2019 tmsProc(tms, pos);
2020 SkIPoint fixedLoc;
2021 alignProc(tms.fLoc, metricGlyph, &fixedLoc);
2023 SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX;
2024 SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY;
2026 // have to call again, now that we've been "aligned"
2027 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText,
2028 fx & fxMask, fy & fyMask);
2029 // the assumption is that the metrics haven't changed
2030 SkASSERT(prevAdvX == glyph.fAdvanceX);
2031 SkASSERT(prevAdvY == glyph.fAdvanceY);
2032 SkASSERT(glyph.fWidth);
2034 proc(d1g, fx, fy, glyph);
2035 }
2036 pos += scalarsPerPosition;
2037 }
2038 }
2039 } else { // not subpixel
2040 if (SkPaint::kLeft_Align == paint.getTextAlign()) {
2041 while (text < stop) {
2042 // the last 2 parameters are ignored
2043 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
2045 if (glyph.fWidth) {
2046 tmsProc(tms, pos);
2048 proc(d1g,
2049 SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, //d1g.fHalfSampleX,
2050 SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, //d1g.fHalfSampleY,
2051 glyph);
2052 }
2053 pos += scalarsPerPosition;
2054 }
2055 } else {
2056 while (text < stop) {
2057 // the last 2 parameters are ignored
2058 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
2060 if (glyph.fWidth) {
2061 tmsProc(tms, pos);
2063 SkIPoint fixedLoc;
2064 alignProc(tms.fLoc, glyph, &fixedLoc);
2066 proc(d1g,
2067 fixedLoc.fX + SK_FixedHalf, //d1g.fHalfSampleX,
2068 fixedLoc.fY + SK_FixedHalf, //d1g.fHalfSampleY,
2069 glyph);
2070 }
2071 pos += scalarsPerPosition;
2072 }
2073 }
2074 }
2075 }
2077 #if defined _WIN32 && _MSC_VER >= 1300
2078 #pragma warning ( pop )
2079 #endif
2081 ///////////////////////////////////////////////////////////////////////////////
2083 #include "SkPathMeasure.h"
2085 static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
2086 SkPathMeasure& meas, const SkMatrix& matrix) {
2087 SkMatrix::MapXYProc proc = matrix.getMapXYProc();
2089 for (int i = 0; i < count; i++) {
2090 SkPoint pos;
2091 SkVector tangent;
2093 proc(matrix, src[i].fX, src[i].fY, &pos);
2094 SkScalar sx = pos.fX;
2095 SkScalar sy = pos.fY;
2097 if (!meas.getPosTan(sx, &pos, &tangent)) {
2098 // set to 0 if the measure failed, so that we just set dst == pos
2099 tangent.set(0, 0);
2100 }
2102 /* This is the old way (that explains our approach but is way too slow
2103 SkMatrix matrix;
2104 SkPoint pt;
2106 pt.set(sx, sy);
2107 matrix.setSinCos(tangent.fY, tangent.fX);
2108 matrix.preTranslate(-sx, 0);
2109 matrix.postTranslate(pos.fX, pos.fY);
2110 matrix.mapPoints(&dst[i], &pt, 1);
2111 */
2112 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy),
2113 pos.fY + SkScalarMul(tangent.fX, sy));
2114 }
2115 }
2117 /* TODO
2119 Need differentially more subdivisions when the follow-path is curvy. Not sure how to
2120 determine that, but we need it. I guess a cheap answer is let the caller tell us,
2121 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
2122 */
2123 static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
2124 const SkMatrix& matrix) {
2125 SkPath::Iter iter(src, false);
2126 SkPoint srcP[4], dstP[3];
2127 SkPath::Verb verb;
2129 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
2130 switch (verb) {
2131 case SkPath::kMove_Verb:
2132 morphpoints(dstP, srcP, 1, meas, matrix);
2133 dst->moveTo(dstP[0]);
2134 break;
2135 case SkPath::kLine_Verb:
2136 // turn lines into quads to look bendy
2137 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX);
2138 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY);
2139 morphpoints(dstP, srcP, 2, meas, matrix);
2140 dst->quadTo(dstP[0], dstP[1]);
2141 break;
2142 case SkPath::kQuad_Verb:
2143 morphpoints(dstP, &srcP[1], 2, meas, matrix);
2144 dst->quadTo(dstP[0], dstP[1]);
2145 break;
2146 case SkPath::kCubic_Verb:
2147 morphpoints(dstP, &srcP[1], 3, meas, matrix);
2148 dst->cubicTo(dstP[0], dstP[1], dstP[2]);
2149 break;
2150 case SkPath::kClose_Verb:
2151 dst->close();
2152 break;
2153 default:
2154 SkDEBUGFAIL("unknown verb");
2155 break;
2156 }
2157 }
2158 }
2160 void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
2161 const SkPath& follow, const SkMatrix* matrix,
2162 const SkPaint& paint) const {
2163 SkASSERT(byteLength == 0 || text != NULL);
2165 // nothing to draw
2166 if (text == NULL || byteLength == 0 || fRC->isEmpty()) {
2167 return;
2168 }
2170 SkTextToPathIter iter(text, byteLength, paint, true);
2171 SkPathMeasure meas(follow, false);
2172 SkScalar hOffset = 0;
2174 // need to measure first
2175 if (paint.getTextAlign() != SkPaint::kLeft_Align) {
2176 SkScalar pathLen = meas.getLength();
2177 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
2178 pathLen = SkScalarHalf(pathLen);
2179 }
2180 hOffset += pathLen;
2181 }
2183 const SkPath* iterPath;
2184 SkScalar xpos;
2185 SkMatrix scaledMatrix;
2186 SkScalar scale = iter.getPathScale();
2188 scaledMatrix.setScale(scale, scale);
2190 while (iter.next(&iterPath, &xpos)) {
2191 if (iterPath) {
2192 SkPath tmp;
2193 SkMatrix m(scaledMatrix);
2195 m.postTranslate(xpos + hOffset, 0);
2196 if (matrix) {
2197 m.postConcat(*matrix);
2198 }
2199 morphpath(&tmp, *iterPath, meas, m);
2200 if (fDevice) {
2201 fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true);
2202 } else {
2203 this->drawPath(tmp, iter.getPaint(), NULL, true);
2204 }
2205 }
2206 }
2207 }
2209 ///////////////////////////////////////////////////////////////////////////////
2211 struct VertState {
2212 int f0, f1, f2;
2214 VertState(int vCount, const uint16_t indices[], int indexCount)
2215 : fIndices(indices) {
2216 fCurrIndex = 0;
2217 if (indices) {
2218 fCount = indexCount;
2219 } else {
2220 fCount = vCount;
2221 }
2222 }
2224 typedef bool (*Proc)(VertState*);
2225 Proc chooseProc(SkCanvas::VertexMode mode);
2227 private:
2228 int fCount;
2229 int fCurrIndex;
2230 const uint16_t* fIndices;
2232 static bool Triangles(VertState*);
2233 static bool TrianglesX(VertState*);
2234 static bool TriangleStrip(VertState*);
2235 static bool TriangleStripX(VertState*);
2236 static bool TriangleFan(VertState*);
2237 static bool TriangleFanX(VertState*);
2238 };
2240 bool VertState::Triangles(VertState* state) {
2241 int index = state->fCurrIndex;
2242 if (index + 3 > state->fCount) {
2243 return false;
2244 }
2245 state->f0 = index + 0;
2246 state->f1 = index + 1;
2247 state->f2 = index + 2;
2248 state->fCurrIndex = index + 3;
2249 return true;
2250 }
2252 bool VertState::TrianglesX(VertState* state) {
2253 const uint16_t* indices = state->fIndices;
2254 int index = state->fCurrIndex;
2255 if (index + 3 > state->fCount) {
2256 return false;
2257 }
2258 state->f0 = indices[index + 0];
2259 state->f1 = indices[index + 1];
2260 state->f2 = indices[index + 2];
2261 state->fCurrIndex = index + 3;
2262 return true;
2263 }
2265 bool VertState::TriangleStrip(VertState* state) {
2266 int index = state->fCurrIndex;
2267 if (index + 3 > state->fCount) {
2268 return false;
2269 }
2270 state->f2 = index + 2;
2271 if (index & 1) {
2272 state->f0 = index + 1;
2273 state->f1 = index + 0;
2274 } else {
2275 state->f0 = index + 0;
2276 state->f1 = index + 1;
2277 }
2278 state->fCurrIndex = index + 1;
2279 return true;
2280 }
2282 bool VertState::TriangleStripX(VertState* state) {
2283 const uint16_t* indices = state->fIndices;
2284 int index = state->fCurrIndex;
2285 if (index + 3 > state->fCount) {
2286 return false;
2287 }
2288 state->f2 = indices[index + 2];
2289 if (index & 1) {
2290 state->f0 = indices[index + 1];
2291 state->f1 = indices[index + 0];
2292 } else {
2293 state->f0 = indices[index + 0];
2294 state->f1 = indices[index + 1];
2295 }
2296 state->fCurrIndex = index + 1;
2297 return true;
2298 }
2300 bool VertState::TriangleFan(VertState* state) {
2301 int index = state->fCurrIndex;
2302 if (index + 3 > state->fCount) {
2303 return false;
2304 }
2305 state->f0 = 0;
2306 state->f1 = index + 1;
2307 state->f2 = index + 2;
2308 state->fCurrIndex = index + 1;
2309 return true;
2310 }
2312 bool VertState::TriangleFanX(VertState* state) {
2313 const uint16_t* indices = state->fIndices;
2314 int index = state->fCurrIndex;
2315 if (index + 3 > state->fCount) {
2316 return false;
2317 }
2318 state->f0 = indices[0];
2319 state->f1 = indices[index + 1];
2320 state->f2 = indices[index + 2];
2321 state->fCurrIndex = index + 1;
2322 return true;
2323 }
2325 VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
2326 switch (mode) {
2327 case SkCanvas::kTriangles_VertexMode:
2328 return fIndices ? TrianglesX : Triangles;
2329 case SkCanvas::kTriangleStrip_VertexMode:
2330 return fIndices ? TriangleStripX : TriangleStrip;
2331 case SkCanvas::kTriangleFan_VertexMode:
2332 return fIndices ? TriangleFanX : TriangleFan;
2333 default:
2334 return NULL;
2335 }
2336 }
2338 typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&,
2339 SkBlitter*);
2341 static HairProc ChooseHairProc(bool doAntiAlias) {
2342 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
2343 }
2345 static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
2346 const SkPoint texs[], SkMatrix* matrix) {
2347 SkPoint src[3], dst[3];
2349 src[0] = texs[state.f0];
2350 src[1] = texs[state.f1];
2351 src[2] = texs[state.f2];
2352 dst[0] = verts[state.f0];
2353 dst[1] = verts[state.f1];
2354 dst[2] = verts[state.f2];
2355 return matrix->setPolyToPoly(src, dst, 3);
2356 }
2358 class SkTriColorShader : public SkShader {
2359 public:
2360 SkTriColorShader() {}
2362 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
2364 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE;
2366 SK_TO_STRING_OVERRIDE()
2367 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader)
2369 protected:
2370 SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {}
2372 private:
2373 SkMatrix fDstToUnit;
2374 SkPMColor fColors[3];
2376 typedef SkShader INHERITED;
2377 };
2379 bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
2380 int index0, int index1, int index2) {
2382 fColors[0] = SkPreMultiplyColor(colors[index0]);
2383 fColors[1] = SkPreMultiplyColor(colors[index1]);
2384 fColors[2] = SkPreMultiplyColor(colors[index2]);
2386 SkMatrix m, im;
2387 m.reset();
2388 m.set(0, pts[index1].fX - pts[index0].fX);
2389 m.set(1, pts[index2].fX - pts[index0].fX);
2390 m.set(2, pts[index0].fX);
2391 m.set(3, pts[index1].fY - pts[index0].fY);
2392 m.set(4, pts[index2].fY - pts[index0].fY);
2393 m.set(5, pts[index0].fY);
2394 if (!m.invert(&im)) {
2395 return false;
2396 }
2397 return fDstToUnit.setConcat(im, this->getTotalInverse());
2398 }
2400 #include "SkColorPriv.h"
2401 #include "SkComposeShader.h"
2403 static int ScalarTo256(SkScalar v) {
2404 int scale = SkScalarToFixed(v) >> 8;
2405 if (scale < 0) {
2406 scale = 0;
2407 }
2408 if (scale > 255) {
2409 scale = 255;
2410 }
2411 return SkAlpha255To256(scale);
2412 }
2414 void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
2415 SkPoint src;
2417 for (int i = 0; i < count; i++) {
2418 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
2419 x += 1;
2421 int scale1 = ScalarTo256(src.fX);
2422 int scale2 = ScalarTo256(src.fY);
2423 int scale0 = 256 - scale1 - scale2;
2424 if (scale0 < 0) {
2425 if (scale1 > scale2) {
2426 scale2 = 256 - scale1;
2427 } else {
2428 scale1 = 256 - scale2;
2429 }
2430 scale0 = 0;
2431 }
2433 dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
2434 SkAlphaMulQ(fColors[1], scale1) +
2435 SkAlphaMulQ(fColors[2], scale2);
2436 }
2437 }
2439 #ifndef SK_IGNORE_TO_STRING
2440 void SkTriColorShader::toString(SkString* str) const {
2441 str->append("SkTriColorShader: (");
2443 this->INHERITED::toString(str);
2445 str->append(")");
2446 }
2447 #endif
2449 void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
2450 const SkPoint vertices[], const SkPoint textures[],
2451 const SkColor colors[], SkXfermode* xmode,
2452 const uint16_t indices[], int indexCount,
2453 const SkPaint& paint) const {
2454 SkASSERT(0 == count || NULL != vertices);
2456 // abort early if there is nothing to draw
2457 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) {
2458 return;
2459 }
2461 // transform out vertices into device coordinates
2462 SkAutoSTMalloc<16, SkPoint> storage(count);
2463 SkPoint* devVerts = storage.get();
2464 fMatrix->mapPoints(devVerts, vertices, count);
2466 if (fBounder) {
2467 SkRect bounds;
2468 bounds.set(devVerts, count);
2469 if (!fBounder->doRect(bounds, paint)) {
2470 return;
2471 }
2472 }
2474 /*
2475 We can draw the vertices in 1 of 4 ways:
2477 - solid color (no shader/texture[], no colors[])
2478 - just colors (no shader/texture[], has colors[])
2479 - just texture (has shader/texture[], no colors[])
2480 - colors * texture (has shader/texture[], has colors[])
2482 Thus for texture drawing, we need both texture[] and a shader.
2483 */
2485 SkTriColorShader triShader; // must be above declaration of p
2486 SkPaint p(paint);
2488 SkShader* shader = p.getShader();
2489 if (NULL == shader) {
2490 // if we have no shader, we ignore the texture coordinates
2491 textures = NULL;
2492 } else if (NULL == textures) {
2493 // if we don't have texture coordinates, ignore the shader
2494 p.setShader(NULL);
2495 shader = NULL;
2496 }
2498 // setup the custom shader (if needed)
2499 if (NULL != colors) {
2500 if (NULL == textures) {
2501 // just colors (no texture)
2502 shader = p.setShader(&triShader);
2503 } else {
2504 // colors * texture
2505 SkASSERT(shader);
2506 bool releaseMode = false;
2507 if (NULL == xmode) {
2508 xmode = SkXfermode::Create(SkXfermode::kModulate_Mode);
2509 releaseMode = true;
2510 }
2511 SkShader* compose = SkNEW_ARGS(SkComposeShader,
2512 (&triShader, shader, xmode));
2513 p.setShader(compose)->unref();
2514 if (releaseMode) {
2515 xmode->unref();
2516 }
2517 }
2518 }
2520 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
2521 // important that we abort early, as below we may manipulate the shader
2522 // and that is only valid if the shader returned true from setContext.
2523 // If it returned false, then our blitter will be the NullBlitter.
2524 if (blitter->isNullBlitter()) {
2525 return;
2526 }
2528 // setup our state and function pointer for iterating triangles
2529 VertState state(count, indices, indexCount);
2530 VertState::Proc vertProc = state.chooseProc(vmode);
2532 if (NULL != textures || NULL != colors) {
2533 SkMatrix tempM;
2534 SkMatrix savedLocalM;
2535 if (shader) {
2536 savedLocalM = shader->getLocalMatrix();
2537 }
2539 // setContext has already been called and verified to return true
2540 // by the constructor of SkAutoBlitterChoose
2541 bool prevContextSuccess = true;
2542 while (vertProc(&state)) {
2543 if (NULL != textures) {
2544 if (texture_to_matrix(state, vertices, textures, &tempM)) {
2545 tempM.postConcat(savedLocalM);
2546 shader->setLocalMatrix(tempM);
2547 // Need to recall setContext since we changed the local matrix.
2548 // However, we also need to balance the calls this with a
2549 // call to endContext which requires tracking the result of
2550 // the previous call to setContext.
2551 if (prevContextSuccess) {
2552 shader->endContext();
2553 }
2554 prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix);
2555 if (!prevContextSuccess) {
2556 continue;
2557 }
2558 }
2559 }
2560 if (NULL != colors) {
2561 if (!triShader.setup(vertices, colors,
2562 state.f0, state.f1, state.f2)) {
2563 continue;
2564 }
2565 }
2567 SkPoint tmp[] = {
2568 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2]
2569 };
2570 SkScan::FillTriangle(tmp, *fRC, blitter.get());
2571 }
2573 // now restore the shader's original local matrix
2574 if (NULL != shader) {
2575 shader->setLocalMatrix(savedLocalM);
2576 }
2578 // If the final call to setContext fails we must make it suceed so that the
2579 // call to endContext in the destructor for SkAutoBlitterChoose is balanced.
2580 if (!prevContextSuccess) {
2581 prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I());
2582 SkASSERT(prevContextSuccess);
2583 }
2584 } else {
2585 // no colors[] and no texture
2586 HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
2587 const SkRasterClip& clip = *fRC;
2588 while (vertProc(&state)) {
2589 hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get());
2590 hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get());
2591 hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get());
2592 }
2593 }
2594 }
2596 ///////////////////////////////////////////////////////////////////////////////
2597 ///////////////////////////////////////////////////////////////////////////////
2599 #ifdef SK_DEBUG
2601 void SkDraw::validate() const {
2602 SkASSERT(fBitmap != NULL);
2603 SkASSERT(fMatrix != NULL);
2604 SkASSERT(fClip != NULL);
2605 SkASSERT(fRC != NULL);
2607 const SkIRect& cr = fRC->getBounds();
2608 SkIRect br;
2610 br.set(0, 0, fBitmap->width(), fBitmap->height());
2611 SkASSERT(cr.isEmpty() || br.contains(cr));
2612 }
2614 #endif
2616 ///////////////////////////////////////////////////////////////////////////////
2618 SkBounder::SkBounder() {
2619 // initialize up front. This gets reset by SkCanvas before each draw call.
2620 fClip = &SkRegion::GetEmptyRegion();
2621 }
2623 bool SkBounder::doIRect(const SkIRect& r) {
2624 SkIRect rr;
2625 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr);
2626 }
2628 // TODO: change the prototype to take fixed, and update the callers
2629 bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y,
2630 const SkGlyph& glyph) {
2631 SkIRect rr;
2632 if (!rr.intersect(fClip->getBounds(), r)) {
2633 return false;
2634 }
2635 GlyphRec rec;
2636 rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y));
2637 rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX,
2638 rec.fLSB.fY + glyph.fAdvanceY);
2639 rec.fGlyphID = glyph.getGlyphID();
2640 rec.fFlags = 0;
2641 return this->onIRectGlyph(rr, rec);
2642 }
2644 bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1,
2645 const SkPaint& paint) {
2646 SkIRect r;
2647 SkScalar v0, v1;
2649 v0 = pt0.fX;
2650 v1 = pt1.fX;
2651 if (v0 > v1) {
2652 SkTSwap<SkScalar>(v0, v1);
2653 }
2654 r.fLeft = SkScalarFloorToInt(v0);
2655 r.fRight = SkScalarCeilToInt(v1);
2657 v0 = pt0.fY;
2658 v1 = pt1.fY;
2659 if (v0 > v1) {
2660 SkTSwap<SkScalar>(v0, v1);
2661 }
2662 r.fTop = SkScalarFloorToInt(v0);
2663 r.fBottom = SkScalarCeilToInt(v1);
2665 if (paint.isAntiAlias()) {
2666 r.inset(-1, -1);
2667 }
2668 return this->doIRect(r);
2669 }
2671 bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) {
2672 SkIRect r;
2674 if (paint.getStyle() == SkPaint::kFill_Style) {
2675 rect.round(&r);
2676 } else {
2677 int rad = -1;
2678 rect.roundOut(&r);
2679 if (paint.isAntiAlias()) {
2680 rad = -2;
2681 }
2682 r.inset(rad, rad);
2683 }
2684 return this->doIRect(r);
2685 }
2687 bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) {
2688 SkIRect r;
2689 const SkRect& bounds = path.getBounds();
2691 if (doFill) {
2692 bounds.round(&r);
2693 } else { // hairline
2694 bounds.roundOut(&r);
2695 }
2697 if (paint.isAntiAlias()) {
2698 r.inset(-1, -1);
2699 }
2700 return this->doIRect(r);
2701 }
2703 void SkBounder::commit() {
2704 // override in subclass
2705 }
2707 ////////////////////////////////////////////////////////////////////////////////////////////////
2709 #include "SkPath.h"
2710 #include "SkDraw.h"
2711 #include "SkRegion.h"
2712 #include "SkBlitter.h"
2714 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2715 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2716 SkIRect* bounds) {
2717 if (devPath.isEmpty()) {
2718 return false;
2719 }
2721 // init our bounds from the path
2722 {
2723 SkRect pathBounds = devPath.getBounds();
2724 pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
2725 pathBounds.roundOut(bounds);
2726 }
2728 SkIPoint margin = SkIPoint::Make(0, 0);
2729 if (filter) {
2730 SkASSERT(filterMatrix);
2732 SkMask srcM, dstM;
2734 srcM.fBounds = *bounds;
2735 srcM.fFormat = SkMask::kA8_Format;
2736 srcM.fImage = NULL;
2737 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2738 return false;
2739 }
2740 }
2742 // (possibly) trim the bounds to reflect the clip
2743 // (plus whatever slop the filter needs)
2744 if (clipBounds) {
2745 SkIRect tmp = *clipBounds;
2746 // Ugh. Guard against gigantic margins from wacky filters. Without this
2747 // check we can request arbitrary amounts of slop beyond our visible
2748 // clip, and bring down the renderer (at least on finite RAM machines
2749 // like handsets, etc.). Need to balance this invented value between
2750 // quality of large filters like blurs, and the corresponding memory
2751 // requests.
2752 static const int MAX_MARGIN = 128;
2753 tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
2754 -SkMin32(margin.fY, MAX_MARGIN));
2755 if (!bounds->intersect(tmp)) {
2756 return false;
2757 }
2758 }
2760 return true;
2761 }
2763 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
2764 SkPaint::Style style) {
2765 SkBitmap bm;
2766 SkDraw draw;
2767 SkRasterClip clip;
2768 SkMatrix matrix;
2769 SkPaint paint;
2771 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
2772 bm.setPixels(mask.fImage);
2774 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
2775 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2776 -SkIntToScalar(mask.fBounds.fTop));
2778 draw.fBitmap = &bm;
2779 draw.fRC = &clip;
2780 draw.fClip = &clip.bwRgn();
2781 draw.fMatrix = &matrix;
2782 draw.fBounder = NULL;
2783 paint.setAntiAlias(true);
2784 paint.setStyle(style);
2785 draw.drawPath(devPath, paint);
2786 }
2788 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2789 const SkMaskFilter* filter, const SkMatrix* filterMatrix,
2790 SkMask* mask, SkMask::CreateMode mode,
2791 SkPaint::Style style) {
2792 if (SkMask::kJustRenderImage_CreateMode != mode) {
2793 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2794 return false;
2795 }
2797 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2798 mask->fFormat = SkMask::kA8_Format;
2799 mask->fRowBytes = mask->fBounds.width();
2800 size_t size = mask->computeImageSize();
2801 if (0 == size) {
2802 // we're too big to allocate the mask, abort
2803 return false;
2804 }
2805 mask->fImage = SkMask::AllocImage(size);
2806 memset(mask->fImage, 0, mask->computeImageSize());
2807 }
2809 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2810 draw_into_mask(*mask, devPath, style);
2811 }
2813 return true;
2814 }