gfx/skia/trunk/src/core/SkDraw.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial