|
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 */ |
|
7 |
|
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" |
|
29 |
|
30 #include "SkAutoKern.h" |
|
31 #include "SkBitmapProcShader.h" |
|
32 #include "SkDrawProcs.h" |
|
33 #include "SkMatrixUtils.h" |
|
34 |
|
35 |
|
36 //#define TRACE_BITMAP_DRAWS |
|
37 |
|
38 |
|
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 } |
|
51 |
|
52 SkBlitter* operator->() { return fBlitter; } |
|
53 SkBlitter* get() const { return fBlitter; } |
|
54 |
|
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 } |
|
60 |
|
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) |
|
67 |
|
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 } |
|
83 |
|
84 ~SkAutoBitmapShaderInstall() { |
|
85 // since fAllocator will destroy shader, we insist that owners == 2 |
|
86 SkASSERT(2 == fPaint.getShader()->getRefCnt()); |
|
87 |
|
88 fPaint.setShader(NULL); // unref the shader by 1 |
|
89 |
|
90 } |
|
91 |
|
92 // return the new paint that has the shader applied |
|
93 const SkPaint& paintWithShader() const { return fPaint; } |
|
94 |
|
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) |
|
102 |
|
103 /////////////////////////////////////////////////////////////////////////////// |
|
104 |
|
105 SkDraw::SkDraw() { |
|
106 sk_bzero(this, sizeof(*this)); |
|
107 } |
|
108 |
|
109 SkDraw::SkDraw(const SkDraw& src) { |
|
110 memcpy(this, &src, sizeof(*this)); |
|
111 } |
|
112 |
|
113 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { |
|
114 if (fRC->isEmpty()) { |
|
115 return false; |
|
116 } |
|
117 |
|
118 SkMatrix inverse; |
|
119 if (!fMatrix->invert(&inverse)) { |
|
120 return false; |
|
121 } |
|
122 |
|
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 } |
|
129 |
|
130 /////////////////////////////////////////////////////////////////////////////// |
|
131 |
|
132 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); |
|
133 |
|
134 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { |
|
135 sk_bzero(pixels, bytes); |
|
136 } |
|
137 |
|
138 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} |
|
139 |
|
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 } |
|
143 |
|
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 } |
|
147 |
|
148 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { |
|
149 memset(pixels, data, bytes); |
|
150 } |
|
151 |
|
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 } |
|
160 |
|
161 SkXfermode::Mode mode; |
|
162 if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { |
|
163 return NULL; |
|
164 } |
|
165 |
|
166 SkColor color = paint.getColor(); |
|
167 |
|
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 } |
|
177 |
|
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 } |
|
219 |
|
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 } |
|
237 |
|
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; |
|
242 |
|
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 } |
|
250 |
|
251 void SkDraw::drawPaint(const SkPaint& paint) const { |
|
252 SkDEBUGCODE(this->validate();) |
|
253 |
|
254 if (fRC->isEmpty()) { |
|
255 return; |
|
256 } |
|
257 |
|
258 SkIRect devRect; |
|
259 devRect.set(0, 0, fBitmap->width(), fBitmap->height()); |
|
260 if (fBounder && !fBounder->doIRect(devRect)) { |
|
261 return; |
|
262 } |
|
263 |
|
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 } |
|
277 |
|
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 } |
|
286 |
|
287 // normal case: use a blitter |
|
288 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); |
|
289 SkScan::FillIRect(devRect, *fRC, blitter.get()); |
|
290 } |
|
291 |
|
292 /////////////////////////////////////////////////////////////////////////////// |
|
293 |
|
294 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 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(); |
|
318 |
|
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 } |
|
327 |
|
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); |
|
336 |
|
337 uint16_t* addr = bitmap->getAddr16(0, 0); |
|
338 size_t rb = bitmap->rowBytes(); |
|
339 |
|
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 } |
|
348 |
|
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); |
|
357 |
|
358 SkPMColor* addr = bitmap->getAddr32(0, 0); |
|
359 size_t rb = bitmap->rowBytes(); |
|
360 |
|
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 } |
|
369 |
|
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 } |
|
380 |
|
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 } |
|
387 |
|
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 } |
|
394 |
|
395 // aa versions |
|
396 |
|
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 } |
|
403 |
|
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 } |
|
410 |
|
411 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) |
|
412 |
|
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); |
|
419 |
|
420 SkXRect r; |
|
421 r.fLeft = x - radius; |
|
422 r.fTop = y - radius; |
|
423 r.fRight = x + radius; |
|
424 r.fBottom = y + radius; |
|
425 |
|
426 SkScan::FillXRect(r, *rec.fRC, blitter); |
|
427 } |
|
428 } |
|
429 |
|
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); |
|
436 |
|
437 SkXRect r; |
|
438 r.fLeft = x - radius; |
|
439 r.fTop = y - radius; |
|
440 r.fRight = x + radius; |
|
441 r.fBottom = y + radius; |
|
442 |
|
443 SkScan::AntiFillXRect(r, *rec.fRC, blitter); |
|
444 } |
|
445 } |
|
446 |
|
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 } |
|
470 |
|
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 } |
|
481 |
|
482 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { |
|
483 Proc proc = NULL; |
|
484 |
|
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 } |
|
494 |
|
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); |
|
500 |
|
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 } |
|
535 |
|
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(); |
|
542 |
|
543 bounds.set(pts, SkToInt(count)); |
|
544 bounds.inset(-inset, -inset); |
|
545 matrix.mapRect(&bounds); |
|
546 |
|
547 bounds.roundOut(&ibounds); |
|
548 return bounder->doIRect(ibounds); |
|
549 } |
|
550 |
|
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 |
|
554 |
|
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 } |
|
562 |
|
563 if ((long)count <= 0) { |
|
564 return; |
|
565 } |
|
566 |
|
567 SkASSERT(pts != NULL); |
|
568 SkDEBUGCODE(this->validate();) |
|
569 |
|
570 // nothing to draw |
|
571 if (fRC->isEmpty()) { |
|
572 return; |
|
573 } |
|
574 |
|
575 if (fBounder) { |
|
576 if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) { |
|
577 return; |
|
578 } |
|
579 |
|
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 } |
|
587 |
|
588 PtProcRec rec; |
|
589 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { |
|
590 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); |
|
591 |
|
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); |
|
598 |
|
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); |
|
619 |
|
620 SkScalar width = newPaint.getStrokeWidth(); |
|
621 SkScalar radius = SkScalarHalf(width); |
|
622 |
|
623 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { |
|
624 SkPath path; |
|
625 SkMatrix preMatrix; |
|
626 |
|
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; |
|
642 |
|
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; |
|
664 |
|
665 SkPath path; |
|
666 path.moveTo(pts[0]); |
|
667 path.lineTo(pts[1]); |
|
668 |
|
669 SkRect cullRect = SkRect::Make(fRC->getBounds()); |
|
670 |
|
671 if (paint.getPathEffect()->asPoints(&pointData, path, rec, |
|
672 *fMatrix, &cullRect)) { |
|
673 // 'asPoints' managed to find some fast path |
|
674 |
|
675 SkPaint newP(paint); |
|
676 newP.setPathEffect(NULL); |
|
677 newP.setStyle(SkPaint::kFill_Style); |
|
678 |
|
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 } |
|
686 |
|
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 } |
|
694 |
|
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())); |
|
698 |
|
699 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { |
|
700 newP.setStrokeCap(SkPaint::kRound_Cap); |
|
701 } else { |
|
702 newP.setStrokeCap(SkPaint::kButt_Cap); |
|
703 } |
|
704 |
|
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)); |
|
723 |
|
724 SkRect r; |
|
725 |
|
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 } |
|
738 |
|
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 } |
|
765 |
|
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 } |
|
772 |
|
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 } |
|
780 |
|
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(); |
|
788 |
|
789 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { |
|
790 style = SkPaint::kFill_Style; |
|
791 } |
|
792 |
|
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 } |
|
808 |
|
809 static const SkPoint* rect_points(const SkRect& r) { |
|
810 return SkTCast<const SkPoint*>(&r); |
|
811 } |
|
812 |
|
813 static SkPoint* rect_points(SkRect& r) { |
|
814 return SkTCast<SkPoint*>(&r); |
|
815 } |
|
816 |
|
817 void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { |
|
818 SkDEBUGCODE(this->validate();) |
|
819 |
|
820 // nothing to draw |
|
821 if (fRC->isEmpty()) { |
|
822 return; |
|
823 } |
|
824 |
|
825 SkPoint strokeSize; |
|
826 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); |
|
827 |
|
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 } |
|
835 |
|
836 const SkMatrix& matrix = *fMatrix; |
|
837 SkRect devRect; |
|
838 |
|
839 // transform rect into devRect |
|
840 matrix.mapPoints(rect_points(devRect), rect_points(rect), 2); |
|
841 devRect.sort(); |
|
842 |
|
843 if (fBounder && !fBounder->doRect(devRect, paint)) { |
|
844 return; |
|
845 } |
|
846 |
|
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 } |
|
857 |
|
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); |
|
864 |
|
865 SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix, |
|
866 paint); |
|
867 const SkRasterClip& clip = looper.getRC(); |
|
868 SkBlitter* blitter = blitterStorage.get(); |
|
869 |
|
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 } |
|
900 |
|
901 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { |
|
902 if (srcM.fBounds.isEmpty()) { |
|
903 return; |
|
904 } |
|
905 |
|
906 const SkMask* mask = &srcM; |
|
907 |
|
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); |
|
916 |
|
917 if (fBounder && !fBounder->doIRect(mask->fBounds)) { |
|
918 return; |
|
919 } |
|
920 |
|
921 SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint); |
|
922 SkBlitter* blitter = blitterChooser.get(); |
|
923 |
|
924 SkAAClipBlitterWrapper wrapper; |
|
925 const SkRegion* clipRgn; |
|
926 |
|
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 } |
|
936 |
|
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 } |
|
945 |
|
946 static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) { |
|
947 SkXfermode::Coeff dc; |
|
948 if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) { |
|
949 return false; |
|
950 } |
|
951 |
|
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 } |
|
961 |
|
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. |
|
966 |
|
967 if (matrix.hasPerspective()) { |
|
968 return false; |
|
969 } |
|
970 |
|
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 } |
|
985 |
|
986 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { |
|
987 SkDEBUGCODE(this->validate()); |
|
988 |
|
989 if (fRC->isEmpty()) { |
|
990 return; |
|
991 } |
|
992 |
|
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 } |
|
1001 |
|
1002 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { |
|
1003 goto DRAW_PATH; |
|
1004 } |
|
1005 |
|
1006 if (paint.getRasterizer()) { |
|
1007 goto DRAW_PATH; |
|
1008 } |
|
1009 } |
|
1010 |
|
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 } |
|
1023 |
|
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 } |
|
1030 |
|
1031 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, |
|
1032 const SkMatrix* prePathMatrix, bool pathIsMutable, |
|
1033 bool drawCoverage) const { |
|
1034 SkDEBUGCODE(this->validate();) |
|
1035 |
|
1036 // nothing to draw |
|
1037 if (fRC->isEmpty()) { |
|
1038 return; |
|
1039 } |
|
1040 |
|
1041 SkPath* pathPtr = (SkPath*)&origSrcPath; |
|
1042 bool doFill = true; |
|
1043 SkPath tmpPath; |
|
1044 SkMatrix tmpMatrix; |
|
1045 const SkMatrix* matrix = fMatrix; |
|
1046 |
|
1047 if (prePathMatrix) { |
|
1048 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || |
|
1049 origPaint.getRasterizer()) { |
|
1050 SkPath* result = pathPtr; |
|
1051 |
|
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;) |
|
1068 |
|
1069 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); |
|
1070 |
|
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 } |
|
1094 |
|
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 } |
|
1104 |
|
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 } |
|
1115 |
|
1116 // avoid possibly allocating a new path in transform if we can |
|
1117 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; |
|
1118 |
|
1119 // transform the path into device space |
|
1120 pathPtr->transform(*matrix, devPathPtr); |
|
1121 |
|
1122 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint, drawCoverage); |
|
1123 |
|
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 } |
|
1133 |
|
1134 if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) { |
|
1135 return; |
|
1136 } |
|
1137 |
|
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 } |
|
1154 |
|
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 } |
|
1163 |
|
1164 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, |
|
1165 const SkPaint& paint) const { |
|
1166 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); |
|
1167 |
|
1168 if (just_translate(*fMatrix, bitmap)) { |
|
1169 int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); |
|
1170 int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); |
|
1171 |
|
1172 SkAutoLockPixels alp(bitmap); |
|
1173 if (!bitmap.readyToDraw()) { |
|
1174 return; |
|
1175 } |
|
1176 |
|
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); |
|
1182 |
|
1183 this->drawDevMask(mask, paint); |
|
1184 } else { // need to xform the bitmap first |
|
1185 SkRect r; |
|
1186 SkMask mask; |
|
1187 |
|
1188 r.set(0, 0, |
|
1189 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); |
|
1190 fMatrix->mapRect(&r); |
|
1191 r.round(&mask.fBounds); |
|
1192 |
|
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 } |
|
1203 |
|
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 } |
|
1211 |
|
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); |
|
1216 |
|
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); |
|
1223 |
|
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); |
|
1229 |
|
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 } |
|
1243 |
|
1244 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, |
|
1245 const SkRect& srcR) { |
|
1246 SkRect dstR; |
|
1247 SkIRect devIR; |
|
1248 |
|
1249 m.mapRect(&dstR, srcR); |
|
1250 dstR.roundOut(&devIR); |
|
1251 return c.quickReject(devIR); |
|
1252 } |
|
1253 |
|
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 } |
|
1260 |
|
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 } |
|
1266 |
|
1267 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, |
|
1268 const SkPaint& origPaint) const { |
|
1269 SkDEBUGCODE(this->validate();) |
|
1270 |
|
1271 // nothing to draw |
|
1272 if (fRC->isEmpty() || |
|
1273 bitmap.width() == 0 || bitmap.height() == 0 || |
|
1274 bitmap.colorType() == kUnknown_SkColorType) { |
|
1275 return; |
|
1276 } |
|
1277 |
|
1278 SkPaint paint(origPaint); |
|
1279 paint.setStyle(SkPaint::kFill_Style); |
|
1280 |
|
1281 SkMatrix matrix; |
|
1282 if (!matrix.setConcat(*fMatrix, prematrix)) { |
|
1283 return; |
|
1284 } |
|
1285 |
|
1286 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { |
|
1287 return; |
|
1288 } |
|
1289 |
|
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 } |
|
1299 |
|
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()); |
|
1320 |
|
1321 SkScan::FillIRect(ir, *fRC, blitter); |
|
1322 return; |
|
1323 } |
|
1324 } |
|
1325 } |
|
1326 |
|
1327 // now make a temp draw on the stack, and use it |
|
1328 // |
|
1329 SkDraw draw(*this); |
|
1330 draw.fMatrix = &matrix; |
|
1331 |
|
1332 if (bitmap.colorType() == kAlpha_8_SkColorType) { |
|
1333 draw.drawBitmapAsMask(bitmap, paint); |
|
1334 } else { |
|
1335 SkAutoBitmapShaderInstall install(bitmap, paint); |
|
1336 |
|
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 } |
|
1344 |
|
1345 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, |
|
1346 const SkPaint& origPaint) const { |
|
1347 SkDEBUGCODE(this->validate();) |
|
1348 |
|
1349 // nothing to draw |
|
1350 if (fRC->isEmpty() || |
|
1351 bitmap.width() == 0 || bitmap.height() == 0 || |
|
1352 bitmap.colorType() == kUnknown_SkColorType) { |
|
1353 return; |
|
1354 } |
|
1355 |
|
1356 SkIRect bounds; |
|
1357 bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); |
|
1358 |
|
1359 if (fRC->quickReject(bounds)) { |
|
1360 return; // nothing to draw |
|
1361 } |
|
1362 |
|
1363 SkPaint paint(origPaint); |
|
1364 paint.setStyle(SkPaint::kFill_Style); |
|
1365 |
|
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); |
|
1371 |
|
1372 if (blitter) { |
|
1373 if (fBounder && !fBounder->doIRect(bounds)) { |
|
1374 return; |
|
1375 } |
|
1376 |
|
1377 SkScan::FillIRect(bounds, *fRC, blitter); |
|
1378 return; |
|
1379 } |
|
1380 } |
|
1381 |
|
1382 SkAutoBitmapShaderInstall install(bitmap, paint); |
|
1383 const SkPaint& shaderPaint = install.paintWithShader(); |
|
1384 |
|
1385 SkMatrix matrix; |
|
1386 SkRect r; |
|
1387 |
|
1388 // get a scalar version of our rect |
|
1389 r.set(bounds); |
|
1390 |
|
1391 // tell the shader our offset |
|
1392 matrix.setTranslate(r.fLeft, r.fTop); |
|
1393 shaderPaint.getShader()->setLocalMatrix(matrix); |
|
1394 |
|
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 } |
|
1402 |
|
1403 /////////////////////////////////////////////////////////////////////////////// |
|
1404 |
|
1405 #include "SkScalerContext.h" |
|
1406 #include "SkGlyphCache.h" |
|
1407 #include "SkTextToPathIter.h" |
|
1408 #include "SkUtils.h" |
|
1409 |
|
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; |
|
1414 |
|
1415 SkAutoKern autokern; |
|
1416 |
|
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); |
|
1421 |
|
1422 x += autokern.adjust(glyph) + glyph.fAdvanceX; |
|
1423 y += glyph.fAdvanceY; |
|
1424 } |
|
1425 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); |
|
1426 |
|
1427 SkASSERT(text == stop); |
|
1428 } |
|
1429 |
|
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 } |
|
1435 |
|
1436 // we don't cache perspective |
|
1437 if (ctm.hasPerspective()) { |
|
1438 return true; |
|
1439 } |
|
1440 |
|
1441 SkMatrix textM; |
|
1442 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); |
|
1443 } |
|
1444 |
|
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();) |
|
1449 |
|
1450 SkTextToPathIter iter(text, byteLength, paint, true); |
|
1451 |
|
1452 SkMatrix matrix; |
|
1453 matrix.setScale(iter.getPathScale(), iter.getPathScale()); |
|
1454 matrix.postTranslate(x, y); |
|
1455 |
|
1456 const SkPath* iterPath; |
|
1457 SkScalar xpos, prevXPos = 0; |
|
1458 |
|
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 } |
|
1472 |
|
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 |
|
1478 |
|
1479 ////////////////////////////////////////////////////////////////////////////// |
|
1480 |
|
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())); |
|
1490 |
|
1491 left += glyph.fLeft; |
|
1492 top += glyph.fTop; |
|
1493 |
|
1494 int right = left + glyph.fWidth; |
|
1495 int bottom = top + glyph.fHeight; |
|
1496 |
|
1497 SkMask mask; |
|
1498 SkIRect storage; |
|
1499 SkIRect* bounds = &mask.fBounds; |
|
1500 |
|
1501 mask.fBounds.set(left, top, right, bottom); |
|
1502 |
|
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 } |
|
1510 |
|
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 } |
|
1518 |
|
1519 mask.fRowBytes = glyph.rowBytes(); |
|
1520 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); |
|
1521 mask.fImage = aa; |
|
1522 state.blitMask(mask, *bounds); |
|
1523 } |
|
1524 |
|
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); |
|
1533 |
|
1534 SkMask mask; |
|
1535 |
|
1536 left += glyph.fLeft; |
|
1537 top += glyph.fTop; |
|
1538 |
|
1539 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); |
|
1540 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); |
|
1541 |
|
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 } |
|
1551 |
|
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 } |
|
1561 |
|
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); |
|
1568 |
|
1569 SkMask mask; |
|
1570 |
|
1571 left += glyph.fLeft; |
|
1572 top += glyph.fTop; |
|
1573 |
|
1574 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); |
|
1575 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); |
|
1576 |
|
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 } |
|
1586 |
|
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 } |
|
1602 |
|
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); |
|
1610 |
|
1611 if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) { |
|
1612 D1G_NoBounder_RectClip(state, fx, fy, glyph); |
|
1613 } |
|
1614 } |
|
1615 |
|
1616 static bool hasCustomD1GProc(const SkDraw& draw) { |
|
1617 return draw.fProcs && draw.fProcs->fD1GProc; |
|
1618 } |
|
1619 |
|
1620 static bool needsRasterTextBlit(const SkDraw& draw) { |
|
1621 return !hasCustomD1GProc(draw); |
|
1622 } |
|
1623 |
|
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; |
|
1631 |
|
1632 if (cache->isSubpixel()) { |
|
1633 fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); |
|
1634 } else { |
|
1635 fHalfSampleX = fHalfSampleY = SK_FixedHalf; |
|
1636 } |
|
1637 |
|
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 } |
|
1644 |
|
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 } |
|
1669 |
|
1670 void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { |
|
1671 SkASSERT(SkMask::kARGB32_Format == mask.fFormat); |
|
1672 |
|
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); |
|
1677 |
|
1678 fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); |
|
1679 } |
|
1680 |
|
1681 /////////////////////////////////////////////////////////////////////////////// |
|
1682 |
|
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); |
|
1686 |
|
1687 SkDEBUGCODE(this->validate();) |
|
1688 |
|
1689 // nothing to draw |
|
1690 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { |
|
1691 return; |
|
1692 } |
|
1693 |
|
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 } |
|
1700 |
|
1701 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
|
1702 |
|
1703 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); |
|
1704 SkGlyphCache* cache = autoCache.getCache(); |
|
1705 |
|
1706 // transform our starting point |
|
1707 { |
|
1708 SkPoint loc; |
|
1709 fMatrix->mapXY(x, y, &loc); |
|
1710 x = loc.fX; |
|
1711 y = loc.fY; |
|
1712 } |
|
1713 |
|
1714 // need to measure first |
|
1715 if (paint.getTextAlign() != SkPaint::kLeft_Align) { |
|
1716 SkVector stop; |
|
1717 |
|
1718 measure_text(cache, glyphCacheProc, text, byteLength, &stop); |
|
1719 |
|
1720 SkScalar stopX = stop.fX; |
|
1721 SkScalar stopY = stop.fY; |
|
1722 |
|
1723 if (paint.getTextAlign() == SkPaint::kCenter_Align) { |
|
1724 stopX = SkScalarHalf(stopX); |
|
1725 stopY = SkScalarHalf(stopY); |
|
1726 } |
|
1727 x -= stopX; |
|
1728 y -= stopY; |
|
1729 } |
|
1730 |
|
1731 const char* stop = text + byteLength; |
|
1732 |
|
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 } |
|
1744 |
|
1745 SkAutoKern autokern; |
|
1746 SkDraw1Glyph d1g; |
|
1747 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); |
|
1748 |
|
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 } |
|
1761 |
|
1762 SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; |
|
1763 SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; |
|
1764 |
|
1765 while (text < stop) { |
|
1766 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); |
|
1767 |
|
1768 fx += autokern.adjust(glyph); |
|
1769 |
|
1770 if (glyph.fWidth) { |
|
1771 proc(d1g, fx, fy, glyph); |
|
1772 } |
|
1773 |
|
1774 fx += glyph.fAdvanceX; |
|
1775 fy += glyph.fAdvanceY; |
|
1776 } |
|
1777 } |
|
1778 |
|
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*); |
|
1783 |
|
1784 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { |
|
1785 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); |
|
1786 } |
|
1787 |
|
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 } |
|
1792 |
|
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 } |
|
1797 |
|
1798 static AlignProc pick_align_proc(SkPaint::Align align) { |
|
1799 static const AlignProc gProcs[] = { |
|
1800 leftAlignProc, centerAlignProc, rightAlignProc |
|
1801 }; |
|
1802 |
|
1803 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); |
|
1804 |
|
1805 return gProcs[align]; |
|
1806 } |
|
1807 |
|
1808 typedef void (*AlignProc_scalar)(const SkPoint&, const SkGlyph&, SkPoint*); |
|
1809 |
|
1810 static void leftAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) { |
|
1811 dst->set(loc.fX, loc.fY); |
|
1812 } |
|
1813 |
|
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 } |
|
1818 |
|
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 } |
|
1823 |
|
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 }; |
|
1828 |
|
1829 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); |
|
1830 |
|
1831 return gProcs[align]; |
|
1832 } |
|
1833 |
|
1834 class TextMapState { |
|
1835 public: |
|
1836 mutable SkPoint fLoc; |
|
1837 |
|
1838 TextMapState(const SkMatrix& matrix, SkScalar y) |
|
1839 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} |
|
1840 |
|
1841 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); |
|
1842 |
|
1843 Proc pickProc(int scalarsPerPosition); |
|
1844 |
|
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; |
|
1851 |
|
1852 static void MapXProc(const TextMapState& state, const SkScalar pos[]) { |
|
1853 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); |
|
1854 } |
|
1855 |
|
1856 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { |
|
1857 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); |
|
1858 } |
|
1859 |
|
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 } |
|
1865 |
|
1866 static void MapOnlyTransXProc(const TextMapState& state, |
|
1867 const SkScalar pos[]) { |
|
1868 state.fLoc.set(*pos + state.fTransX, state.fTransformedY); |
|
1869 } |
|
1870 }; |
|
1871 |
|
1872 TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { |
|
1873 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
|
1874 |
|
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 } |
|
1891 |
|
1892 ////////////////////////////////////////////////////////////////////////////// |
|
1893 |
|
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(); |
|
1901 |
|
1902 SkMatrix matrix; |
|
1903 matrix.setScale(matrixScale, matrixScale); |
|
1904 |
|
1905 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
|
1906 SkAutoGlyphCache autoCache(paint, NULL, NULL); |
|
1907 SkGlyphCache* cache = autoCache.getCache(); |
|
1908 |
|
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); |
|
1913 |
|
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); |
|
1922 |
|
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 } |
|
1935 |
|
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); |
|
1941 |
|
1942 SkDEBUGCODE(this->validate();) |
|
1943 |
|
1944 // nothing to draw |
|
1945 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { |
|
1946 return; |
|
1947 } |
|
1948 |
|
1949 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { |
|
1950 this->drawPosText_asPaths(text, byteLength, pos, constY, |
|
1951 scalarsPerPosition, paint); |
|
1952 return; |
|
1953 } |
|
1954 |
|
1955 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
|
1956 SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); |
|
1957 SkGlyphCache* cache = autoCache.getCache(); |
|
1958 |
|
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 } |
|
1970 |
|
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); |
|
1977 |
|
1978 if (cache->isSubpixel()) { |
|
1979 // maybe we should skip the rounding if linearText is set |
|
1980 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); |
|
1981 |
|
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 } |
|
1995 |
|
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; |
|
2001 |
|
2002 const SkGlyph& glyph = glyphCacheProc(cache, &text, |
|
2003 fx & fxMask, fy & fyMask); |
|
2004 |
|
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); |
|
2014 |
|
2015 if (metricGlyph.fWidth) { |
|
2016 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) |
|
2017 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) |
|
2018 |
|
2019 tmsProc(tms, pos); |
|
2020 SkIPoint fixedLoc; |
|
2021 alignProc(tms.fLoc, metricGlyph, &fixedLoc); |
|
2022 |
|
2023 SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX; |
|
2024 SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY; |
|
2025 |
|
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); |
|
2033 |
|
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); |
|
2044 |
|
2045 if (glyph.fWidth) { |
|
2046 tmsProc(tms, pos); |
|
2047 |
|
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); |
|
2059 |
|
2060 if (glyph.fWidth) { |
|
2061 tmsProc(tms, pos); |
|
2062 |
|
2063 SkIPoint fixedLoc; |
|
2064 alignProc(tms.fLoc, glyph, &fixedLoc); |
|
2065 |
|
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 } |
|
2076 |
|
2077 #if defined _WIN32 && _MSC_VER >= 1300 |
|
2078 #pragma warning ( pop ) |
|
2079 #endif |
|
2080 |
|
2081 /////////////////////////////////////////////////////////////////////////////// |
|
2082 |
|
2083 #include "SkPathMeasure.h" |
|
2084 |
|
2085 static void morphpoints(SkPoint dst[], const SkPoint src[], int count, |
|
2086 SkPathMeasure& meas, const SkMatrix& matrix) { |
|
2087 SkMatrix::MapXYProc proc = matrix.getMapXYProc(); |
|
2088 |
|
2089 for (int i = 0; i < count; i++) { |
|
2090 SkPoint pos; |
|
2091 SkVector tangent; |
|
2092 |
|
2093 proc(matrix, src[i].fX, src[i].fY, &pos); |
|
2094 SkScalar sx = pos.fX; |
|
2095 SkScalar sy = pos.fY; |
|
2096 |
|
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 } |
|
2101 |
|
2102 /* This is the old way (that explains our approach but is way too slow |
|
2103 SkMatrix matrix; |
|
2104 SkPoint pt; |
|
2105 |
|
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 } |
|
2116 |
|
2117 /* TODO |
|
2118 |
|
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; |
|
2128 |
|
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 } |
|
2159 |
|
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); |
|
2164 |
|
2165 // nothing to draw |
|
2166 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { |
|
2167 return; |
|
2168 } |
|
2169 |
|
2170 SkTextToPathIter iter(text, byteLength, paint, true); |
|
2171 SkPathMeasure meas(follow, false); |
|
2172 SkScalar hOffset = 0; |
|
2173 |
|
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 } |
|
2182 |
|
2183 const SkPath* iterPath; |
|
2184 SkScalar xpos; |
|
2185 SkMatrix scaledMatrix; |
|
2186 SkScalar scale = iter.getPathScale(); |
|
2187 |
|
2188 scaledMatrix.setScale(scale, scale); |
|
2189 |
|
2190 while (iter.next(&iterPath, &xpos)) { |
|
2191 if (iterPath) { |
|
2192 SkPath tmp; |
|
2193 SkMatrix m(scaledMatrix); |
|
2194 |
|
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 } |
|
2208 |
|
2209 /////////////////////////////////////////////////////////////////////////////// |
|
2210 |
|
2211 struct VertState { |
|
2212 int f0, f1, f2; |
|
2213 |
|
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 } |
|
2223 |
|
2224 typedef bool (*Proc)(VertState*); |
|
2225 Proc chooseProc(SkCanvas::VertexMode mode); |
|
2226 |
|
2227 private: |
|
2228 int fCount; |
|
2229 int fCurrIndex; |
|
2230 const uint16_t* fIndices; |
|
2231 |
|
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 }; |
|
2239 |
|
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 } |
|
2251 |
|
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 } |
|
2264 |
|
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 } |
|
2281 |
|
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 } |
|
2299 |
|
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 } |
|
2311 |
|
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 } |
|
2324 |
|
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 } |
|
2337 |
|
2338 typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&, |
|
2339 SkBlitter*); |
|
2340 |
|
2341 static HairProc ChooseHairProc(bool doAntiAlias) { |
|
2342 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; |
|
2343 } |
|
2344 |
|
2345 static bool texture_to_matrix(const VertState& state, const SkPoint verts[], |
|
2346 const SkPoint texs[], SkMatrix* matrix) { |
|
2347 SkPoint src[3], dst[3]; |
|
2348 |
|
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 } |
|
2357 |
|
2358 class SkTriColorShader : public SkShader { |
|
2359 public: |
|
2360 SkTriColorShader() {} |
|
2361 |
|
2362 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); |
|
2363 |
|
2364 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; |
|
2365 |
|
2366 SK_TO_STRING_OVERRIDE() |
|
2367 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) |
|
2368 |
|
2369 protected: |
|
2370 SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {} |
|
2371 |
|
2372 private: |
|
2373 SkMatrix fDstToUnit; |
|
2374 SkPMColor fColors[3]; |
|
2375 |
|
2376 typedef SkShader INHERITED; |
|
2377 }; |
|
2378 |
|
2379 bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], |
|
2380 int index0, int index1, int index2) { |
|
2381 |
|
2382 fColors[0] = SkPreMultiplyColor(colors[index0]); |
|
2383 fColors[1] = SkPreMultiplyColor(colors[index1]); |
|
2384 fColors[2] = SkPreMultiplyColor(colors[index2]); |
|
2385 |
|
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 } |
|
2399 |
|
2400 #include "SkColorPriv.h" |
|
2401 #include "SkComposeShader.h" |
|
2402 |
|
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 } |
|
2413 |
|
2414 void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { |
|
2415 SkPoint src; |
|
2416 |
|
2417 for (int i = 0; i < count; i++) { |
|
2418 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); |
|
2419 x += 1; |
|
2420 |
|
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 } |
|
2432 |
|
2433 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + |
|
2434 SkAlphaMulQ(fColors[1], scale1) + |
|
2435 SkAlphaMulQ(fColors[2], scale2); |
|
2436 } |
|
2437 } |
|
2438 |
|
2439 #ifndef SK_IGNORE_TO_STRING |
|
2440 void SkTriColorShader::toString(SkString* str) const { |
|
2441 str->append("SkTriColorShader: ("); |
|
2442 |
|
2443 this->INHERITED::toString(str); |
|
2444 |
|
2445 str->append(")"); |
|
2446 } |
|
2447 #endif |
|
2448 |
|
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); |
|
2455 |
|
2456 // abort early if there is nothing to draw |
|
2457 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { |
|
2458 return; |
|
2459 } |
|
2460 |
|
2461 // transform out vertices into device coordinates |
|
2462 SkAutoSTMalloc<16, SkPoint> storage(count); |
|
2463 SkPoint* devVerts = storage.get(); |
|
2464 fMatrix->mapPoints(devVerts, vertices, count); |
|
2465 |
|
2466 if (fBounder) { |
|
2467 SkRect bounds; |
|
2468 bounds.set(devVerts, count); |
|
2469 if (!fBounder->doRect(bounds, paint)) { |
|
2470 return; |
|
2471 } |
|
2472 } |
|
2473 |
|
2474 /* |
|
2475 We can draw the vertices in 1 of 4 ways: |
|
2476 |
|
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[]) |
|
2481 |
|
2482 Thus for texture drawing, we need both texture[] and a shader. |
|
2483 */ |
|
2484 |
|
2485 SkTriColorShader triShader; // must be above declaration of p |
|
2486 SkPaint p(paint); |
|
2487 |
|
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 } |
|
2497 |
|
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 } |
|
2519 |
|
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 } |
|
2527 |
|
2528 // setup our state and function pointer for iterating triangles |
|
2529 VertState state(count, indices, indexCount); |
|
2530 VertState::Proc vertProc = state.chooseProc(vmode); |
|
2531 |
|
2532 if (NULL != textures || NULL != colors) { |
|
2533 SkMatrix tempM; |
|
2534 SkMatrix savedLocalM; |
|
2535 if (shader) { |
|
2536 savedLocalM = shader->getLocalMatrix(); |
|
2537 } |
|
2538 |
|
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 } |
|
2566 |
|
2567 SkPoint tmp[] = { |
|
2568 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] |
|
2569 }; |
|
2570 SkScan::FillTriangle(tmp, *fRC, blitter.get()); |
|
2571 } |
|
2572 |
|
2573 // now restore the shader's original local matrix |
|
2574 if (NULL != shader) { |
|
2575 shader->setLocalMatrix(savedLocalM); |
|
2576 } |
|
2577 |
|
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 } |
|
2595 |
|
2596 /////////////////////////////////////////////////////////////////////////////// |
|
2597 /////////////////////////////////////////////////////////////////////////////// |
|
2598 |
|
2599 #ifdef SK_DEBUG |
|
2600 |
|
2601 void SkDraw::validate() const { |
|
2602 SkASSERT(fBitmap != NULL); |
|
2603 SkASSERT(fMatrix != NULL); |
|
2604 SkASSERT(fClip != NULL); |
|
2605 SkASSERT(fRC != NULL); |
|
2606 |
|
2607 const SkIRect& cr = fRC->getBounds(); |
|
2608 SkIRect br; |
|
2609 |
|
2610 br.set(0, 0, fBitmap->width(), fBitmap->height()); |
|
2611 SkASSERT(cr.isEmpty() || br.contains(cr)); |
|
2612 } |
|
2613 |
|
2614 #endif |
|
2615 |
|
2616 /////////////////////////////////////////////////////////////////////////////// |
|
2617 |
|
2618 SkBounder::SkBounder() { |
|
2619 // initialize up front. This gets reset by SkCanvas before each draw call. |
|
2620 fClip = &SkRegion::GetEmptyRegion(); |
|
2621 } |
|
2622 |
|
2623 bool SkBounder::doIRect(const SkIRect& r) { |
|
2624 SkIRect rr; |
|
2625 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); |
|
2626 } |
|
2627 |
|
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 } |
|
2643 |
|
2644 bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, |
|
2645 const SkPaint& paint) { |
|
2646 SkIRect r; |
|
2647 SkScalar v0, v1; |
|
2648 |
|
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); |
|
2656 |
|
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); |
|
2664 |
|
2665 if (paint.isAntiAlias()) { |
|
2666 r.inset(-1, -1); |
|
2667 } |
|
2668 return this->doIRect(r); |
|
2669 } |
|
2670 |
|
2671 bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { |
|
2672 SkIRect r; |
|
2673 |
|
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 } |
|
2686 |
|
2687 bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { |
|
2688 SkIRect r; |
|
2689 const SkRect& bounds = path.getBounds(); |
|
2690 |
|
2691 if (doFill) { |
|
2692 bounds.round(&r); |
|
2693 } else { // hairline |
|
2694 bounds.roundOut(&r); |
|
2695 } |
|
2696 |
|
2697 if (paint.isAntiAlias()) { |
|
2698 r.inset(-1, -1); |
|
2699 } |
|
2700 return this->doIRect(r); |
|
2701 } |
|
2702 |
|
2703 void SkBounder::commit() { |
|
2704 // override in subclass |
|
2705 } |
|
2706 |
|
2707 //////////////////////////////////////////////////////////////////////////////////////////////// |
|
2708 |
|
2709 #include "SkPath.h" |
|
2710 #include "SkDraw.h" |
|
2711 #include "SkRegion.h" |
|
2712 #include "SkBlitter.h" |
|
2713 |
|
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 } |
|
2720 |
|
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 } |
|
2727 |
|
2728 SkIPoint margin = SkIPoint::Make(0, 0); |
|
2729 if (filter) { |
|
2730 SkASSERT(filterMatrix); |
|
2731 |
|
2732 SkMask srcM, dstM; |
|
2733 |
|
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 } |
|
2741 |
|
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 } |
|
2759 |
|
2760 return true; |
|
2761 } |
|
2762 |
|
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; |
|
2770 |
|
2771 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); |
|
2772 bm.setPixels(mask.fImage); |
|
2773 |
|
2774 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); |
|
2775 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), |
|
2776 -SkIntToScalar(mask.fBounds.fTop)); |
|
2777 |
|
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 } |
|
2787 |
|
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 } |
|
2796 |
|
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 } |
|
2808 |
|
2809 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
|
2810 draw_into_mask(*mask, devPath, style); |
|
2811 } |
|
2812 |
|
2813 return true; |
|
2814 } |