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