SkDraw.cpp revision c3d7d90973528527131c72549b10c2a21300e0ac
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 676 if (SkPathEffect::PointData::kCircles_PointFlag & dst.fFlags) { 677 newP.setStrokeCap(SkPaint::kRound_Cap); 678 } else { 679 newP.setStrokeCap(SkPaint::kButt_Cap); 680 } 681 682 this->drawPoints(SkCanvas::kPoints_PointMode, 683 dst.fPoints.count(), 684 dst.fPoints.begin(), 685 newP, 686 forceUseDevice); 687 break; 688 } 689 } 690#endif // DISABLE_DASHING_OPTIMIZATION 691 // couldn't take fast path so fall through! 692 case SkCanvas::kPolygon_PointMode: { 693 count -= 1; 694 SkPath path; 695 SkPaint p(paint); 696 p.setStyle(SkPaint::kStroke_Style); 697 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 698 for (size_t i = 0; i < count; i += inc) { 699 path.moveTo(pts[i]); 700 path.lineTo(pts[i+1]); 701 if (fDevice) { 702 fDevice->drawPath(*this, path, p, NULL, true); 703 } else { 704 this->drawPath(path, p, NULL, true); 705 } 706 path.rewind(); 707 } 708 break; 709 } 710 } 711 } 712} 713 714static inline SkPoint* as_lefttop(SkRect* r) { 715 return (SkPoint*)(void*)r; 716} 717 718static inline SkPoint* as_rightbottom(SkRect* r) { 719 return ((SkPoint*)(void*)r) + 1; 720} 721 722static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 723 SkPoint* strokeSize) { 724 if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 725 paint.getStrokeMiter() < SK_ScalarSqrt2) { 726 return false; 727 } 728 729 SkASSERT(matrix.rectStaysRect()); 730 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 731 matrix.mapVectors(strokeSize, &pt, 1); 732 strokeSize->fX = SkScalarAbs(strokeSize->fX); 733 strokeSize->fY = SkScalarAbs(strokeSize->fY); 734 return true; 735} 736 737SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 738 const SkMatrix& matrix, 739 SkPoint* strokeSize) { 740 RectType rtype; 741 const SkScalar width = paint.getStrokeWidth(); 742 const bool zeroWidth = (0 == width); 743 SkPaint::Style style = paint.getStyle(); 744 745 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 746 style = SkPaint::kFill_Style; 747 } 748 749 if (paint.getPathEffect() || paint.getMaskFilter() || 750 paint.getRasterizer() || !matrix.rectStaysRect() || 751 SkPaint::kStrokeAndFill_Style == style) { 752 rtype = kPath_RectType; 753 } else if (SkPaint::kFill_Style == style) { 754 rtype = kFill_RectType; 755 } else if (zeroWidth) { 756 rtype = kHair_RectType; 757 } else if (easy_rect_join(paint, matrix, strokeSize)) { 758 rtype = kStroke_RectType; 759 } else { 760 rtype = kPath_RectType; 761 } 762 return rtype; 763} 764 765static const SkPoint* rect_points(const SkRect& r) { 766 return (const SkPoint*)(void*)&r; 767} 768 769static SkPoint* rect_points(SkRect& r) { 770 return (SkPoint*)(void*)&r; 771} 772 773void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { 774 SkDEBUGCODE(this->validate();) 775 776 // nothing to draw 777 if (fRC->isEmpty()) { 778 return; 779 } 780 781 SkPoint strokeSize; 782 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 783 784 if (kPath_RectType == rtype) { 785 SkPath tmp; 786 tmp.addRect(rect); 787 tmp.setFillType(SkPath::kWinding_FillType); 788 this->drawPath(tmp, paint, NULL, true); 789 return; 790 } 791 792 const SkMatrix& matrix = *fMatrix; 793 SkRect devRect; 794 795 // transform rect into devRect 796 matrix.mapPoints(rect_points(devRect), rect_points(rect), 2); 797 devRect.sort(); 798 799 if (fBounder && !fBounder->doRect(devRect, paint)) { 800 return; 801 } 802 803 // look for the quick exit, before we build a blitter 804 if (true) { 805 SkIRect ir; 806 devRect.roundOut(&ir); 807 if (paint.getStyle() != SkPaint::kFill_Style) { 808 // extra space for hairlines 809 ir.inset(-1, -1); 810 } 811 if (fRC->quickReject(ir)) 812 return; 813 } 814 815 SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint); 816 const SkRasterClip& clip = *fRC; 817 SkBlitter* blitter = blitterStorage.get(); 818 819 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 820 // case we are also hairline (if we've gotten to here), which devolves to 821 // effectively just kFill 822 switch (rtype) { 823 case kFill_RectType: 824 if (paint.isAntiAlias()) { 825 SkScan::AntiFillRect(devRect, clip, blitter); 826 } else { 827 SkScan::FillRect(devRect, clip, blitter); 828 } 829 break; 830 case kStroke_RectType: 831 if (paint.isAntiAlias()) { 832 SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter); 833 } else { 834 SkScan::FrameRect(devRect, strokeSize, clip, blitter); 835 } 836 break; 837 case kHair_RectType: 838 if (paint.isAntiAlias()) { 839 SkScan::AntiHairRect(devRect, clip, blitter); 840 } else { 841 SkScan::HairRect(devRect, clip, blitter); 842 } 843 break; 844 default: 845 SkDEBUGFAIL("bad rtype"); 846 } 847} 848 849void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 850 if (srcM.fBounds.isEmpty()) { 851 return; 852 } 853 854 const SkMask* mask = &srcM; 855 856 SkMask dstM; 857 if (paint.getMaskFilter() && 858 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) { 859 mask = &dstM; 860 } else { 861 dstM.fImage = NULL; 862 } 863 SkAutoMaskFreeImage ami(dstM.fImage); 864 865 if (fBounder && !fBounder->doIRect(mask->fBounds)) { 866 return; 867 } 868 869 SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint); 870 SkBlitter* blitter = blitterChooser.get(); 871 872 SkAAClipBlitterWrapper wrapper; 873 const SkRegion* clipRgn; 874 875 if (fRC->isBW()) { 876 clipRgn = &fRC->bwRgn(); 877 } else { 878 wrapper.init(*fRC, blitter); 879 clipRgn = &wrapper.getRgn(); 880 blitter = wrapper.getBlitter(); 881 } 882 blitter->blitMaskRegion(*mask, *clipRgn); 883} 884 885static SkScalar fast_len(const SkVector& vec) { 886 SkScalar x = SkScalarAbs(vec.fX); 887 SkScalar y = SkScalarAbs(vec.fY); 888 if (x < y) { 889 SkTSwap(x, y); 890 } 891 return x + SkScalarHalf(y); 892} 893 894static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) { 895 SkXfermode::Coeff dc; 896 if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) { 897 return false; 898 } 899 900 switch (dc) { 901 case SkXfermode::kOne_Coeff: 902 case SkXfermode::kISA_Coeff: 903 case SkXfermode::kISC_Coeff: 904 return true; 905 default: 906 return false; 907 } 908} 909 910bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix, 911 SkScalar* coverage) { 912 SkASSERT(coverage); 913 if (SkPaint::kStroke_Style != paint.getStyle()) { 914 return false; 915 } 916 SkScalar strokeWidth = paint.getStrokeWidth(); 917 if (0 == strokeWidth) { 918 *coverage = SK_Scalar1; 919 return true; 920 } 921 922 // if we get here, we need to try to fake a thick-stroke with a modulated 923 // hairline 924 925 if (!paint.isAntiAlias()) { 926 return false; 927 } 928 if (matrix.hasPerspective()) { 929 return false; 930 } 931 932 SkVector src[2], dst[2]; 933 src[0].set(strokeWidth, 0); 934 src[1].set(0, strokeWidth); 935 matrix.mapVectors(dst, src, 2); 936 SkScalar len0 = fast_len(dst[0]); 937 SkScalar len1 = fast_len(dst[1]); 938 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 939 *coverage = SkScalarAve(len0, len1); 940 return true; 941 } 942 return false; 943} 944 945void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 946 const SkMatrix* prePathMatrix, bool pathIsMutable) const { 947 SkDEBUGCODE(this->validate();) 948 949 // nothing to draw 950 if (fRC->isEmpty()) { 951 return; 952 } 953 954 SkPath* pathPtr = (SkPath*)&origSrcPath; 955 bool doFill = true; 956 SkPath tmpPath; 957 SkMatrix tmpMatrix; 958 const SkMatrix* matrix = fMatrix; 959 960 if (prePathMatrix) { 961 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 962 origPaint.getRasterizer()) { 963 SkPath* result = pathPtr; 964 965 if (!pathIsMutable) { 966 result = &tmpPath; 967 pathIsMutable = true; 968 } 969 pathPtr->transform(*prePathMatrix, result); 970 pathPtr = result; 971 } else { 972 if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) { 973 // overflow 974 return; 975 } 976 matrix = &tmpMatrix; 977 } 978 } 979 // at this point we're done with prePathMatrix 980 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 981 982 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 983 984 { 985 SkScalar coverage; 986 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 987 if (SK_Scalar1 == coverage) { 988 paint.writable()->setStrokeWidth(0); 989 } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) { 990 U8CPU newAlpha; 991#if 0 992 newAlpha = SkToU8(SkScalarRoundToInt(coverage * 993 origPaint.getAlpha())); 994#else 995 // this is the old technique, which we preserve for now so 996 // we don't change previous results (testing) 997 // the new way seems fine, its just (a tiny bit) different 998 int scale = (int)SkScalarMul(coverage, 256); 999 newAlpha = origPaint.getAlpha() * scale >> 8; 1000#endif 1001 SkPaint* writablePaint = paint.writable(); 1002 writablePaint->setStrokeWidth(0); 1003 writablePaint->setAlpha(newAlpha); 1004 } 1005 } 1006 } 1007 1008 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 1009 doFill = paint->getFillPath(*pathPtr, &tmpPath); 1010 pathPtr = &tmpPath; 1011 } 1012 1013 if (paint->getRasterizer()) { 1014 SkMask mask; 1015 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1016 &fRC->getBounds(), paint->getMaskFilter(), &mask, 1017 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1018 this->drawDevMask(mask, *paint); 1019 SkMask::FreeImage(mask.fImage); 1020 } 1021 return; 1022 } 1023 1024 // avoid possibly allocating a new path in transform if we can 1025 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1026 1027 // transform the path into device space 1028 pathPtr->transform(*matrix, devPathPtr); 1029 1030 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint); 1031 1032 if (paint->getMaskFilter()) { 1033 SkPaint::Style style = doFill ? SkPaint::kFill_Style : 1034 SkPaint::kStroke_Style; 1035 if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, 1036 fBounder, blitter.get(), 1037 style)) { 1038 return; // filterPath() called the blitter, so we're done 1039 } 1040 } 1041 1042 if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) { 1043 return; 1044 } 1045 1046 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 1047 if (doFill) { 1048 if (paint->isAntiAlias()) { 1049 proc = SkScan::AntiFillPath; 1050 } else { 1051 proc = SkScan::FillPath; 1052 } 1053 } else { // hairline 1054 if (paint->isAntiAlias()) { 1055 proc = SkScan::AntiHairPath; 1056 } else { 1057 proc = SkScan::HairPath; 1058 } 1059 } 1060 proc(*devPathPtr, *fRC, blitter.get()); 1061} 1062 1063/** For the purposes of drawing bitmaps, if a matrix is "almost" translate 1064 go ahead and treat it as if it were, so that subsequent code can go fast. 1065 */ 1066static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) { 1067 SkMatrix::TypeMask mask = matrix.getType(); 1068 1069 if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1070 return false; 1071 } 1072 if (mask & SkMatrix::kScale_Mask) { 1073 SkScalar sx = matrix[SkMatrix::kMScaleX]; 1074 SkScalar sy = matrix[SkMatrix::kMScaleY]; 1075 int w = bitmap.width(); 1076 int h = bitmap.height(); 1077 int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w))); 1078 int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h))); 1079 return sw == w && sh == h; 1080 } 1081 // if we got here, we're either kTranslate_Mask or identity 1082 return true; 1083} 1084 1085void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, 1086 const SkPaint& paint) const { 1087 SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config); 1088 1089 if (just_translate(*fMatrix, bitmap)) { 1090 int ix = SkScalarRound(fMatrix->getTranslateX()); 1091 int iy = SkScalarRound(fMatrix->getTranslateY()); 1092 1093 SkMask mask; 1094 mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1095 mask.fFormat = SkMask::kA8_Format; 1096 mask.fRowBytes = bitmap.rowBytes(); 1097 mask.fImage = bitmap.getAddr8(0, 0); 1098 1099 this->drawDevMask(mask, paint); 1100 } else { // need to xform the bitmap first 1101 SkRect r; 1102 SkMask mask; 1103 1104 r.set(0, 0, 1105 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1106 fMatrix->mapRect(&r); 1107 r.round(&mask.fBounds); 1108 1109 // set the mask's bounds to the transformed bitmap-bounds, 1110 // clipped to the actual device 1111 { 1112 SkIRect devBounds; 1113 devBounds.set(0, 0, fBitmap->width(), fBitmap->height()); 1114 // need intersect(l, t, r, b) on irect 1115 if (!mask.fBounds.intersect(devBounds)) { 1116 return; 1117 } 1118 } 1119 1120 mask.fFormat = SkMask::kA8_Format; 1121 mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1122 size_t size = mask.computeImageSize(); 1123 if (0 == size) { 1124 // the mask is too big to allocated, draw nothing 1125 return; 1126 } 1127 1128 // allocate (and clear) our temp buffer to hold the transformed bitmap 1129 SkAutoMalloc storage(size); 1130 mask.fImage = (uint8_t*)storage.get(); 1131 memset(mask.fImage, 0, size); 1132 1133 // now draw our bitmap(src) into mask(dst), transformed by the matrix 1134 { 1135 SkBitmap device; 1136 device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), 1137 mask.fBounds.height(), mask.fRowBytes); 1138 device.setPixels(mask.fImage); 1139 1140 SkCanvas c(device); 1141 // need the unclipped top/left for the translate 1142 c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1143 -SkIntToScalar(mask.fBounds.fTop)); 1144 c.concat(*fMatrix); 1145 1146 // We can't call drawBitmap, or we'll infinitely recurse. Instead 1147 // we manually build a shader and draw that into our new mask 1148 SkPaint tmpPaint; 1149 tmpPaint.setFlags(paint.getFlags()); 1150 SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1151 SkRect rr; 1152 rr.set(0, 0, SkIntToScalar(bitmap.width()), 1153 SkIntToScalar(bitmap.height())); 1154 c.drawRect(rr, install.paintWithShader()); 1155 } 1156 this->drawDevMask(mask, paint); 1157 } 1158} 1159 1160static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1161 const SkRect& srcR) { 1162 SkRect dstR; 1163 SkIRect devIR; 1164 1165 m.mapRect(&dstR, srcR); 1166 dstR.roundOut(&devIR); 1167 return c.quickReject(devIR); 1168} 1169 1170static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1171 int width, int height) { 1172 SkRect r; 1173 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1174 return clipped_out(matrix, clip, r); 1175} 1176 1177static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, 1178 const SkBitmap& bitmap) { 1179 return clip.isBW() || 1180 clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height()); 1181} 1182 1183void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1184 const SkPaint& origPaint) const { 1185 SkDEBUGCODE(this->validate();) 1186 1187 // nothing to draw 1188 if (fRC->isEmpty() || 1189 bitmap.width() == 0 || bitmap.height() == 0 || 1190 bitmap.getConfig() == SkBitmap::kNo_Config) { 1191 return; 1192 } 1193 1194#ifndef SK_ALLOW_OVER_32K_BITMAPS 1195 // run away on too-big bitmaps for now (exceed 16.16) 1196 if (bitmap.width() > 32767 || bitmap.height() > 32767) { 1197 return; 1198 } 1199#endif 1200 1201 SkPaint paint(origPaint); 1202 paint.setStyle(SkPaint::kFill_Style); 1203 1204 SkMatrix matrix; 1205 if (!matrix.setConcat(*fMatrix, prematrix)) { 1206 return; 1207 } 1208 1209 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1210 return; 1211 } 1212 1213 if (fBounder && just_translate(matrix, bitmap)) { 1214 SkIRect ir; 1215 int32_t ix = SkScalarRound(matrix.getTranslateX()); 1216 int32_t iy = SkScalarRound(matrix.getTranslateY()); 1217 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1218 if (!fBounder->doIRect(ir)) { 1219 return; 1220 } 1221 } 1222 1223 // only lock the pixels if we passed the clip and bounder tests 1224 SkAutoLockPixels alp(bitmap); 1225 // after the lock, check if we are valid 1226 if (!bitmap.readyToDraw()) { 1227 return; 1228 } 1229 1230 if (bitmap.getConfig() != SkBitmap::kA8_Config && 1231 just_translate(matrix, bitmap)) { 1232 int ix = SkScalarRound(matrix.getTranslateX()); 1233 int iy = SkScalarRound(matrix.getTranslateY()); 1234 if (clipHandlesSprite(*fRC, ix, iy, bitmap)) { 1235 uint32_t storage[kBlitterStorageLongCount]; 1236 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1237 ix, iy, storage, sizeof(storage)); 1238 if (blitter) { 1239 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1240 1241 SkIRect ir; 1242 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1243 1244 SkScan::FillIRect(ir, *fRC, blitter); 1245 return; 1246 } 1247 } 1248 } 1249 1250 // now make a temp draw on the stack, and use it 1251 // 1252 SkDraw draw(*this); 1253 draw.fMatrix = &matrix; 1254 1255 if (bitmap.getConfig() == SkBitmap::kA8_Config) { 1256 draw.drawBitmapAsMask(bitmap, paint); 1257 } else { 1258 SkAutoBitmapShaderInstall install(bitmap, paint); 1259 1260 SkRect r; 1261 r.set(0, 0, SkIntToScalar(bitmap.width()), 1262 SkIntToScalar(bitmap.height())); 1263 // is this ok if paint has a rasterizer? 1264 draw.drawRect(r, install.paintWithShader()); 1265 } 1266} 1267 1268void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, 1269 const SkPaint& origPaint) const { 1270 SkDEBUGCODE(this->validate();) 1271 1272 // nothing to draw 1273 if (fRC->isEmpty() || 1274 bitmap.width() == 0 || bitmap.height() == 0 || 1275 bitmap.getConfig() == SkBitmap::kNo_Config) { 1276 return; 1277 } 1278 1279 SkIRect bounds; 1280 bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); 1281 1282 if (fRC->quickReject(bounds)) { 1283 return; // nothing to draw 1284 } 1285 1286 SkPaint paint(origPaint); 1287 paint.setStyle(SkPaint::kFill_Style); 1288 1289 if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) { 1290 uint32_t storage[kBlitterStorageLongCount]; 1291 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1292 x, y, storage, sizeof(storage)); 1293 1294 if (blitter) { 1295 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage); 1296 1297 if (fBounder && !fBounder->doIRect(bounds)) { 1298 return; 1299 } 1300 1301 SkScan::FillIRect(bounds, *fRC, blitter); 1302 return; 1303 } 1304 } 1305 1306 SkAutoBitmapShaderInstall install(bitmap, paint); 1307 const SkPaint& shaderPaint = install.paintWithShader(); 1308 1309 SkMatrix matrix; 1310 SkRect r; 1311 1312 // get a scalar version of our rect 1313 r.set(bounds); 1314 1315 // tell the shader our offset 1316 matrix.setTranslate(r.fLeft, r.fTop); 1317 shaderPaint.getShader()->setLocalMatrix(matrix); 1318 1319 SkDraw draw(*this); 1320 matrix.reset(); 1321 draw.fMatrix = &matrix; 1322 // call ourself with a rect 1323 // is this OK if paint has a rasterizer? 1324 draw.drawRect(r, shaderPaint); 1325} 1326 1327/////////////////////////////////////////////////////////////////////////////// 1328 1329#include "SkScalerContext.h" 1330#include "SkGlyphCache.h" 1331#include "SkTextToPathIter.h" 1332#include "SkUtils.h" 1333 1334static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, 1335 const char text[], size_t byteLength, SkVector* stopVector) { 1336 SkFixed x = 0, y = 0; 1337 const char* stop = text + byteLength; 1338 1339 SkAutoKern autokern; 1340 1341 while (text < stop) { 1342 // don't need x, y here, since all subpixel variants will have the 1343 // same advance 1344 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1345 1346 x += autokern.adjust(glyph) + glyph.fAdvanceX; 1347 y += glyph.fAdvanceY; 1348 } 1349 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); 1350 1351 SkASSERT(text == stop); 1352} 1353 1354void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1355 SkScalar x, SkScalar y, 1356 const SkPaint& paint) const { 1357 SkDEBUGCODE(this->validate();) 1358 1359 SkTextToPathIter iter(text, byteLength, paint, true); 1360 1361 SkMatrix matrix; 1362 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1363 matrix.postTranslate(x, y); 1364 1365 const SkPath* iterPath; 1366 SkScalar xpos, prevXPos = 0; 1367 1368 while (iter.next(&iterPath, &xpos)) { 1369 matrix.postTranslate(xpos - prevXPos, 0); 1370 if (iterPath) { 1371 const SkPaint& pnt = iter.getPaint(); 1372 if (fDevice) { 1373 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1374 } else { 1375 this->drawPath(*iterPath, pnt, &matrix, false); 1376 } 1377 } 1378 prevXPos = xpos; 1379 } 1380} 1381 1382// disable warning : local variable used without having been initialized 1383#if defined _WIN32 && _MSC_VER >= 1300 1384#pragma warning ( push ) 1385#pragma warning ( disable : 4701 ) 1386#endif 1387 1388////////////////////////////////////////////////////////////////////////////// 1389 1390static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, 1391 SkFixed fx, SkFixed fy, 1392 const SkGlyph& glyph) { 1393 int left = SkFixedFloor(fx); 1394 int top = SkFixedFloor(fy); 1395 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1396 SkASSERT(NULL == state.fBounder); 1397 SkASSERT((NULL == state.fClip && state.fAAClip) || 1398 (state.fClip && NULL == state.fAAClip && state.fClip->isRect())); 1399 1400 left += glyph.fLeft; 1401 top += glyph.fTop; 1402 1403 int right = left + glyph.fWidth; 1404 int bottom = top + glyph.fHeight; 1405 1406 SkMask mask; 1407 SkIRect storage; 1408 SkIRect* bounds = &mask.fBounds; 1409 1410 mask.fBounds.set(left, top, right, bottom); 1411 1412 // this extra test is worth it, assuming that most of the time it succeeds 1413 // since we can avoid writing to storage 1414 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { 1415 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) 1416 return; 1417 bounds = &storage; 1418 } 1419 1420 uint8_t* aa = (uint8_t*)glyph.fImage; 1421 if (NULL == aa) { 1422 aa = (uint8_t*)state.fCache->findImage(glyph); 1423 if (NULL == aa) { 1424 return; // can't rasterize glyph 1425 } 1426 } 1427 1428 mask.fRowBytes = glyph.rowBytes(); 1429 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1430 mask.fImage = aa; 1431 state.fBlitter->blitMask(mask, *bounds); 1432} 1433 1434static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, 1435 SkFixed fx, SkFixed fy, 1436 const SkGlyph& glyph) { 1437 int left = SkFixedFloor(fx); 1438 int top = SkFixedFloor(fy); 1439 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1440 SkASSERT(!state.fClip->isRect()); 1441 SkASSERT(NULL == state.fBounder); 1442 1443 SkMask mask; 1444 1445 left += glyph.fLeft; 1446 top += glyph.fTop; 1447 1448 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1449 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1450 1451 if (!clipper.done()) { 1452 const SkIRect& cr = clipper.rect(); 1453 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1454 if (NULL == aa) { 1455 aa = (uint8_t*)state.fCache->findImage(glyph); 1456 if (NULL == aa) { 1457 return; 1458 } 1459 } 1460 1461 mask.fRowBytes = glyph.rowBytes(); 1462 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1463 mask.fImage = (uint8_t*)aa; 1464 do { 1465 state.fBlitter->blitMask(mask, cr); 1466 clipper.next(); 1467 } while (!clipper.done()); 1468 } 1469} 1470 1471static void D1G_Bounder(const SkDraw1Glyph& state, 1472 SkFixed fx, SkFixed fy, 1473 const SkGlyph& glyph) { 1474 int left = SkFixedFloor(fx); 1475 int top = SkFixedFloor(fy); 1476 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1477 1478 SkMask mask; 1479 1480 left += glyph.fLeft; 1481 top += glyph.fTop; 1482 1483 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1484 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1485 1486 if (!clipper.done()) { 1487 const SkIRect& cr = clipper.rect(); 1488 const uint8_t* aa = (const uint8_t*)glyph.fImage; 1489 if (NULL == aa) { 1490 aa = (uint8_t*)state.fCache->findImage(glyph); 1491 if (NULL == aa) { 1492 return; 1493 } 1494 } 1495 1496 // we need to pass the origin, which we approximate with our 1497 // (unadjusted) left,top coordinates (the caller called fixedfloor) 1498 if (state.fBounder->doIRectGlyph(cr, 1499 left - glyph.fLeft, 1500 top - glyph.fTop, glyph)) { 1501 mask.fRowBytes = glyph.rowBytes(); 1502 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1503 mask.fImage = (uint8_t*)aa; 1504 do { 1505 state.fBlitter->blitMask(mask, cr); 1506 clipper.next(); 1507 } while (!clipper.done()); 1508 } 1509 } 1510} 1511 1512static void D1G_Bounder_AAClip(const SkDraw1Glyph& state, 1513 SkFixed fx, SkFixed fy, 1514 const SkGlyph& glyph) { 1515 int left = SkFixedFloor(fx); 1516 int top = SkFixedFloor(fy); 1517 SkIRect bounds; 1518 bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1519 1520 if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) { 1521 D1G_NoBounder_RectClip(state, fx, fy, glyph); 1522 } 1523} 1524 1525static bool hasCustomD1GProc(const SkDraw& draw) { 1526 return draw.fProcs && draw.fProcs->fD1GProc; 1527} 1528 1529static bool needsRasterTextBlit(const SkDraw& draw) { 1530 return !hasCustomD1GProc(draw); 1531} 1532 1533SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, 1534 SkGlyphCache* cache) { 1535 fDraw = draw; 1536 fBounder = draw->fBounder; 1537 fBlitter = blitter; 1538 fCache = cache; 1539 1540 if (hasCustomD1GProc(*draw)) { 1541 // todo: fix this assumption about clips w/ custom 1542 fClip = draw->fClip; 1543 fClipBounds = fClip->getBounds(); 1544 return draw->fProcs->fD1GProc; 1545 } 1546 1547 if (draw->fRC->isBW()) { 1548 fAAClip = NULL; 1549 fClip = &draw->fRC->bwRgn(); 1550 fClipBounds = fClip->getBounds(); 1551 if (NULL == fBounder) { 1552 if (fClip->isRect()) { 1553 return D1G_NoBounder_RectClip; 1554 } else { 1555 return D1G_NoBounder_RgnClip; 1556 } 1557 } else { 1558 return D1G_Bounder; 1559 } 1560 } else { // aaclip 1561 fAAClip = &draw->fRC->aaRgn(); 1562 fClip = NULL; 1563 fClipBounds = fAAClip->getBounds(); 1564 if (NULL == fBounder) { 1565 return D1G_NoBounder_RectClip; 1566 } else { 1567 return D1G_Bounder_AAClip; 1568 } 1569 } 1570} 1571 1572/////////////////////////////////////////////////////////////////////////////// 1573 1574void SkDraw::drawText(const char text[], size_t byteLength, 1575 SkScalar x, SkScalar y, const SkPaint& paint) const { 1576 SkASSERT(byteLength == 0 || text != NULL); 1577 1578 SkDEBUGCODE(this->validate();) 1579 1580 // nothing to draw 1581 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1582 return; 1583 } 1584 1585 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1586 // will fill if its frame-width is 0. 1587 if (/*paint.isLinearText() ||*/ 1588 (fMatrix->hasPerspective()) || 1589 (0 == paint.getStrokeWidth() && SkPaint::kStroke_Style == paint.getStyle())) { 1590 this->drawText_asPaths(text, byteLength, x, y, paint); 1591 return; 1592 } 1593 1594 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1595 1596 const SkMatrix* matrix = fMatrix; 1597 1598 SkAutoGlyphCache autoCache(paint, matrix); 1599 SkGlyphCache* cache = autoCache.getCache(); 1600 1601 // transform our starting point 1602 { 1603 SkPoint loc; 1604 matrix->mapXY(x, y, &loc); 1605 x = loc.fX; 1606 y = loc.fY; 1607 } 1608 1609 // need to measure first 1610 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 1611 SkVector stop; 1612 1613 measure_text(cache, glyphCacheProc, text, byteLength, &stop); 1614 1615 SkScalar stopX = stop.fX; 1616 SkScalar stopY = stop.fY; 1617 1618 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1619 stopX = SkScalarHalf(stopX); 1620 stopY = SkScalarHalf(stopY); 1621 } 1622 x -= stopX; 1623 y -= stopY; 1624 } 1625 1626 SkFixed fx = SkScalarToFixed(x); 1627 SkFixed fy = SkScalarToFixed(y); 1628 const char* stop = text + byteLength; 1629 1630 SkFixed fxMask = ~0; 1631 SkFixed fyMask = ~0; 1632 if (cache->isSubpixel()) { 1633 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*matrix); 1634 if (kX_SkAxisAlignment == baseline) { 1635 fyMask = 0; 1636 } else if (kY_SkAxisAlignment == baseline) { 1637 fxMask = 0; 1638 } 1639 1640 // apply bias here to avoid adding 1/2 the sampling frequency in the loop 1641 fx += SK_FixedHalf >> SkGlyph::kSubBits; 1642 fy += SK_FixedHalf >> SkGlyph::kSubBits; 1643 } else { 1644 fx += SK_FixedHalf; 1645 fy += SK_FixedHalf; 1646 } 1647 1648 SkAAClipBlitter aaBlitter; 1649 SkAutoBlitterChoose blitterChooser; 1650 SkBlitter* blitter = NULL; 1651 if (needsRasterTextBlit(*this)) { 1652 blitterChooser.choose(*fBitmap, *matrix, paint); 1653 blitter = blitterChooser.get(); 1654 if (fRC->isAA()) { 1655 aaBlitter.init(blitter, &fRC->aaRgn()); 1656 blitter = &aaBlitter; 1657 } 1658 } 1659 1660 SkAutoKern autokern; 1661 SkDraw1Glyph d1g; 1662 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); 1663 1664 while (text < stop) { 1665 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); 1666 1667 fx += autokern.adjust(glyph); 1668 1669 if (glyph.fWidth) { 1670 proc(d1g, fx, fy, glyph); 1671 } 1672 fx += glyph.fAdvanceX; 1673 fy += glyph.fAdvanceY; 1674 } 1675} 1676 1677// last parameter is interpreted as SkFixed [x, y] 1678// return the fixed position, which may be rounded or not by the caller 1679// e.g. subpixel doesn't round 1680typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); 1681 1682static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1683 SkIPoint* dst) { 1684 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); 1685} 1686 1687static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1688 SkIPoint* dst) { 1689 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), 1690 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); 1691} 1692 1693static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, 1694 SkIPoint* dst) { 1695 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, 1696 SkScalarToFixed(loc.fY) - glyph.fAdvanceY); 1697} 1698 1699static AlignProc pick_align_proc(SkPaint::Align align) { 1700 static const AlignProc gProcs[] = { 1701 leftAlignProc, centerAlignProc, rightAlignProc 1702 }; 1703 1704 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1705 1706 return gProcs[align]; 1707} 1708 1709class TextMapState { 1710public: 1711 mutable SkPoint fLoc; 1712 1713 TextMapState(const SkMatrix& matrix, SkScalar y) 1714 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} 1715 1716 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); 1717 1718 Proc pickProc(int scalarsPerPosition); 1719 1720private: 1721 const SkMatrix& fMatrix; 1722 SkMatrix::MapXYProc fProc; 1723 SkScalar fY; // ignored by MapXYProc 1724 // these are only used by Only... procs 1725 SkScalar fScaleX, fTransX, fTransformedY; 1726 1727 static void MapXProc(const TextMapState& state, const SkScalar pos[]) { 1728 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); 1729 } 1730 1731 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { 1732 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); 1733 } 1734 1735 static void MapOnlyScaleXProc(const TextMapState& state, 1736 const SkScalar pos[]) { 1737 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, 1738 state.fTransformedY); 1739 } 1740 1741 static void MapOnlyTransXProc(const TextMapState& state, 1742 const SkScalar pos[]) { 1743 state.fLoc.set(*pos + state.fTransX, state.fTransformedY); 1744 } 1745}; 1746 1747TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { 1748 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1749 1750 if (1 == scalarsPerPosition) { 1751 unsigned mtype = fMatrix.getType(); 1752 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1753 return MapXProc; 1754 } else { 1755 fScaleX = fMatrix.getScaleX(); 1756 fTransX = fMatrix.getTranslateX(); 1757 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + 1758 fMatrix.getTranslateY(); 1759 return (mtype & SkMatrix::kScale_Mask) ? 1760 MapOnlyScaleXProc : MapOnlyTransXProc; 1761 } 1762 } else { 1763 return MapXYProc; 1764 } 1765} 1766 1767////////////////////////////////////////////////////////////////////////////// 1768 1769void SkDraw::drawPosText(const char text[], size_t byteLength, 1770 const SkScalar pos[], SkScalar constY, 1771 int scalarsPerPosition, const SkPaint& paint) const { 1772 SkASSERT(byteLength == 0 || text != NULL); 1773 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1774 1775 SkDEBUGCODE(this->validate();) 1776 1777 // nothing to draw 1778 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1779 return; 1780 } 1781 1782 if (/*paint.isLinearText() ||*/ 1783 (fMatrix->hasPerspective())) { 1784 // TODO !!!! 1785// this->drawText_asPaths(text, byteLength, x, y, paint); 1786 return; 1787 } 1788 1789 const SkMatrix* matrix = fMatrix; 1790 1791 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1792 SkAutoGlyphCache autoCache(paint, matrix); 1793 SkGlyphCache* cache = autoCache.getCache(); 1794 1795 SkAAClipBlitterWrapper wrapper; 1796 SkAutoBlitterChoose blitterChooser; 1797 SkBlitter* blitter = NULL; 1798 if (needsRasterTextBlit(*this)) { 1799 blitterChooser.choose(*fBitmap, *matrix, paint); 1800 blitter = blitterChooser.get(); 1801 if (fRC->isAA()) { 1802 wrapper.init(*fRC, blitter); 1803 blitter = wrapper.getBlitter(); 1804 } 1805 } 1806 1807 const char* stop = text + byteLength; 1808 AlignProc alignProc = pick_align_proc(paint.getTextAlign()); 1809 SkDraw1Glyph d1g; 1810 SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); 1811 TextMapState tms(*matrix, constY); 1812 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1813 1814 if (cache->isSubpixel()) { 1815 // maybe we should skip the rounding if linearText is set 1816 SkAxisAlignment roundBaseline = SkComputeAxisAlignmentForHText(*matrix); 1817 1818 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1819 while (text < stop) { 1820 1821 tmsProc(tms, pos); 1822 1823#ifdef SK_DRAW_POS_TEXT_IGNORE_SUBPIXEL_LEFT_ALIGN_FIX 1824 SkFixed fx = SkScalarToFixed(tms.fLoc.fX); 1825 SkFixed fy = SkScalarToFixed(tms.fLoc.fY); 1826#else 1827 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + (SK_FixedHalf >> SkGlyph::kSubBits); 1828 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + (SK_FixedHalf >> SkGlyph::kSubBits); 1829#endif 1830 SkFixed fxMask = ~0; 1831 SkFixed fyMask = ~0; 1832 1833 if (kX_SkAxisAlignment == roundBaseline) { 1834 fyMask = 0; 1835 } else if (kY_SkAxisAlignment == roundBaseline) { 1836 fxMask = 0; 1837 } 1838 1839 const SkGlyph& glyph = glyphCacheProc(cache, &text, 1840 fx & fxMask, fy & fyMask); 1841 1842 if (glyph.fWidth) { 1843 proc(d1g, fx, fy, glyph); 1844 } 1845 pos += scalarsPerPosition; 1846 } 1847 } else { 1848 while (text < stop) { 1849 const char* currentText = text; 1850 const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0); 1851 1852 if (glyph->fWidth) { 1853 SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;) 1854 SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;) 1855 1856 SkFixed fx, fy; 1857 SkFixed fxMask = ~0; 1858 SkFixed fyMask = ~0; 1859 tmsProc(tms, pos); 1860 1861 { 1862 SkIPoint fixedLoc; 1863 alignProc(tms.fLoc, *glyph, &fixedLoc); 1864 fx = fixedLoc.fX + (SK_FixedHalf >> SkGlyph::kSubBits); 1865 fy = fixedLoc.fY + (SK_FixedHalf >> SkGlyph::kSubBits); 1866 1867 if (kX_SkAxisAlignment == roundBaseline) { 1868 fyMask = 0; 1869 } else if (kY_SkAxisAlignment == roundBaseline) { 1870 fxMask = 0; 1871 } 1872 } 1873 1874 // have to call again, now that we've been "aligned" 1875 glyph = &glyphCacheProc(cache, ¤tText, 1876 fx & fxMask, fy & fyMask); 1877 // the assumption is that the advance hasn't changed 1878 SkASSERT(prevAdvX == glyph->fAdvanceX); 1879 SkASSERT(prevAdvY == glyph->fAdvanceY); 1880 1881 proc(d1g, fx, fy, *glyph); 1882 } 1883 pos += scalarsPerPosition; 1884 } 1885 } 1886 } else { // not subpixel 1887 if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1888 while (text < stop) { 1889 // the last 2 parameters are ignored 1890 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1891 1892 if (glyph.fWidth) { 1893 tmsProc(tms, pos); 1894 1895 proc(d1g, 1896 SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, 1897 SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, 1898 glyph); 1899 } 1900 pos += scalarsPerPosition; 1901 } 1902 } else { 1903 while (text < stop) { 1904 // the last 2 parameters are ignored 1905 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1906 1907 if (glyph.fWidth) { 1908 tmsProc(tms, pos); 1909 1910 SkIPoint fixedLoc; 1911 alignProc(tms.fLoc, glyph, &fixedLoc); 1912 1913 proc(d1g, 1914 fixedLoc.fX + SK_FixedHalf, 1915 fixedLoc.fY + SK_FixedHalf, 1916 glyph); 1917 } 1918 pos += scalarsPerPosition; 1919 } 1920 } 1921 } 1922} 1923 1924#if defined _WIN32 && _MSC_VER >= 1300 1925#pragma warning ( pop ) 1926#endif 1927 1928/////////////////////////////////////////////////////////////////////////////// 1929 1930#include "SkPathMeasure.h" 1931 1932static void morphpoints(SkPoint dst[], const SkPoint src[], int count, 1933 SkPathMeasure& meas, const SkMatrix& matrix) { 1934 SkMatrix::MapXYProc proc = matrix.getMapXYProc(); 1935 1936 for (int i = 0; i < count; i++) { 1937 SkPoint pos; 1938 SkVector tangent; 1939 1940 proc(matrix, src[i].fX, src[i].fY, &pos); 1941 SkScalar sx = pos.fX; 1942 SkScalar sy = pos.fY; 1943 1944 if (!meas.getPosTan(sx, &pos, &tangent)) { 1945 // set to 0 if the measure failed, so that we just set dst == pos 1946 tangent.set(0, 0); 1947 } 1948 1949 /* This is the old way (that explains our approach but is way too slow 1950 SkMatrix matrix; 1951 SkPoint pt; 1952 1953 pt.set(sx, sy); 1954 matrix.setSinCos(tangent.fY, tangent.fX); 1955 matrix.preTranslate(-sx, 0); 1956 matrix.postTranslate(pos.fX, pos.fY); 1957 matrix.mapPoints(&dst[i], &pt, 1); 1958 */ 1959 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), 1960 pos.fY + SkScalarMul(tangent.fX, sy)); 1961 } 1962} 1963 1964/* TODO 1965 1966 Need differentially more subdivisions when the follow-path is curvy. Not sure how to 1967 determine that, but we need it. I guess a cheap answer is let the caller tell us, 1968 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 1969*/ 1970static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 1971 const SkMatrix& matrix) { 1972 SkPath::Iter iter(src, false); 1973 SkPoint srcP[4], dstP[3]; 1974 SkPath::Verb verb; 1975 1976 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 1977 switch (verb) { 1978 case SkPath::kMove_Verb: 1979 morphpoints(dstP, srcP, 1, meas, matrix); 1980 dst->moveTo(dstP[0]); 1981 break; 1982 case SkPath::kLine_Verb: 1983 // turn lines into quads to look bendy 1984 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); 1985 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); 1986 morphpoints(dstP, srcP, 2, meas, matrix); 1987 dst->quadTo(dstP[0], dstP[1]); 1988 break; 1989 case SkPath::kQuad_Verb: 1990 morphpoints(dstP, &srcP[1], 2, meas, matrix); 1991 dst->quadTo(dstP[0], dstP[1]); 1992 break; 1993 case SkPath::kCubic_Verb: 1994 morphpoints(dstP, &srcP[1], 3, meas, matrix); 1995 dst->cubicTo(dstP[0], dstP[1], dstP[2]); 1996 break; 1997 case SkPath::kClose_Verb: 1998 dst->close(); 1999 break; 2000 default: 2001 SkDEBUGFAIL("unknown verb"); 2002 break; 2003 } 2004 } 2005} 2006 2007void SkDraw::drawTextOnPath(const char text[], size_t byteLength, 2008 const SkPath& follow, const SkMatrix* matrix, 2009 const SkPaint& paint) const { 2010 SkASSERT(byteLength == 0 || text != NULL); 2011 2012 // nothing to draw 2013 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2014 return; 2015 } 2016 2017 SkTextToPathIter iter(text, byteLength, paint, true); 2018 SkPathMeasure meas(follow, false); 2019 SkScalar hOffset = 0; 2020 2021 // need to measure first 2022 if (paint.getTextAlign() != SkPaint::kLeft_Align) { 2023 SkScalar pathLen = meas.getLength(); 2024 if (paint.getTextAlign() == SkPaint::kCenter_Align) { 2025 pathLen = SkScalarHalf(pathLen); 2026 } 2027 hOffset += pathLen; 2028 } 2029 2030 const SkPath* iterPath; 2031 SkScalar xpos; 2032 SkMatrix scaledMatrix; 2033 SkScalar scale = iter.getPathScale(); 2034 2035 scaledMatrix.setScale(scale, scale); 2036 2037 while (iter.next(&iterPath, &xpos)) { 2038 if (iterPath) { 2039 SkPath tmp; 2040 SkMatrix m(scaledMatrix); 2041 2042 m.postTranslate(xpos + hOffset, 0); 2043 if (matrix) { 2044 m.postConcat(*matrix); 2045 } 2046 morphpath(&tmp, *iterPath, meas, m); 2047 if (fDevice) { 2048 fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true); 2049 } else { 2050 this->drawPath(tmp, iter.getPaint(), NULL, true); 2051 } 2052 } 2053 } 2054} 2055 2056#ifdef SK_BUILD_FOR_ANDROID 2057void SkDraw::drawPosTextOnPath(const char text[], size_t byteLength, 2058 const SkPoint pos[], const SkPaint& paint, 2059 const SkPath& path, const SkMatrix* matrix) const { 2060 // nothing to draw 2061 if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 2062 return; 2063 } 2064 2065 SkMatrix scaledMatrix; 2066 SkPathMeasure meas(path, false); 2067 2068 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc( 2069 SkPaint::kForward_TextBufferDirection, true); 2070 2071 // Copied (modified) from SkTextToPathIter constructor to setup paint 2072 SkPaint tempPaint(paint); 2073 2074 tempPaint.setLinearText(true); 2075 tempPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup 2076 2077 if (tempPaint.getPathEffect() == NULL && !(tempPaint.getStrokeWidth() > 0 2078 && tempPaint.getStyle() != SkPaint::kFill_Style)) { 2079 tempPaint.setStyle(SkPaint::kFill_Style); 2080 tempPaint.setPathEffect(NULL); 2081 } 2082 // End copied from SkTextToPathIter constructor 2083 2084 // detach cache 2085 SkGlyphCache* cache = tempPaint.detachCache(NULL); 2086 2087 // Must set scale, even if 1 2088 SkScalar scale = SK_Scalar1; 2089 scaledMatrix.setScale(scale, scale); 2090 2091 // Loop over all glyph ids 2092 for (const char* stop = text + byteLength; text < stop; pos++) { 2093 2094 const SkGlyph& glyph = glyphCacheProc(cache, &text); 2095 SkPath tmp; 2096 2097 const SkPath* glyphPath = cache->findPath(glyph); 2098 if (glyphPath == NULL) { 2099 continue; 2100 } 2101 2102 SkMatrix m(scaledMatrix); 2103 m.postTranslate(pos->fX, 0); 2104 2105 if (matrix) { 2106 m.postConcat(*matrix); 2107 } 2108 2109 morphpath(&tmp, *glyphPath, meas, m); 2110 this->drawPath(tmp, tempPaint); 2111 2112 } 2113 2114 // re-attach cache 2115 SkGlyphCache::AttachCache(cache); 2116} 2117#endif 2118 2119/////////////////////////////////////////////////////////////////////////////// 2120 2121struct VertState { 2122 int f0, f1, f2; 2123 2124 VertState(int vCount, const uint16_t indices[], int indexCount) 2125 : fIndices(indices) { 2126 fCurrIndex = 0; 2127 if (indices) { 2128 fCount = indexCount; 2129 } else { 2130 fCount = vCount; 2131 } 2132 } 2133 2134 typedef bool (*Proc)(VertState*); 2135 Proc chooseProc(SkCanvas::VertexMode mode); 2136 2137private: 2138 int fCount; 2139 int fCurrIndex; 2140 const uint16_t* fIndices; 2141 2142 static bool Triangles(VertState*); 2143 static bool TrianglesX(VertState*); 2144 static bool TriangleStrip(VertState*); 2145 static bool TriangleStripX(VertState*); 2146 static bool TriangleFan(VertState*); 2147 static bool TriangleFanX(VertState*); 2148}; 2149 2150bool VertState::Triangles(VertState* state) { 2151 int index = state->fCurrIndex; 2152 if (index + 3 > state->fCount) { 2153 return false; 2154 } 2155 state->f0 = index + 0; 2156 state->f1 = index + 1; 2157 state->f2 = index + 2; 2158 state->fCurrIndex = index + 3; 2159 return true; 2160} 2161 2162bool VertState::TrianglesX(VertState* state) { 2163 const uint16_t* indices = state->fIndices; 2164 int index = state->fCurrIndex; 2165 if (index + 3 > state->fCount) { 2166 return false; 2167 } 2168 state->f0 = indices[index + 0]; 2169 state->f1 = indices[index + 1]; 2170 state->f2 = indices[index + 2]; 2171 state->fCurrIndex = index + 3; 2172 return true; 2173} 2174 2175bool VertState::TriangleStrip(VertState* state) { 2176 int index = state->fCurrIndex; 2177 if (index + 3 > state->fCount) { 2178 return false; 2179 } 2180 state->f2 = index + 2; 2181 if (index & 1) { 2182 state->f0 = index + 1; 2183 state->f1 = index + 0; 2184 } else { 2185 state->f0 = index + 0; 2186 state->f1 = index + 1; 2187 } 2188 state->fCurrIndex = index + 1; 2189 return true; 2190} 2191 2192bool VertState::TriangleStripX(VertState* state) { 2193 const uint16_t* indices = state->fIndices; 2194 int index = state->fCurrIndex; 2195 if (index + 3 > state->fCount) { 2196 return false; 2197 } 2198 state->f2 = indices[index + 2]; 2199 if (index & 1) { 2200 state->f0 = indices[index + 1]; 2201 state->f1 = indices[index + 0]; 2202 } else { 2203 state->f0 = indices[index + 0]; 2204 state->f1 = indices[index + 1]; 2205 } 2206 state->fCurrIndex = index + 1; 2207 return true; 2208} 2209 2210bool VertState::TriangleFan(VertState* state) { 2211 int index = state->fCurrIndex; 2212 if (index + 3 > state->fCount) { 2213 return false; 2214 } 2215 state->f0 = 0; 2216 state->f1 = index + 1; 2217 state->f2 = index + 2; 2218 state->fCurrIndex = index + 1; 2219 return true; 2220} 2221 2222bool VertState::TriangleFanX(VertState* state) { 2223 const uint16_t* indices = state->fIndices; 2224 int index = state->fCurrIndex; 2225 if (index + 3 > state->fCount) { 2226 return false; 2227 } 2228 state->f0 = indices[0]; 2229 state->f1 = indices[index + 1]; 2230 state->f2 = indices[index + 2]; 2231 state->fCurrIndex = index + 1; 2232 return true; 2233} 2234 2235VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { 2236 switch (mode) { 2237 case SkCanvas::kTriangles_VertexMode: 2238 return fIndices ? TrianglesX : Triangles; 2239 case SkCanvas::kTriangleStrip_VertexMode: 2240 return fIndices ? TriangleStripX : TriangleStrip; 2241 case SkCanvas::kTriangleFan_VertexMode: 2242 return fIndices ? TriangleFanX : TriangleFan; 2243 default: 2244 return NULL; 2245 } 2246} 2247 2248typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&, 2249 SkBlitter*); 2250 2251static HairProc ChooseHairProc(bool doAntiAlias) { 2252 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 2253} 2254 2255static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 2256 const SkPoint texs[], SkMatrix* matrix) { 2257 SkPoint src[3], dst[3]; 2258 2259 src[0] = texs[state.f0]; 2260 src[1] = texs[state.f1]; 2261 src[2] = texs[state.f2]; 2262 dst[0] = verts[state.f0]; 2263 dst[1] = verts[state.f1]; 2264 dst[2] = verts[state.f2]; 2265 return matrix->setPolyToPoly(src, dst, 3); 2266} 2267 2268class SkTriColorShader : public SkShader { 2269public: 2270 SkTriColorShader() {} 2271 2272 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 2273 2274 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count); 2275 2276 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) 2277 2278protected: 2279 SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {} 2280 2281private: 2282 SkMatrix fDstToUnit; 2283 SkPMColor fColors[3]; 2284 2285 typedef SkShader INHERITED; 2286}; 2287 2288bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], 2289 int index0, int index1, int index2) { 2290 2291 fColors[0] = SkPreMultiplyColor(colors[index0]); 2292 fColors[1] = SkPreMultiplyColor(colors[index1]); 2293 fColors[2] = SkPreMultiplyColor(colors[index2]); 2294 2295 SkMatrix m, im; 2296 m.reset(); 2297 m.set(0, pts[index1].fX - pts[index0].fX); 2298 m.set(1, pts[index2].fX - pts[index0].fX); 2299 m.set(2, pts[index0].fX); 2300 m.set(3, pts[index1].fY - pts[index0].fY); 2301 m.set(4, pts[index2].fY - pts[index0].fY); 2302 m.set(5, pts[index0].fY); 2303 if (!m.invert(&im)) { 2304 return false; 2305 } 2306 return fDstToUnit.setConcat(im, this->getTotalInverse()); 2307} 2308 2309#include "SkColorPriv.h" 2310#include "SkComposeShader.h" 2311 2312static int ScalarTo256(SkScalar v) { 2313 int scale = SkScalarToFixed(v) >> 8; 2314 if (scale < 0) { 2315 scale = 0; 2316 } 2317 if (scale > 255) { 2318 scale = 255; 2319 } 2320 return SkAlpha255To256(scale); 2321} 2322 2323void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 2324 SkPoint src; 2325 2326 for (int i = 0; i < count; i++) { 2327 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 2328 x += 1; 2329 2330 int scale1 = ScalarTo256(src.fX); 2331 int scale2 = ScalarTo256(src.fY); 2332 int scale0 = 256 - scale1 - scale2; 2333 if (scale0 < 0) { 2334 if (scale1 > scale2) { 2335 scale2 = 256 - scale1; 2336 } else { 2337 scale1 = 256 - scale2; 2338 } 2339 scale0 = 0; 2340 } 2341 2342 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 2343 SkAlphaMulQ(fColors[1], scale1) + 2344 SkAlphaMulQ(fColors[2], scale2); 2345 } 2346} 2347 2348void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 2349 const SkPoint vertices[], const SkPoint textures[], 2350 const SkColor colors[], SkXfermode* xmode, 2351 const uint16_t indices[], int indexCount, 2352 const SkPaint& paint) const { 2353 SkASSERT(0 == count || NULL != vertices); 2354 2355 // abort early if there is nothing to draw 2356 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 2357 return; 2358 } 2359 2360 // transform out vertices into device coordinates 2361 SkAutoSTMalloc<16, SkPoint> storage(count); 2362 SkPoint* devVerts = storage.get(); 2363 fMatrix->mapPoints(devVerts, vertices, count); 2364 2365 if (fBounder) { 2366 SkRect bounds; 2367 bounds.set(devVerts, count); 2368 if (!fBounder->doRect(bounds, paint)) { 2369 return; 2370 } 2371 } 2372 2373 /* 2374 We can draw the vertices in 1 of 4 ways: 2375 2376 - solid color (no shader/texture[], no colors[]) 2377 - just colors (no shader/texture[], has colors[]) 2378 - just texture (has shader/texture[], no colors[]) 2379 - colors * texture (has shader/texture[], has colors[]) 2380 2381 Thus for texture drawing, we need both texture[] and a shader. 2382 */ 2383 2384 SkTriColorShader triShader; // must be above declaration of p 2385 SkPaint p(paint); 2386 2387 SkShader* shader = p.getShader(); 2388 if (NULL == shader) { 2389 // if we have no shader, we ignore the texture coordinates 2390 textures = NULL; 2391 } else if (NULL == textures) { 2392 // if we don't have texture coordinates, ignore the shader 2393 p.setShader(NULL); 2394 shader = NULL; 2395 } 2396 2397 // setup the custom shader (if needed) 2398 if (NULL != colors) { 2399 if (NULL == textures) { 2400 // just colors (no texture) 2401 p.setShader(&triShader); 2402 } else { 2403 // colors * texture 2404 SkASSERT(shader); 2405 bool releaseMode = false; 2406 if (NULL == xmode) { 2407 xmode = SkXfermode::Create(SkXfermode::kMultiply_Mode); 2408 releaseMode = true; 2409 } 2410 SkShader* compose = SkNEW_ARGS(SkComposeShader, 2411 (&triShader, shader, xmode)); 2412 p.setShader(compose)->unref(); 2413 if (releaseMode) { 2414 xmode->unref(); 2415 } 2416 } 2417 } 2418 2419 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); 2420 // setup our state and function pointer for iterating triangles 2421 VertState state(count, indices, indexCount); 2422 VertState::Proc vertProc = state.chooseProc(vmode); 2423 2424 if (NULL != textures || NULL != colors) { 2425 SkMatrix tempM; 2426 SkMatrix savedLocalM; 2427 if (shader) { 2428 savedLocalM = shader->getLocalMatrix(); 2429 } 2430 2431 if (NULL != colors) { 2432 if (!triShader.setContext(*fBitmap, p, *fMatrix)) { 2433 colors = NULL; 2434 } 2435 } 2436 2437 while (vertProc(&state)) { 2438 if (NULL != textures) { 2439 if (texture_to_matrix(state, vertices, textures, &tempM)) { 2440 tempM.postConcat(savedLocalM); 2441 shader->setLocalMatrix(tempM); 2442 // need to recal setContext since we changed the local matrix 2443 if (!shader->setContext(*fBitmap, p, *fMatrix)) { 2444 continue; 2445 } 2446 } 2447 } 2448 if (NULL != colors) { 2449 if (!triShader.setup(vertices, colors, 2450 state.f0, state.f1, state.f2)) { 2451 continue; 2452 } 2453 } 2454 2455 SkPoint tmp[] = { 2456 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 2457 }; 2458 SkScan::FillTriangle(tmp, *fRC, blitter.get()); 2459 } 2460 // now restore the shader's original local matrix 2461 if (NULL != shader) { 2462 shader->setLocalMatrix(savedLocalM); 2463 } 2464 } else { 2465 // no colors[] and no texture 2466 HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); 2467 const SkRasterClip& clip = *fRC; 2468 while (vertProc(&state)) { 2469 hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get()); 2470 hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get()); 2471 hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get()); 2472 } 2473 } 2474} 2475 2476/////////////////////////////////////////////////////////////////////////////// 2477/////////////////////////////////////////////////////////////////////////////// 2478 2479#ifdef SK_DEBUG 2480 2481void SkDraw::validate() const { 2482 SkASSERT(fBitmap != NULL); 2483 SkASSERT(fMatrix != NULL); 2484 SkASSERT(fClip != NULL); 2485 SkASSERT(fRC != NULL); 2486 2487 const SkIRect& cr = fRC->getBounds(); 2488 SkIRect br; 2489 2490 br.set(0, 0, fBitmap->width(), fBitmap->height()); 2491 SkASSERT(cr.isEmpty() || br.contains(cr)); 2492} 2493 2494#endif 2495 2496/////////////////////////////////////////////////////////////////////////////// 2497 2498SkBounder::SkBounder() { 2499 // initialize up front. This gets reset by SkCanvas before each draw call. 2500 fClip = &SkRegion::GetEmptyRegion(); 2501} 2502 2503bool SkBounder::doIRect(const SkIRect& r) { 2504 SkIRect rr; 2505 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); 2506} 2507 2508// TODO: change the prototype to take fixed, and update the callers 2509bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y, 2510 const SkGlyph& glyph) { 2511 SkIRect rr; 2512 if (!rr.intersect(fClip->getBounds(), r)) { 2513 return false; 2514 } 2515 GlyphRec rec; 2516 rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y)); 2517 rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX, 2518 rec.fLSB.fY + glyph.fAdvanceY); 2519 rec.fGlyphID = glyph.getGlyphID(); 2520 rec.fFlags = 0; 2521 return this->onIRectGlyph(rr, rec); 2522} 2523 2524bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, 2525 const SkPaint& paint) { 2526 SkIRect r; 2527 SkScalar v0, v1; 2528 2529 v0 = pt0.fX; 2530 v1 = pt1.fX; 2531 if (v0 > v1) { 2532 SkTSwap<SkScalar>(v0, v1); 2533 } 2534 r.fLeft = SkScalarFloor(v0); 2535 r.fRight = SkScalarCeil(v1); 2536 2537 v0 = pt0.fY; 2538 v1 = pt1.fY; 2539 if (v0 > v1) { 2540 SkTSwap<SkScalar>(v0, v1); 2541 } 2542 r.fTop = SkScalarFloor(v0); 2543 r.fBottom = SkScalarCeil(v1); 2544 2545 if (paint.isAntiAlias()) { 2546 r.inset(-1, -1); 2547 } 2548 return this->doIRect(r); 2549} 2550 2551bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { 2552 SkIRect r; 2553 2554 if (paint.getStyle() == SkPaint::kFill_Style) { 2555 rect.round(&r); 2556 } else { 2557 int rad = -1; 2558 rect.roundOut(&r); 2559 if (paint.isAntiAlias()) { 2560 rad = -2; 2561 } 2562 r.inset(rad, rad); 2563 } 2564 return this->doIRect(r); 2565} 2566 2567bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { 2568 SkIRect r; 2569 const SkRect& bounds = path.getBounds(); 2570 2571 if (doFill) { 2572 bounds.round(&r); 2573 } else { // hairline 2574 bounds.roundOut(&r); 2575 } 2576 2577 if (paint.isAntiAlias()) { 2578 r.inset(-1, -1); 2579 } 2580 return this->doIRect(r); 2581} 2582 2583void SkBounder::commit() { 2584 // override in subclass 2585} 2586 2587//////////////////////////////////////////////////////////////////////////////////////////////// 2588 2589#include "SkPath.h" 2590#include "SkDraw.h" 2591#include "SkRegion.h" 2592#include "SkBlitter.h" 2593 2594static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 2595 SkMaskFilter* filter, const SkMatrix* filterMatrix, 2596 SkIRect* bounds) { 2597 if (devPath.isEmpty()) { 2598 return false; 2599 } 2600 2601 // init our bounds from the path 2602 { 2603 SkRect pathBounds = devPath.getBounds(); 2604 pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf); 2605 pathBounds.roundOut(bounds); 2606 } 2607 2608 SkIPoint margin = SkIPoint::Make(0, 0); 2609 if (filter) { 2610 SkASSERT(filterMatrix); 2611 2612 SkMask srcM, dstM; 2613 2614 srcM.fBounds = *bounds; 2615 srcM.fFormat = SkMask::kA8_Format; 2616 srcM.fImage = NULL; 2617 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 2618 return false; 2619 } 2620 } 2621 2622 // (possibly) trim the bounds to reflect the clip 2623 // (plus whatever slop the filter needs) 2624 if (clipBounds) { 2625 SkIRect tmp = *clipBounds; 2626 // Ugh. Guard against gigantic margins from wacky filters. Without this 2627 // check we can request arbitrary amounts of slop beyond our visible 2628 // clip, and bring down the renderer (at least on finite RAM machines 2629 // like handsets, etc.). Need to balance this invented value between 2630 // quality of large filters like blurs, and the corresponding memory 2631 // requests. 2632 static const int MAX_MARGIN = 128; 2633 tmp.inset(-SkMin32(margin.fX, MAX_MARGIN), 2634 -SkMin32(margin.fY, MAX_MARGIN)); 2635 if (!bounds->intersect(tmp)) { 2636 return false; 2637 } 2638 } 2639 2640 return true; 2641} 2642 2643static void draw_into_mask(const SkMask& mask, const SkPath& devPath, 2644 SkPaint::Style style) { 2645 SkBitmap bm; 2646 SkDraw draw; 2647 SkRasterClip clip; 2648 SkMatrix matrix; 2649 SkPaint paint; 2650 2651 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 2652 bm.setPixels(mask.fImage); 2653 2654 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 2655 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 2656 -SkIntToScalar(mask.fBounds.fTop)); 2657 2658 draw.fBitmap = &bm; 2659 draw.fRC = &clip; 2660 draw.fClip = &clip.bwRgn(); 2661 draw.fMatrix = &matrix; 2662 draw.fBounder = NULL; 2663 paint.setAntiAlias(true); 2664 paint.setStyle(style); 2665 draw.drawPath(devPath, paint); 2666} 2667 2668bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 2669 SkMaskFilter* filter, const SkMatrix* filterMatrix, 2670 SkMask* mask, SkMask::CreateMode mode, 2671 SkPaint::Style style) { 2672 if (SkMask::kJustRenderImage_CreateMode != mode) { 2673 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 2674 return false; 2675 } 2676 2677 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 2678 mask->fFormat = SkMask::kA8_Format; 2679 mask->fRowBytes = mask->fBounds.width(); 2680 size_t size = mask->computeImageSize(); 2681 if (0 == size) { 2682 // we're too big to allocate the mask, abort 2683 return false; 2684 } 2685 mask->fImage = SkMask::AllocImage(size); 2686 memset(mask->fImage, 0, mask->computeImageSize()); 2687 } 2688 2689 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2690 draw_into_mask(*mask, devPath, style); 2691 } 2692 2693 return true; 2694} 2695