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