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