1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkDraw.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2814 @@ 1.4 +/* 1.5 + * Copyright 2006 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkDraw.h" 1.12 +#include "SkBlitter.h" 1.13 +#include "SkBounder.h" 1.14 +#include "SkCanvas.h" 1.15 +#include "SkColorPriv.h" 1.16 +#include "SkDevice.h" 1.17 +#include "SkDeviceLooper.h" 1.18 +#include "SkFixed.h" 1.19 +#include "SkMaskFilter.h" 1.20 +#include "SkPaint.h" 1.21 +#include "SkPathEffect.h" 1.22 +#include "SkRasterClip.h" 1.23 +#include "SkRasterizer.h" 1.24 +#include "SkRRect.h" 1.25 +#include "SkScan.h" 1.26 +#include "SkShader.h" 1.27 +#include "SkSmallAllocator.h" 1.28 +#include "SkString.h" 1.29 +#include "SkStroke.h" 1.30 +#include "SkTLazy.h" 1.31 +#include "SkUtils.h" 1.32 + 1.33 +#include "SkAutoKern.h" 1.34 +#include "SkBitmapProcShader.h" 1.35 +#include "SkDrawProcs.h" 1.36 +#include "SkMatrixUtils.h" 1.37 + 1.38 + 1.39 +//#define TRACE_BITMAP_DRAWS 1.40 + 1.41 + 1.42 +/** Helper for allocating small blitters on the stack. 1.43 + */ 1.44 +class SkAutoBlitterChoose : SkNoncopyable { 1.45 +public: 1.46 + SkAutoBlitterChoose() { 1.47 + fBlitter = NULL; 1.48 + } 1.49 + SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix, 1.50 + const SkPaint& paint, bool drawCoverage = false) { 1.51 + fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator, 1.52 + drawCoverage); 1.53 + } 1.54 + 1.55 + SkBlitter* operator->() { return fBlitter; } 1.56 + SkBlitter* get() const { return fBlitter; } 1.57 + 1.58 + void choose(const SkBitmap& device, const SkMatrix& matrix, 1.59 + const SkPaint& paint) { 1.60 + SkASSERT(!fBlitter); 1.61 + fBlitter = SkBlitter::Choose(device, matrix, paint, &fAllocator); 1.62 + } 1.63 + 1.64 +private: 1.65 + // Owned by fAllocator, which will handle the delete. 1.66 + SkBlitter* fBlitter; 1.67 + SkTBlitterAllocator fAllocator; 1.68 +}; 1.69 +#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose) 1.70 + 1.71 +/** 1.72 + * Since we are providing the storage for the shader (to avoid the perf cost 1.73 + * of calling new) we insist that in our destructor we can account for all 1.74 + * owners of the shader. 1.75 + */ 1.76 +class SkAutoBitmapShaderInstall : SkNoncopyable { 1.77 +public: 1.78 + SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint) 1.79 + : fPaint(paint) /* makes a copy of the paint */ { 1.80 + fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode, 1.81 + SkShader::kClamp_TileMode, 1.82 + &fAllocator)); 1.83 + // we deliberately left the shader with an owner-count of 2 1.84 + SkASSERT(2 == fPaint.getShader()->getRefCnt()); 1.85 + } 1.86 + 1.87 + ~SkAutoBitmapShaderInstall() { 1.88 + // since fAllocator will destroy shader, we insist that owners == 2 1.89 + SkASSERT(2 == fPaint.getShader()->getRefCnt()); 1.90 + 1.91 + fPaint.setShader(NULL); // unref the shader by 1 1.92 + 1.93 + } 1.94 + 1.95 + // return the new paint that has the shader applied 1.96 + const SkPaint& paintWithShader() const { return fPaint; } 1.97 + 1.98 +private: 1.99 + // copy of caller's paint (which we then modify) 1.100 + SkPaint fPaint; 1.101 + // Stores the shader. 1.102 + SkTBlitterAllocator fAllocator; 1.103 +}; 1.104 +#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall) 1.105 + 1.106 +/////////////////////////////////////////////////////////////////////////////// 1.107 + 1.108 +SkDraw::SkDraw() { 1.109 + sk_bzero(this, sizeof(*this)); 1.110 +} 1.111 + 1.112 +SkDraw::SkDraw(const SkDraw& src) { 1.113 + memcpy(this, &src, sizeof(*this)); 1.114 +} 1.115 + 1.116 +bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 1.117 + if (fRC->isEmpty()) { 1.118 + return false; 1.119 + } 1.120 + 1.121 + SkMatrix inverse; 1.122 + if (!fMatrix->invert(&inverse)) { 1.123 + return false; 1.124 + } 1.125 + 1.126 + SkIRect devBounds = fRC->getBounds(); 1.127 + // outset to have slop for antialasing and hairlines 1.128 + devBounds.outset(1, 1); 1.129 + inverse.mapRect(localBounds, SkRect::Make(devBounds)); 1.130 + return true; 1.131 +} 1.132 + 1.133 +/////////////////////////////////////////////////////////////////////////////// 1.134 + 1.135 +typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 1.136 + 1.137 +static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 1.138 + sk_bzero(pixels, bytes); 1.139 +} 1.140 + 1.141 +static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 1.142 + 1.143 +static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 1.144 + sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2)); 1.145 +} 1.146 + 1.147 +static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 1.148 + sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1)); 1.149 +} 1.150 + 1.151 +static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 1.152 + memset(pixels, data, bytes); 1.153 +} 1.154 + 1.155 +static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap, 1.156 + const SkPaint& paint, 1.157 + uint32_t* data) { 1.158 + // todo: we can apply colorfilter up front if no shader, so we wouldn't 1.159 + // need to abort this fastpath 1.160 + if (paint.getShader() || paint.getColorFilter()) { 1.161 + return NULL; 1.162 + } 1.163 + 1.164 + SkXfermode::Mode mode; 1.165 + if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { 1.166 + return NULL; 1.167 + } 1.168 + 1.169 + SkColor color = paint.getColor(); 1.170 + 1.171 + // collaps modes based on color... 1.172 + if (SkXfermode::kSrcOver_Mode == mode) { 1.173 + unsigned alpha = SkColorGetA(color); 1.174 + if (0 == alpha) { 1.175 + mode = SkXfermode::kDst_Mode; 1.176 + } else if (0xFF == alpha) { 1.177 + mode = SkXfermode::kSrc_Mode; 1.178 + } 1.179 + } 1.180 + 1.181 + switch (mode) { 1.182 + case SkXfermode::kClear_Mode: 1.183 +// SkDebugf("--- D_Clear_BitmapXferProc\n"); 1.184 + return D_Clear_BitmapXferProc; // ignore data 1.185 + case SkXfermode::kDst_Mode: 1.186 +// SkDebugf("--- D_Dst_BitmapXferProc\n"); 1.187 + return D_Dst_BitmapXferProc; // ignore data 1.188 + case SkXfermode::kSrc_Mode: { 1.189 + /* 1.190 + should I worry about dithering for the lower depths? 1.191 + */ 1.192 + SkPMColor pmc = SkPreMultiplyColor(color); 1.193 + switch (bitmap.colorType()) { 1.194 + case kPMColor_SkColorType: 1.195 + if (data) { 1.196 + *data = pmc; 1.197 + } 1.198 +// SkDebugf("--- D32_Src_BitmapXferProc\n"); 1.199 + return D32_Src_BitmapXferProc; 1.200 + case kRGB_565_SkColorType: 1.201 + if (data) { 1.202 + *data = SkPixel32ToPixel16(pmc); 1.203 + } 1.204 +// SkDebugf("--- D16_Src_BitmapXferProc\n"); 1.205 + return D16_Src_BitmapXferProc; 1.206 + case kAlpha_8_SkColorType: 1.207 + if (data) { 1.208 + *data = SkGetPackedA32(pmc); 1.209 + } 1.210 +// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 1.211 + return DA8_Src_BitmapXferProc; 1.212 + default: 1.213 + break; 1.214 + } 1.215 + break; 1.216 + } 1.217 + default: 1.218 + break; 1.219 + } 1.220 + return NULL; 1.221 +} 1.222 + 1.223 +static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect, 1.224 + BitmapXferProc proc, uint32_t procData) { 1.225 + int shiftPerPixel; 1.226 + switch (bitmap.colorType()) { 1.227 + case kPMColor_SkColorType: 1.228 + shiftPerPixel = 2; 1.229 + break; 1.230 + case kRGB_565_SkColorType: 1.231 + shiftPerPixel = 1; 1.232 + break; 1.233 + case kAlpha_8_SkColorType: 1.234 + shiftPerPixel = 0; 1.235 + break; 1.236 + default: 1.237 + SkDEBUGFAIL("Can't use xferproc on this config"); 1.238 + return; 1.239 + } 1.240 + 1.241 + uint8_t* pixels = (uint8_t*)bitmap.getPixels(); 1.242 + SkASSERT(pixels); 1.243 + const size_t rowBytes = bitmap.rowBytes(); 1.244 + const int widthBytes = rect.width() << shiftPerPixel; 1.245 + 1.246 + // skip down to the first scanline and X position 1.247 + pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 1.248 + for (int scans = rect.height() - 1; scans >= 0; --scans) { 1.249 + proc(pixels, widthBytes, procData); 1.250 + pixels += rowBytes; 1.251 + } 1.252 +} 1.253 + 1.254 +void SkDraw::drawPaint(const SkPaint& paint) const { 1.255 + SkDEBUGCODE(this->validate();) 1.256 + 1.257 + if (fRC->isEmpty()) { 1.258 + return; 1.259 + } 1.260 + 1.261 + SkIRect devRect; 1.262 + devRect.set(0, 0, fBitmap->width(), fBitmap->height()); 1.263 + if (fBounder && !fBounder->doIRect(devRect)) { 1.264 + return; 1.265 + } 1.266 + 1.267 + if (fRC->isBW()) { 1.268 + /* If we don't have a shader (i.e. we're just a solid color) we may 1.269 + be faster to operate directly on the device bitmap, rather than invoking 1.270 + a blitter. Esp. true for xfermodes, which require a colorshader to be 1.271 + present, which is just redundant work. Since we're drawing everywhere 1.272 + in the clip, we don't have to worry about antialiasing. 1.273 + */ 1.274 + uint32_t procData = 0; // to avoid the warning 1.275 + BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData); 1.276 + if (proc) { 1.277 + if (D_Dst_BitmapXferProc == proc) { // nothing to do 1.278 + return; 1.279 + } 1.280 + 1.281 + SkRegion::Iterator iter(fRC->bwRgn()); 1.282 + while (!iter.done()) { 1.283 + CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData); 1.284 + iter.next(); 1.285 + } 1.286 + return; 1.287 + } 1.288 + } 1.289 + 1.290 + // normal case: use a blitter 1.291 + SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 1.292 + SkScan::FillIRect(devRect, *fRC, blitter.get()); 1.293 +} 1.294 + 1.295 +/////////////////////////////////////////////////////////////////////////////// 1.296 + 1.297 +struct PtProcRec { 1.298 + SkCanvas::PointMode fMode; 1.299 + const SkPaint* fPaint; 1.300 + const SkRegion* fClip; 1.301 + const SkRasterClip* fRC; 1.302 + 1.303 + // computed values 1.304 + SkFixed fRadius; 1.305 + 1.306 + typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 1.307 + SkBlitter*); 1.308 + 1.309 + bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 1.310 + const SkRasterClip*); 1.311 + Proc chooseProc(SkBlitter** blitter); 1.312 + 1.313 +private: 1.314 + SkAAClipBlitterWrapper fWrapper; 1.315 +}; 1.316 + 1.317 +static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.318 + int count, SkBlitter* blitter) { 1.319 + SkASSERT(rec.fClip->isRect()); 1.320 + const SkIRect& r = rec.fClip->getBounds(); 1.321 + 1.322 + for (int i = 0; i < count; i++) { 1.323 + int x = SkScalarFloorToInt(devPts[i].fX); 1.324 + int y = SkScalarFloorToInt(devPts[i].fY); 1.325 + if (r.contains(x, y)) { 1.326 + blitter->blitH(x, y, 1); 1.327 + } 1.328 + } 1.329 +} 1.330 + 1.331 +static void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 1.332 + const SkPoint devPts[], int count, 1.333 + SkBlitter* blitter) { 1.334 + SkASSERT(rec.fRC->isRect()); 1.335 + const SkIRect& r = rec.fRC->getBounds(); 1.336 + uint32_t value; 1.337 + const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value); 1.338 + SkASSERT(bitmap); 1.339 + 1.340 + uint16_t* addr = bitmap->getAddr16(0, 0); 1.341 + size_t rb = bitmap->rowBytes(); 1.342 + 1.343 + for (int i = 0; i < count; i++) { 1.344 + int x = SkScalarFloorToInt(devPts[i].fX); 1.345 + int y = SkScalarFloorToInt(devPts[i].fY); 1.346 + if (r.contains(x, y)) { 1.347 + ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 1.348 + } 1.349 + } 1.350 +} 1.351 + 1.352 +static void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 1.353 + const SkPoint devPts[], int count, 1.354 + SkBlitter* blitter) { 1.355 + SkASSERT(rec.fRC->isRect()); 1.356 + const SkIRect& r = rec.fRC->getBounds(); 1.357 + uint32_t value; 1.358 + const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value); 1.359 + SkASSERT(bitmap); 1.360 + 1.361 + SkPMColor* addr = bitmap->getAddr32(0, 0); 1.362 + size_t rb = bitmap->rowBytes(); 1.363 + 1.364 + for (int i = 0; i < count; i++) { 1.365 + int x = SkScalarFloorToInt(devPts[i].fX); 1.366 + int y = SkScalarFloorToInt(devPts[i].fY); 1.367 + if (r.contains(x, y)) { 1.368 + ((SkPMColor*)((char*)addr + y * rb))[x] = value; 1.369 + } 1.370 + } 1.371 +} 1.372 + 1.373 +static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.374 + int count, SkBlitter* blitter) { 1.375 + for (int i = 0; i < count; i++) { 1.376 + int x = SkScalarFloorToInt(devPts[i].fX); 1.377 + int y = SkScalarFloorToInt(devPts[i].fY); 1.378 + if (rec.fClip->contains(x, y)) { 1.379 + blitter->blitH(x, y, 1); 1.380 + } 1.381 + } 1.382 +} 1.383 + 1.384 +static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.385 + int count, SkBlitter* blitter) { 1.386 + for (int i = 0; i < count; i += 2) { 1.387 + SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 1.388 + } 1.389 +} 1.390 + 1.391 +static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.392 + int count, SkBlitter* blitter) { 1.393 + for (int i = 0; i < count - 1; i++) { 1.394 + SkScan::HairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 1.395 + } 1.396 +} 1.397 + 1.398 +// aa versions 1.399 + 1.400 +static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.401 + int count, SkBlitter* blitter) { 1.402 + for (int i = 0; i < count; i += 2) { 1.403 + SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 1.404 + } 1.405 +} 1.406 + 1.407 +static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 1.408 + int count, SkBlitter* blitter) { 1.409 + for (int i = 0; i < count - 1; i++) { 1.410 + SkScan::AntiHairLine(devPts[i], devPts[i+1], *rec.fRC, blitter); 1.411 + } 1.412 +} 1.413 + 1.414 +// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 1.415 + 1.416 +static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 1.417 + int count, SkBlitter* blitter) { 1.418 + const SkFixed radius = rec.fRadius; 1.419 + for (int i = 0; i < count; i++) { 1.420 + SkFixed x = SkScalarToFixed(devPts[i].fX); 1.421 + SkFixed y = SkScalarToFixed(devPts[i].fY); 1.422 + 1.423 + SkXRect r; 1.424 + r.fLeft = x - radius; 1.425 + r.fTop = y - radius; 1.426 + r.fRight = x + radius; 1.427 + r.fBottom = y + radius; 1.428 + 1.429 + SkScan::FillXRect(r, *rec.fRC, blitter); 1.430 + } 1.431 +} 1.432 + 1.433 +static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 1.434 + int count, SkBlitter* blitter) { 1.435 + const SkFixed radius = rec.fRadius; 1.436 + for (int i = 0; i < count; i++) { 1.437 + SkFixed x = SkScalarToFixed(devPts[i].fX); 1.438 + SkFixed y = SkScalarToFixed(devPts[i].fY); 1.439 + 1.440 + SkXRect r; 1.441 + r.fLeft = x - radius; 1.442 + r.fTop = y - radius; 1.443 + r.fRight = x + radius; 1.444 + r.fBottom = y + radius; 1.445 + 1.446 + SkScan::AntiFillXRect(r, *rec.fRC, blitter); 1.447 + } 1.448 +} 1.449 + 1.450 +// If this guy returns true, then chooseProc() must return a valid proc 1.451 +bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 1.452 + const SkMatrix* matrix, const SkRasterClip* rc) { 1.453 + if (paint.getPathEffect()) { 1.454 + return false; 1.455 + } 1.456 + SkScalar width = paint.getStrokeWidth(); 1.457 + if (0 == width) { 1.458 + fMode = mode; 1.459 + fPaint = &paint; 1.460 + fClip = NULL; 1.461 + fRC = rc; 1.462 + fRadius = SK_FixedHalf; 1.463 + return true; 1.464 + } 1.465 + if (paint.getStrokeCap() != SkPaint::kRound_Cap && 1.466 + matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) { 1.467 + SkScalar sx = matrix->get(SkMatrix::kMScaleX); 1.468 + SkScalar sy = matrix->get(SkMatrix::kMScaleY); 1.469 + if (SkScalarNearlyZero(sx - sy)) { 1.470 + if (sx < 0) { 1.471 + sx = -sx; 1.472 + } 1.473 + 1.474 + fMode = mode; 1.475 + fPaint = &paint; 1.476 + fClip = NULL; 1.477 + fRC = rc; 1.478 + fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; 1.479 + return true; 1.480 + } 1.481 + } 1.482 + return false; 1.483 +} 1.484 + 1.485 +PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 1.486 + Proc proc = NULL; 1.487 + 1.488 + SkBlitter* blitter = *blitterPtr; 1.489 + if (fRC->isBW()) { 1.490 + fClip = &fRC->bwRgn(); 1.491 + } else { 1.492 + fWrapper.init(*fRC, blitter); 1.493 + fClip = &fWrapper.getRgn(); 1.494 + blitter = fWrapper.getBlitter(); 1.495 + *blitterPtr = blitter; 1.496 + } 1.497 + 1.498 + // for our arrays 1.499 + SkASSERT(0 == SkCanvas::kPoints_PointMode); 1.500 + SkASSERT(1 == SkCanvas::kLines_PointMode); 1.501 + SkASSERT(2 == SkCanvas::kPolygon_PointMode); 1.502 + SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 1.503 + 1.504 + if (fPaint->isAntiAlias()) { 1.505 + if (0 == fPaint->getStrokeWidth()) { 1.506 + static const Proc gAAProcs[] = { 1.507 + aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 1.508 + }; 1.509 + proc = gAAProcs[fMode]; 1.510 + } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 1.511 + SkASSERT(SkCanvas::kPoints_PointMode == fMode); 1.512 + proc = aa_square_proc; 1.513 + } 1.514 + } else { // BW 1.515 + if (fRadius <= SK_FixedHalf) { // small radii and hairline 1.516 + if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 1.517 + uint32_t value; 1.518 + const SkBitmap* bm = blitter->justAnOpaqueColor(&value); 1.519 + if (bm && kRGB_565_SkColorType == bm->colorType()) { 1.520 + proc = bw_pt_rect_16_hair_proc; 1.521 + } else if (bm && kPMColor_SkColorType == bm->colorType()) { 1.522 + proc = bw_pt_rect_32_hair_proc; 1.523 + } else { 1.524 + proc = bw_pt_rect_hair_proc; 1.525 + } 1.526 + } else { 1.527 + static Proc gBWProcs[] = { 1.528 + bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 1.529 + }; 1.530 + proc = gBWProcs[fMode]; 1.531 + } 1.532 + } else { 1.533 + proc = bw_square_proc; 1.534 + } 1.535 + } 1.536 + return proc; 1.537 +} 1.538 + 1.539 +static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode, 1.540 + size_t count, const SkPoint pts[], 1.541 + const SkPaint& paint, const SkMatrix& matrix) { 1.542 + SkIRect ibounds; 1.543 + SkRect bounds; 1.544 + SkScalar inset = paint.getStrokeWidth(); 1.545 + 1.546 + bounds.set(pts, SkToInt(count)); 1.547 + bounds.inset(-inset, -inset); 1.548 + matrix.mapRect(&bounds); 1.549 + 1.550 + bounds.roundOut(&ibounds); 1.551 + return bounder->doIRect(ibounds); 1.552 +} 1.553 + 1.554 +// each of these costs 8-bytes of stack space, so don't make it too large 1.555 +// must be even for lines/polygon to work 1.556 +#define MAX_DEV_PTS 32 1.557 + 1.558 +void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 1.559 + const SkPoint pts[], const SkPaint& paint, 1.560 + bool forceUseDevice) const { 1.561 + // if we're in lines mode, force count to be even 1.562 + if (SkCanvas::kLines_PointMode == mode) { 1.563 + count &= ~(size_t)1; 1.564 + } 1.565 + 1.566 + if ((long)count <= 0) { 1.567 + return; 1.568 + } 1.569 + 1.570 + SkASSERT(pts != NULL); 1.571 + SkDEBUGCODE(this->validate();) 1.572 + 1.573 + // nothing to draw 1.574 + if (fRC->isEmpty()) { 1.575 + return; 1.576 + } 1.577 + 1.578 + if (fBounder) { 1.579 + if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) { 1.580 + return; 1.581 + } 1.582 + 1.583 + // clear the bounder and call this again, so we don't invoke the bounder 1.584 + // later if we happen to call ourselves for drawRect, drawPath, etc. 1.585 + SkDraw noBounder(*this); 1.586 + noBounder.fBounder = NULL; 1.587 + noBounder.drawPoints(mode, count, pts, paint, forceUseDevice); 1.588 + return; 1.589 + } 1.590 + 1.591 + PtProcRec rec; 1.592 + if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { 1.593 + SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 1.594 + 1.595 + SkPoint devPts[MAX_DEV_PTS]; 1.596 + const SkMatrix* matrix = fMatrix; 1.597 + SkBlitter* bltr = blitter.get(); 1.598 + PtProcRec::Proc proc = rec.chooseProc(&bltr); 1.599 + // we have to back up subsequent passes if we're in polygon mode 1.600 + const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 1.601 + 1.602 + do { 1.603 + int n = SkToInt(count); 1.604 + if (n > MAX_DEV_PTS) { 1.605 + n = MAX_DEV_PTS; 1.606 + } 1.607 + matrix->mapPoints(devPts, pts, n); 1.608 + proc(rec, devPts, n, bltr); 1.609 + pts += n - backup; 1.610 + SkASSERT(SkToInt(count) >= n); 1.611 + count -= n; 1.612 + if (count > 0) { 1.613 + count += backup; 1.614 + } 1.615 + } while (count != 0); 1.616 + } else { 1.617 + switch (mode) { 1.618 + case SkCanvas::kPoints_PointMode: { 1.619 + // temporarily mark the paint as filling. 1.620 + SkPaint newPaint(paint); 1.621 + newPaint.setStyle(SkPaint::kFill_Style); 1.622 + 1.623 + SkScalar width = newPaint.getStrokeWidth(); 1.624 + SkScalar radius = SkScalarHalf(width); 1.625 + 1.626 + if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 1.627 + SkPath path; 1.628 + SkMatrix preMatrix; 1.629 + 1.630 + path.addCircle(0, 0, radius); 1.631 + for (size_t i = 0; i < count; i++) { 1.632 + preMatrix.setTranslate(pts[i].fX, pts[i].fY); 1.633 + // pass true for the last point, since we can modify 1.634 + // then path then 1.635 + if (fDevice) { 1.636 + fDevice->drawPath(*this, path, newPaint, &preMatrix, 1.637 + (count-1) == i); 1.638 + } else { 1.639 + this->drawPath(path, newPaint, &preMatrix, 1.640 + (count-1) == i); 1.641 + } 1.642 + } 1.643 + } else { 1.644 + SkRect r; 1.645 + 1.646 + for (size_t i = 0; i < count; i++) { 1.647 + r.fLeft = pts[i].fX - radius; 1.648 + r.fTop = pts[i].fY - radius; 1.649 + r.fRight = r.fLeft + width; 1.650 + r.fBottom = r.fTop + width; 1.651 + if (fDevice) { 1.652 + fDevice->drawRect(*this, r, newPaint); 1.653 + } else { 1.654 + this->drawRect(r, newPaint); 1.655 + } 1.656 + } 1.657 + } 1.658 + break; 1.659 + } 1.660 + case SkCanvas::kLines_PointMode: 1.661 +#ifndef SK_DISABLE_DASHING_OPTIMIZATION 1.662 + if (2 == count && NULL != paint.getPathEffect()) { 1.663 + // most likely a dashed line - see if it is one of the ones 1.664 + // we can accelerate 1.665 + SkStrokeRec rec(paint); 1.666 + SkPathEffect::PointData pointData; 1.667 + 1.668 + SkPath path; 1.669 + path.moveTo(pts[0]); 1.670 + path.lineTo(pts[1]); 1.671 + 1.672 + SkRect cullRect = SkRect::Make(fRC->getBounds()); 1.673 + 1.674 + if (paint.getPathEffect()->asPoints(&pointData, path, rec, 1.675 + *fMatrix, &cullRect)) { 1.676 + // 'asPoints' managed to find some fast path 1.677 + 1.678 + SkPaint newP(paint); 1.679 + newP.setPathEffect(NULL); 1.680 + newP.setStyle(SkPaint::kFill_Style); 1.681 + 1.682 + if (!pointData.fFirst.isEmpty()) { 1.683 + if (fDevice) { 1.684 + fDevice->drawPath(*this, pointData.fFirst, newP); 1.685 + } else { 1.686 + this->drawPath(pointData.fFirst, newP); 1.687 + } 1.688 + } 1.689 + 1.690 + if (!pointData.fLast.isEmpty()) { 1.691 + if (fDevice) { 1.692 + fDevice->drawPath(*this, pointData.fLast, newP); 1.693 + } else { 1.694 + this->drawPath(pointData.fLast, newP); 1.695 + } 1.696 + } 1.697 + 1.698 + if (pointData.fSize.fX == pointData.fSize.fY) { 1.699 + // The rest of the dashed line can just be drawn as points 1.700 + SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 1.701 + 1.702 + if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 1.703 + newP.setStrokeCap(SkPaint::kRound_Cap); 1.704 + } else { 1.705 + newP.setStrokeCap(SkPaint::kButt_Cap); 1.706 + } 1.707 + 1.708 + if (fDevice) { 1.709 + fDevice->drawPoints(*this, 1.710 + SkCanvas::kPoints_PointMode, 1.711 + pointData.fNumPoints, 1.712 + pointData.fPoints, 1.713 + newP); 1.714 + } else { 1.715 + this->drawPoints(SkCanvas::kPoints_PointMode, 1.716 + pointData.fNumPoints, 1.717 + pointData.fPoints, 1.718 + newP, 1.719 + forceUseDevice); 1.720 + } 1.721 + break; 1.722 + } else { 1.723 + // The rest of the dashed line must be drawn as rects 1.724 + SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 1.725 + pointData.fFlags)); 1.726 + 1.727 + SkRect r; 1.728 + 1.729 + for (int i = 0; i < pointData.fNumPoints; ++i) { 1.730 + r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 1.731 + pointData.fPoints[i].fY - pointData.fSize.fY, 1.732 + pointData.fPoints[i].fX + pointData.fSize.fX, 1.733 + pointData.fPoints[i].fY + pointData.fSize.fY); 1.734 + if (fDevice) { 1.735 + fDevice->drawRect(*this, r, newP); 1.736 + } else { 1.737 + this->drawRect(r, newP); 1.738 + } 1.739 + } 1.740 + } 1.741 + 1.742 + break; 1.743 + } 1.744 + } 1.745 +#endif // DISABLE_DASHING_OPTIMIZATION 1.746 + // couldn't take fast path so fall through! 1.747 + case SkCanvas::kPolygon_PointMode: { 1.748 + count -= 1; 1.749 + SkPath path; 1.750 + SkPaint p(paint); 1.751 + p.setStyle(SkPaint::kStroke_Style); 1.752 + size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 1.753 + for (size_t i = 0; i < count; i += inc) { 1.754 + path.moveTo(pts[i]); 1.755 + path.lineTo(pts[i+1]); 1.756 + if (fDevice) { 1.757 + fDevice->drawPath(*this, path, p, NULL, true); 1.758 + } else { 1.759 + this->drawPath(path, p, NULL, true); 1.760 + } 1.761 + path.rewind(); 1.762 + } 1.763 + break; 1.764 + } 1.765 + } 1.766 + } 1.767 +} 1.768 + 1.769 +static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 1.770 + SkPoint* strokeSize) { 1.771 + if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 1.772 + paint.getStrokeMiter() < SK_ScalarSqrt2) { 1.773 + return false; 1.774 + } 1.775 + 1.776 + SkASSERT(matrix.rectStaysRect()); 1.777 + SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 1.778 + matrix.mapVectors(strokeSize, &pt, 1); 1.779 + strokeSize->fX = SkScalarAbs(strokeSize->fX); 1.780 + strokeSize->fY = SkScalarAbs(strokeSize->fY); 1.781 + return true; 1.782 +} 1.783 + 1.784 +SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 1.785 + const SkMatrix& matrix, 1.786 + SkPoint* strokeSize) { 1.787 + RectType rtype; 1.788 + const SkScalar width = paint.getStrokeWidth(); 1.789 + const bool zeroWidth = (0 == width); 1.790 + SkPaint::Style style = paint.getStyle(); 1.791 + 1.792 + if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 1.793 + style = SkPaint::kFill_Style; 1.794 + } 1.795 + 1.796 + if (paint.getPathEffect() || paint.getMaskFilter() || 1.797 + paint.getRasterizer() || !matrix.rectStaysRect() || 1.798 + SkPaint::kStrokeAndFill_Style == style) { 1.799 + rtype = kPath_RectType; 1.800 + } else if (SkPaint::kFill_Style == style) { 1.801 + rtype = kFill_RectType; 1.802 + } else if (zeroWidth) { 1.803 + rtype = kHair_RectType; 1.804 + } else if (easy_rect_join(paint, matrix, strokeSize)) { 1.805 + rtype = kStroke_RectType; 1.806 + } else { 1.807 + rtype = kPath_RectType; 1.808 + } 1.809 + return rtype; 1.810 +} 1.811 + 1.812 +static const SkPoint* rect_points(const SkRect& r) { 1.813 + return SkTCast<const SkPoint*>(&r); 1.814 +} 1.815 + 1.816 +static SkPoint* rect_points(SkRect& r) { 1.817 + return SkTCast<SkPoint*>(&r); 1.818 +} 1.819 + 1.820 +void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const { 1.821 + SkDEBUGCODE(this->validate();) 1.822 + 1.823 + // nothing to draw 1.824 + if (fRC->isEmpty()) { 1.825 + return; 1.826 + } 1.827 + 1.828 + SkPoint strokeSize; 1.829 + RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 1.830 + 1.831 + if (kPath_RectType == rtype) { 1.832 + SkPath tmp; 1.833 + tmp.addRect(rect); 1.834 + tmp.setFillType(SkPath::kWinding_FillType); 1.835 + this->drawPath(tmp, paint, NULL, true); 1.836 + return; 1.837 + } 1.838 + 1.839 + const SkMatrix& matrix = *fMatrix; 1.840 + SkRect devRect; 1.841 + 1.842 + // transform rect into devRect 1.843 + matrix.mapPoints(rect_points(devRect), rect_points(rect), 2); 1.844 + devRect.sort(); 1.845 + 1.846 + if (fBounder && !fBounder->doRect(devRect, paint)) { 1.847 + return; 1.848 + } 1.849 + 1.850 + // look for the quick exit, before we build a blitter 1.851 + SkIRect ir; 1.852 + devRect.roundOut(&ir); 1.853 + if (paint.getStyle() != SkPaint::kFill_Style) { 1.854 + // extra space for hairlines 1.855 + ir.inset(-1, -1); 1.856 + } 1.857 + if (fRC->quickReject(ir)) { 1.858 + return; 1.859 + } 1.860 + 1.861 + SkDeviceLooper looper(*fBitmap, *fRC, ir, paint.isAntiAlias()); 1.862 + while (looper.next()) { 1.863 + SkRect localDevRect; 1.864 + looper.mapRect(&localDevRect, devRect); 1.865 + SkMatrix localMatrix; 1.866 + looper.mapMatrix(&localMatrix, matrix); 1.867 + 1.868 + SkAutoBlitterChoose blitterStorage(looper.getBitmap(), localMatrix, 1.869 + paint); 1.870 + const SkRasterClip& clip = looper.getRC(); 1.871 + SkBlitter* blitter = blitterStorage.get(); 1.872 + 1.873 + // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 1.874 + // case we are also hairline (if we've gotten to here), which devolves to 1.875 + // effectively just kFill 1.876 + switch (rtype) { 1.877 + case kFill_RectType: 1.878 + if (paint.isAntiAlias()) { 1.879 + SkScan::AntiFillRect(localDevRect, clip, blitter); 1.880 + } else { 1.881 + SkScan::FillRect(localDevRect, clip, blitter); 1.882 + } 1.883 + break; 1.884 + case kStroke_RectType: 1.885 + if (paint.isAntiAlias()) { 1.886 + SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 1.887 + } else { 1.888 + SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 1.889 + } 1.890 + break; 1.891 + case kHair_RectType: 1.892 + if (paint.isAntiAlias()) { 1.893 + SkScan::AntiHairRect(localDevRect, clip, blitter); 1.894 + } else { 1.895 + SkScan::HairRect(localDevRect, clip, blitter); 1.896 + } 1.897 + break; 1.898 + default: 1.899 + SkDEBUGFAIL("bad rtype"); 1.900 + } 1.901 + } 1.902 +} 1.903 + 1.904 +void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 1.905 + if (srcM.fBounds.isEmpty()) { 1.906 + return; 1.907 + } 1.908 + 1.909 + const SkMask* mask = &srcM; 1.910 + 1.911 + SkMask dstM; 1.912 + if (paint.getMaskFilter() && 1.913 + paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) { 1.914 + mask = &dstM; 1.915 + } else { 1.916 + dstM.fImage = NULL; 1.917 + } 1.918 + SkAutoMaskFreeImage ami(dstM.fImage); 1.919 + 1.920 + if (fBounder && !fBounder->doIRect(mask->fBounds)) { 1.921 + return; 1.922 + } 1.923 + 1.924 + SkAutoBlitterChoose blitterChooser(*fBitmap, *fMatrix, paint); 1.925 + SkBlitter* blitter = blitterChooser.get(); 1.926 + 1.927 + SkAAClipBlitterWrapper wrapper; 1.928 + const SkRegion* clipRgn; 1.929 + 1.930 + if (fRC->isBW()) { 1.931 + clipRgn = &fRC->bwRgn(); 1.932 + } else { 1.933 + wrapper.init(*fRC, blitter); 1.934 + clipRgn = &wrapper.getRgn(); 1.935 + blitter = wrapper.getBlitter(); 1.936 + } 1.937 + blitter->blitMaskRegion(*mask, *clipRgn); 1.938 +} 1.939 + 1.940 +static SkScalar fast_len(const SkVector& vec) { 1.941 + SkScalar x = SkScalarAbs(vec.fX); 1.942 + SkScalar y = SkScalarAbs(vec.fY); 1.943 + if (x < y) { 1.944 + SkTSwap(x, y); 1.945 + } 1.946 + return x + SkScalarHalf(y); 1.947 +} 1.948 + 1.949 +static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) { 1.950 + SkXfermode::Coeff dc; 1.951 + if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) { 1.952 + return false; 1.953 + } 1.954 + 1.955 + switch (dc) { 1.956 + case SkXfermode::kOne_Coeff: 1.957 + case SkXfermode::kISA_Coeff: 1.958 + case SkXfermode::kISC_Coeff: 1.959 + return true; 1.960 + default: 1.961 + return false; 1.962 + } 1.963 +} 1.964 + 1.965 +bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix, 1.966 + SkScalar* coverage) { 1.967 + SkASSERT(strokeWidth > 0); 1.968 + // We need to try to fake a thick-stroke with a modulated hairline. 1.969 + 1.970 + if (matrix.hasPerspective()) { 1.971 + return false; 1.972 + } 1.973 + 1.974 + SkVector src[2], dst[2]; 1.975 + src[0].set(strokeWidth, 0); 1.976 + src[1].set(0, strokeWidth); 1.977 + matrix.mapVectors(dst, src, 2); 1.978 + SkScalar len0 = fast_len(dst[0]); 1.979 + SkScalar len1 = fast_len(dst[1]); 1.980 + if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 1.981 + if (NULL != coverage) { 1.982 + *coverage = SkScalarAve(len0, len1); 1.983 + } 1.984 + return true; 1.985 + } 1.986 + return false; 1.987 +} 1.988 + 1.989 +void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 1.990 + SkDEBUGCODE(this->validate()); 1.991 + 1.992 + if (fRC->isEmpty()) { 1.993 + return; 1.994 + } 1.995 + 1.996 + { 1.997 + // TODO: Investigate optimizing these options. They are in the same 1.998 + // order as SkDraw::drawPath, which handles each case. It may be 1.999 + // that there is no way to optimize for these using the SkRRect path. 1.1000 + SkScalar coverage; 1.1001 + if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 1.1002 + goto DRAW_PATH; 1.1003 + } 1.1004 + 1.1005 + if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 1.1006 + goto DRAW_PATH; 1.1007 + } 1.1008 + 1.1009 + if (paint.getRasterizer()) { 1.1010 + goto DRAW_PATH; 1.1011 + } 1.1012 + } 1.1013 + 1.1014 + if (paint.getMaskFilter()) { 1.1015 + // Transform the rrect into device space. 1.1016 + SkRRect devRRect; 1.1017 + if (rrect.transform(*fMatrix, &devRRect)) { 1.1018 + SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint); 1.1019 + if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, 1.1020 + fBounder, blitter.get(), 1.1021 + SkPaint::kFill_Style)) { 1.1022 + return; // filterRRect() called the blitter, so we're done 1.1023 + } 1.1024 + } 1.1025 + } 1.1026 + 1.1027 +DRAW_PATH: 1.1028 + // Now fall back to the default case of using a path. 1.1029 + SkPath path; 1.1030 + path.addRRect(rrect); 1.1031 + this->drawPath(path, paint, NULL, true); 1.1032 +} 1.1033 + 1.1034 +void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1.1035 + const SkMatrix* prePathMatrix, bool pathIsMutable, 1.1036 + bool drawCoverage) const { 1.1037 + SkDEBUGCODE(this->validate();) 1.1038 + 1.1039 + // nothing to draw 1.1040 + if (fRC->isEmpty()) { 1.1041 + return; 1.1042 + } 1.1043 + 1.1044 + SkPath* pathPtr = (SkPath*)&origSrcPath; 1.1045 + bool doFill = true; 1.1046 + SkPath tmpPath; 1.1047 + SkMatrix tmpMatrix; 1.1048 + const SkMatrix* matrix = fMatrix; 1.1049 + 1.1050 + if (prePathMatrix) { 1.1051 + if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 1.1052 + origPaint.getRasterizer()) { 1.1053 + SkPath* result = pathPtr; 1.1054 + 1.1055 + if (!pathIsMutable) { 1.1056 + result = &tmpPath; 1.1057 + pathIsMutable = true; 1.1058 + } 1.1059 + pathPtr->transform(*prePathMatrix, result); 1.1060 + pathPtr = result; 1.1061 + } else { 1.1062 + if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) { 1.1063 + // overflow 1.1064 + return; 1.1065 + } 1.1066 + matrix = &tmpMatrix; 1.1067 + } 1.1068 + } 1.1069 + // at this point we're done with prePathMatrix 1.1070 + SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1.1071 + 1.1072 + SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1.1073 + 1.1074 + { 1.1075 + SkScalar coverage; 1.1076 + if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1.1077 + if (SK_Scalar1 == coverage) { 1.1078 + paint.writable()->setStrokeWidth(0); 1.1079 + } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) { 1.1080 + U8CPU newAlpha; 1.1081 +#if 0 1.1082 + newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1.1083 + origPaint.getAlpha())); 1.1084 +#else 1.1085 + // this is the old technique, which we preserve for now so 1.1086 + // we don't change previous results (testing) 1.1087 + // the new way seems fine, its just (a tiny bit) different 1.1088 + int scale = (int)SkScalarMul(coverage, 256); 1.1089 + newAlpha = origPaint.getAlpha() * scale >> 8; 1.1090 +#endif 1.1091 + SkPaint* writablePaint = paint.writable(); 1.1092 + writablePaint->setStrokeWidth(0); 1.1093 + writablePaint->setAlpha(newAlpha); 1.1094 + } 1.1095 + } 1.1096 + } 1.1097 + 1.1098 + if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 1.1099 + SkRect cullRect; 1.1100 + const SkRect* cullRectPtr = NULL; 1.1101 + if (this->computeConservativeLocalClipBounds(&cullRect)) { 1.1102 + cullRectPtr = &cullRect; 1.1103 + } 1.1104 + doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr); 1.1105 + pathPtr = &tmpPath; 1.1106 + } 1.1107 + 1.1108 + if (paint->getRasterizer()) { 1.1109 + SkMask mask; 1.1110 + if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1.1111 + &fRC->getBounds(), paint->getMaskFilter(), &mask, 1.1112 + SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1.1113 + this->drawDevMask(mask, *paint); 1.1114 + SkMask::FreeImage(mask.fImage); 1.1115 + } 1.1116 + return; 1.1117 + } 1.1118 + 1.1119 + // avoid possibly allocating a new path in transform if we can 1.1120 + SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1.1121 + 1.1122 + // transform the path into device space 1.1123 + pathPtr->transform(*matrix, devPathPtr); 1.1124 + 1.1125 + SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint, drawCoverage); 1.1126 + 1.1127 + if (paint->getMaskFilter()) { 1.1128 + SkPaint::Style style = doFill ? SkPaint::kFill_Style : 1.1129 + SkPaint::kStroke_Style; 1.1130 + if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, 1.1131 + fBounder, blitter.get(), 1.1132 + style)) { 1.1133 + return; // filterPath() called the blitter, so we're done 1.1134 + } 1.1135 + } 1.1136 + 1.1137 + if (fBounder && !fBounder->doPath(*devPathPtr, *paint, doFill)) { 1.1138 + return; 1.1139 + } 1.1140 + 1.1141 + void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 1.1142 + if (doFill) { 1.1143 + if (paint->isAntiAlias()) { 1.1144 + proc = SkScan::AntiFillPath; 1.1145 + } else { 1.1146 + proc = SkScan::FillPath; 1.1147 + } 1.1148 + } else { // hairline 1.1149 + if (paint->isAntiAlias()) { 1.1150 + proc = SkScan::AntiHairPath; 1.1151 + } else { 1.1152 + proc = SkScan::HairPath; 1.1153 + } 1.1154 + } 1.1155 + proc(*devPathPtr, *fRC, blitter.get()); 1.1156 +} 1.1157 + 1.1158 +/** For the purposes of drawing bitmaps, if a matrix is "almost" translate 1.1159 + go ahead and treat it as if it were, so that subsequent code can go fast. 1.1160 + */ 1.1161 +static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) { 1.1162 + unsigned bits = 0; // TODO: find a way to allow the caller to tell us to 1.1163 + // respect filtering. 1.1164 + return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits); 1.1165 +} 1.1166 + 1.1167 +void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, 1.1168 + const SkPaint& paint) const { 1.1169 + SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); 1.1170 + 1.1171 + if (just_translate(*fMatrix, bitmap)) { 1.1172 + int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); 1.1173 + int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); 1.1174 + 1.1175 + SkAutoLockPixels alp(bitmap); 1.1176 + if (!bitmap.readyToDraw()) { 1.1177 + return; 1.1178 + } 1.1179 + 1.1180 + SkMask mask; 1.1181 + mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1.1182 + mask.fFormat = SkMask::kA8_Format; 1.1183 + mask.fRowBytes = SkToU32(bitmap.rowBytes()); 1.1184 + mask.fImage = bitmap.getAddr8(0, 0); 1.1185 + 1.1186 + this->drawDevMask(mask, paint); 1.1187 + } else { // need to xform the bitmap first 1.1188 + SkRect r; 1.1189 + SkMask mask; 1.1190 + 1.1191 + r.set(0, 0, 1.1192 + SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1.1193 + fMatrix->mapRect(&r); 1.1194 + r.round(&mask.fBounds); 1.1195 + 1.1196 + // set the mask's bounds to the transformed bitmap-bounds, 1.1197 + // clipped to the actual device 1.1198 + { 1.1199 + SkIRect devBounds; 1.1200 + devBounds.set(0, 0, fBitmap->width(), fBitmap->height()); 1.1201 + // need intersect(l, t, r, b) on irect 1.1202 + if (!mask.fBounds.intersect(devBounds)) { 1.1203 + return; 1.1204 + } 1.1205 + } 1.1206 + 1.1207 + mask.fFormat = SkMask::kA8_Format; 1.1208 + mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1.1209 + size_t size = mask.computeImageSize(); 1.1210 + if (0 == size) { 1.1211 + // the mask is too big to allocated, draw nothing 1.1212 + return; 1.1213 + } 1.1214 + 1.1215 + // allocate (and clear) our temp buffer to hold the transformed bitmap 1.1216 + SkAutoMalloc storage(size); 1.1217 + mask.fImage = (uint8_t*)storage.get(); 1.1218 + memset(mask.fImage, 0, size); 1.1219 + 1.1220 + // now draw our bitmap(src) into mask(dst), transformed by the matrix 1.1221 + { 1.1222 + SkBitmap device; 1.1223 + device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), 1.1224 + mask.fBounds.height(), mask.fRowBytes); 1.1225 + device.setPixels(mask.fImage); 1.1226 + 1.1227 + SkCanvas c(device); 1.1228 + // need the unclipped top/left for the translate 1.1229 + c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1.1230 + -SkIntToScalar(mask.fBounds.fTop)); 1.1231 + c.concat(*fMatrix); 1.1232 + 1.1233 + // We can't call drawBitmap, or we'll infinitely recurse. Instead 1.1234 + // we manually build a shader and draw that into our new mask 1.1235 + SkPaint tmpPaint; 1.1236 + tmpPaint.setFlags(paint.getFlags()); 1.1237 + SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1.1238 + SkRect rr; 1.1239 + rr.set(0, 0, SkIntToScalar(bitmap.width()), 1.1240 + SkIntToScalar(bitmap.height())); 1.1241 + c.drawRect(rr, install.paintWithShader()); 1.1242 + } 1.1243 + this->drawDevMask(mask, paint); 1.1244 + } 1.1245 +} 1.1246 + 1.1247 +static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1.1248 + const SkRect& srcR) { 1.1249 + SkRect dstR; 1.1250 + SkIRect devIR; 1.1251 + 1.1252 + m.mapRect(&dstR, srcR); 1.1253 + dstR.roundOut(&devIR); 1.1254 + return c.quickReject(devIR); 1.1255 +} 1.1256 + 1.1257 +static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1.1258 + int width, int height) { 1.1259 + SkRect r; 1.1260 + r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1.1261 + return clipped_out(matrix, clip, r); 1.1262 +} 1.1263 + 1.1264 +static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, 1.1265 + const SkBitmap& bitmap) { 1.1266 + return clip.isBW() || 1.1267 + clip.quickContains(x, y, x + bitmap.width(), y + bitmap.height()); 1.1268 +} 1.1269 + 1.1270 +void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1.1271 + const SkPaint& origPaint) const { 1.1272 + SkDEBUGCODE(this->validate();) 1.1273 + 1.1274 + // nothing to draw 1.1275 + if (fRC->isEmpty() || 1.1276 + bitmap.width() == 0 || bitmap.height() == 0 || 1.1277 + bitmap.colorType() == kUnknown_SkColorType) { 1.1278 + return; 1.1279 + } 1.1280 + 1.1281 + SkPaint paint(origPaint); 1.1282 + paint.setStyle(SkPaint::kFill_Style); 1.1283 + 1.1284 + SkMatrix matrix; 1.1285 + if (!matrix.setConcat(*fMatrix, prematrix)) { 1.1286 + return; 1.1287 + } 1.1288 + 1.1289 + if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1.1290 + return; 1.1291 + } 1.1292 + 1.1293 + if (fBounder && just_translate(matrix, bitmap)) { 1.1294 + SkIRect ir; 1.1295 + int32_t ix = SkScalarRoundToInt(matrix.getTranslateX()); 1.1296 + int32_t iy = SkScalarRoundToInt(matrix.getTranslateY()); 1.1297 + ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1.1298 + if (!fBounder->doIRect(ir)) { 1.1299 + return; 1.1300 + } 1.1301 + } 1.1302 + 1.1303 + if (bitmap.colorType() != kAlpha_8_SkColorType && 1.1304 + just_translate(matrix, bitmap)) { 1.1305 + // 1.1306 + // It is safe to call lock pixels now, since we know the matrix is 1.1307 + // (more or less) identity. 1.1308 + // 1.1309 + SkAutoLockPixels alp(bitmap); 1.1310 + if (!bitmap.readyToDraw()) { 1.1311 + return; 1.1312 + } 1.1313 + int ix = SkScalarRoundToInt(matrix.getTranslateX()); 1.1314 + int iy = SkScalarRoundToInt(matrix.getTranslateY()); 1.1315 + if (clipHandlesSprite(*fRC, ix, iy, bitmap)) { 1.1316 + SkTBlitterAllocator allocator; 1.1317 + // blitter will be owned by the allocator. 1.1318 + SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1.1319 + ix, iy, &allocator); 1.1320 + if (blitter) { 1.1321 + SkIRect ir; 1.1322 + ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height()); 1.1323 + 1.1324 + SkScan::FillIRect(ir, *fRC, blitter); 1.1325 + return; 1.1326 + } 1.1327 + } 1.1328 + } 1.1329 + 1.1330 + // now make a temp draw on the stack, and use it 1.1331 + // 1.1332 + SkDraw draw(*this); 1.1333 + draw.fMatrix = &matrix; 1.1334 + 1.1335 + if (bitmap.colorType() == kAlpha_8_SkColorType) { 1.1336 + draw.drawBitmapAsMask(bitmap, paint); 1.1337 + } else { 1.1338 + SkAutoBitmapShaderInstall install(bitmap, paint); 1.1339 + 1.1340 + SkRect r; 1.1341 + r.set(0, 0, SkIntToScalar(bitmap.width()), 1.1342 + SkIntToScalar(bitmap.height())); 1.1343 + // is this ok if paint has a rasterizer? 1.1344 + draw.drawRect(r, install.paintWithShader()); 1.1345 + } 1.1346 +} 1.1347 + 1.1348 +void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, 1.1349 + const SkPaint& origPaint) const { 1.1350 + SkDEBUGCODE(this->validate();) 1.1351 + 1.1352 + // nothing to draw 1.1353 + if (fRC->isEmpty() || 1.1354 + bitmap.width() == 0 || bitmap.height() == 0 || 1.1355 + bitmap.colorType() == kUnknown_SkColorType) { 1.1356 + return; 1.1357 + } 1.1358 + 1.1359 + SkIRect bounds; 1.1360 + bounds.set(x, y, x + bitmap.width(), y + bitmap.height()); 1.1361 + 1.1362 + if (fRC->quickReject(bounds)) { 1.1363 + return; // nothing to draw 1.1364 + } 1.1365 + 1.1366 + SkPaint paint(origPaint); 1.1367 + paint.setStyle(SkPaint::kFill_Style); 1.1368 + 1.1369 + if (NULL == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, bitmap)) { 1.1370 + SkTBlitterAllocator allocator; 1.1371 + // blitter will be owned by the allocator. 1.1372 + SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap, 1.1373 + x, y, &allocator); 1.1374 + 1.1375 + if (blitter) { 1.1376 + if (fBounder && !fBounder->doIRect(bounds)) { 1.1377 + return; 1.1378 + } 1.1379 + 1.1380 + SkScan::FillIRect(bounds, *fRC, blitter); 1.1381 + return; 1.1382 + } 1.1383 + } 1.1384 + 1.1385 + SkAutoBitmapShaderInstall install(bitmap, paint); 1.1386 + const SkPaint& shaderPaint = install.paintWithShader(); 1.1387 + 1.1388 + SkMatrix matrix; 1.1389 + SkRect r; 1.1390 + 1.1391 + // get a scalar version of our rect 1.1392 + r.set(bounds); 1.1393 + 1.1394 + // tell the shader our offset 1.1395 + matrix.setTranslate(r.fLeft, r.fTop); 1.1396 + shaderPaint.getShader()->setLocalMatrix(matrix); 1.1397 + 1.1398 + SkDraw draw(*this); 1.1399 + matrix.reset(); 1.1400 + draw.fMatrix = &matrix; 1.1401 + // call ourself with a rect 1.1402 + // is this OK if paint has a rasterizer? 1.1403 + draw.drawRect(r, shaderPaint); 1.1404 +} 1.1405 + 1.1406 +/////////////////////////////////////////////////////////////////////////////// 1.1407 + 1.1408 +#include "SkScalerContext.h" 1.1409 +#include "SkGlyphCache.h" 1.1410 +#include "SkTextToPathIter.h" 1.1411 +#include "SkUtils.h" 1.1412 + 1.1413 +static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, 1.1414 + const char text[], size_t byteLength, SkVector* stopVector) { 1.1415 + SkFixed x = 0, y = 0; 1.1416 + const char* stop = text + byteLength; 1.1417 + 1.1418 + SkAutoKern autokern; 1.1419 + 1.1420 + while (text < stop) { 1.1421 + // don't need x, y here, since all subpixel variants will have the 1.1422 + // same advance 1.1423 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.1424 + 1.1425 + x += autokern.adjust(glyph) + glyph.fAdvanceX; 1.1426 + y += glyph.fAdvanceY; 1.1427 + } 1.1428 + stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y)); 1.1429 + 1.1430 + SkASSERT(text == stop); 1.1431 +} 1.1432 + 1.1433 +bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 1.1434 + // hairline glyphs are fast enough so we don't need to cache them 1.1435 + if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { 1.1436 + return true; 1.1437 + } 1.1438 + 1.1439 + // we don't cache perspective 1.1440 + if (ctm.hasPerspective()) { 1.1441 + return true; 1.1442 + } 1.1443 + 1.1444 + SkMatrix textM; 1.1445 + return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); 1.1446 +} 1.1447 + 1.1448 +void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1.1449 + SkScalar x, SkScalar y, 1.1450 + const SkPaint& paint) const { 1.1451 + SkDEBUGCODE(this->validate();) 1.1452 + 1.1453 + SkTextToPathIter iter(text, byteLength, paint, true); 1.1454 + 1.1455 + SkMatrix matrix; 1.1456 + matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1.1457 + matrix.postTranslate(x, y); 1.1458 + 1.1459 + const SkPath* iterPath; 1.1460 + SkScalar xpos, prevXPos = 0; 1.1461 + 1.1462 + while (iter.next(&iterPath, &xpos)) { 1.1463 + matrix.postTranslate(xpos - prevXPos, 0); 1.1464 + if (iterPath) { 1.1465 + const SkPaint& pnt = iter.getPaint(); 1.1466 + if (fDevice) { 1.1467 + fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1.1468 + } else { 1.1469 + this->drawPath(*iterPath, pnt, &matrix, false); 1.1470 + } 1.1471 + } 1.1472 + prevXPos = xpos; 1.1473 + } 1.1474 +} 1.1475 + 1.1476 +// disable warning : local variable used without having been initialized 1.1477 +#if defined _WIN32 && _MSC_VER >= 1300 1.1478 +#pragma warning ( push ) 1.1479 +#pragma warning ( disable : 4701 ) 1.1480 +#endif 1.1481 + 1.1482 +////////////////////////////////////////////////////////////////////////////// 1.1483 + 1.1484 +static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, 1.1485 + SkFixed fx, SkFixed fy, 1.1486 + const SkGlyph& glyph) { 1.1487 + int left = SkFixedFloorToInt(fx); 1.1488 + int top = SkFixedFloorToInt(fy); 1.1489 + SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1.1490 + SkASSERT(NULL == state.fBounder); 1.1491 + SkASSERT((NULL == state.fClip && state.fAAClip) || 1.1492 + (state.fClip && NULL == state.fAAClip && state.fClip->isRect())); 1.1493 + 1.1494 + left += glyph.fLeft; 1.1495 + top += glyph.fTop; 1.1496 + 1.1497 + int right = left + glyph.fWidth; 1.1498 + int bottom = top + glyph.fHeight; 1.1499 + 1.1500 + SkMask mask; 1.1501 + SkIRect storage; 1.1502 + SkIRect* bounds = &mask.fBounds; 1.1503 + 1.1504 + mask.fBounds.set(left, top, right, bottom); 1.1505 + 1.1506 + // this extra test is worth it, assuming that most of the time it succeeds 1.1507 + // since we can avoid writing to storage 1.1508 + if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { 1.1509 + if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) 1.1510 + return; 1.1511 + bounds = &storage; 1.1512 + } 1.1513 + 1.1514 + uint8_t* aa = (uint8_t*)glyph.fImage; 1.1515 + if (NULL == aa) { 1.1516 + aa = (uint8_t*)state.fCache->findImage(glyph); 1.1517 + if (NULL == aa) { 1.1518 + return; // can't rasterize glyph 1.1519 + } 1.1520 + } 1.1521 + 1.1522 + mask.fRowBytes = glyph.rowBytes(); 1.1523 + mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1.1524 + mask.fImage = aa; 1.1525 + state.blitMask(mask, *bounds); 1.1526 +} 1.1527 + 1.1528 +static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, 1.1529 + SkFixed fx, SkFixed fy, 1.1530 + const SkGlyph& glyph) { 1.1531 + int left = SkFixedFloorToInt(fx); 1.1532 + int top = SkFixedFloorToInt(fy); 1.1533 + SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1.1534 + SkASSERT(!state.fClip->isRect()); 1.1535 + SkASSERT(NULL == state.fBounder); 1.1536 + 1.1537 + SkMask mask; 1.1538 + 1.1539 + left += glyph.fLeft; 1.1540 + top += glyph.fTop; 1.1541 + 1.1542 + mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1.1543 + SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1.1544 + 1.1545 + if (!clipper.done()) { 1.1546 + const SkIRect& cr = clipper.rect(); 1.1547 + const uint8_t* aa = (const uint8_t*)glyph.fImage; 1.1548 + if (NULL == aa) { 1.1549 + aa = (uint8_t*)state.fCache->findImage(glyph); 1.1550 + if (NULL == aa) { 1.1551 + return; 1.1552 + } 1.1553 + } 1.1554 + 1.1555 + mask.fRowBytes = glyph.rowBytes(); 1.1556 + mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1.1557 + mask.fImage = (uint8_t*)aa; 1.1558 + do { 1.1559 + state.blitMask(mask, cr); 1.1560 + clipper.next(); 1.1561 + } while (!clipper.done()); 1.1562 + } 1.1563 +} 1.1564 + 1.1565 +static void D1G_Bounder(const SkDraw1Glyph& state, 1.1566 + SkFixed fx, SkFixed fy, 1.1567 + const SkGlyph& glyph) { 1.1568 + int left = SkFixedFloorToInt(fx); 1.1569 + int top = SkFixedFloorToInt(fy); 1.1570 + SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1.1571 + 1.1572 + SkMask mask; 1.1573 + 1.1574 + left += glyph.fLeft; 1.1575 + top += glyph.fTop; 1.1576 + 1.1577 + mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1.1578 + SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); 1.1579 + 1.1580 + if (!clipper.done()) { 1.1581 + const SkIRect& cr = clipper.rect(); 1.1582 + const uint8_t* aa = (const uint8_t*)glyph.fImage; 1.1583 + if (NULL == aa) { 1.1584 + aa = (uint8_t*)state.fCache->findImage(glyph); 1.1585 + if (NULL == aa) { 1.1586 + return; 1.1587 + } 1.1588 + } 1.1589 + 1.1590 + // we need to pass the origin, which we approximate with our 1.1591 + // (unadjusted) left,top coordinates (the caller called fixedfloor) 1.1592 + if (state.fBounder->doIRectGlyph(cr, 1.1593 + left - glyph.fLeft, 1.1594 + top - glyph.fTop, glyph)) { 1.1595 + mask.fRowBytes = glyph.rowBytes(); 1.1596 + mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1.1597 + mask.fImage = (uint8_t*)aa; 1.1598 + do { 1.1599 + state.blitMask(mask, cr); 1.1600 + clipper.next(); 1.1601 + } while (!clipper.done()); 1.1602 + } 1.1603 + } 1.1604 +} 1.1605 + 1.1606 +static void D1G_Bounder_AAClip(const SkDraw1Glyph& state, 1.1607 + SkFixed fx, SkFixed fy, 1.1608 + const SkGlyph& glyph) { 1.1609 + int left = SkFixedFloorToInt(fx); 1.1610 + int top = SkFixedFloorToInt(fy); 1.1611 + SkIRect bounds; 1.1612 + bounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); 1.1613 + 1.1614 + if (state.fBounder->doIRectGlyph(bounds, left, top, glyph)) { 1.1615 + D1G_NoBounder_RectClip(state, fx, fy, glyph); 1.1616 + } 1.1617 +} 1.1618 + 1.1619 +static bool hasCustomD1GProc(const SkDraw& draw) { 1.1620 + return draw.fProcs && draw.fProcs->fD1GProc; 1.1621 +} 1.1622 + 1.1623 +static bool needsRasterTextBlit(const SkDraw& draw) { 1.1624 + return !hasCustomD1GProc(draw); 1.1625 +} 1.1626 + 1.1627 +SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, 1.1628 + SkGlyphCache* cache, const SkPaint& pnt) { 1.1629 + fDraw = draw; 1.1630 + fBounder = draw->fBounder; 1.1631 + fBlitter = blitter; 1.1632 + fCache = cache; 1.1633 + fPaint = &pnt; 1.1634 + 1.1635 + if (cache->isSubpixel()) { 1.1636 + fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); 1.1637 + } else { 1.1638 + fHalfSampleX = fHalfSampleY = SK_FixedHalf; 1.1639 + } 1.1640 + 1.1641 + if (hasCustomD1GProc(*draw)) { 1.1642 + // todo: fix this assumption about clips w/ custom 1.1643 + fClip = draw->fClip; 1.1644 + fClipBounds = fClip->getBounds(); 1.1645 + return draw->fProcs->fD1GProc; 1.1646 + } 1.1647 + 1.1648 + if (draw->fRC->isBW()) { 1.1649 + fAAClip = NULL; 1.1650 + fClip = &draw->fRC->bwRgn(); 1.1651 + fClipBounds = fClip->getBounds(); 1.1652 + if (NULL == fBounder) { 1.1653 + if (fClip->isRect()) { 1.1654 + return D1G_NoBounder_RectClip; 1.1655 + } else { 1.1656 + return D1G_NoBounder_RgnClip; 1.1657 + } 1.1658 + } else { 1.1659 + return D1G_Bounder; 1.1660 + } 1.1661 + } else { // aaclip 1.1662 + fAAClip = &draw->fRC->aaRgn(); 1.1663 + fClip = NULL; 1.1664 + fClipBounds = fAAClip->getBounds(); 1.1665 + if (NULL == fBounder) { 1.1666 + return D1G_NoBounder_RectClip; 1.1667 + } else { 1.1668 + return D1G_Bounder_AAClip; 1.1669 + } 1.1670 + } 1.1671 +} 1.1672 + 1.1673 +void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { 1.1674 + SkASSERT(SkMask::kARGB32_Format == mask.fFormat); 1.1675 + 1.1676 + SkBitmap bm; 1.1677 + bm.setConfig(SkBitmap::kARGB_8888_Config, 1.1678 + mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 1.1679 + bm.setPixels((SkPMColor*)mask.fImage); 1.1680 + 1.1681 + fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); 1.1682 +} 1.1683 + 1.1684 +/////////////////////////////////////////////////////////////////////////////// 1.1685 + 1.1686 +void SkDraw::drawText(const char text[], size_t byteLength, 1.1687 + SkScalar x, SkScalar y, const SkPaint& paint) const { 1.1688 + SkASSERT(byteLength == 0 || text != NULL); 1.1689 + 1.1690 + SkDEBUGCODE(this->validate();) 1.1691 + 1.1692 + // nothing to draw 1.1693 + if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1.1694 + return; 1.1695 + } 1.1696 + 1.1697 + // SkScalarRec doesn't currently have a way of representing hairline stroke and 1.1698 + // will fill if its frame-width is 0. 1.1699 + if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1.1700 + this->drawText_asPaths(text, byteLength, x, y, paint); 1.1701 + return; 1.1702 + } 1.1703 + 1.1704 + SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1.1705 + 1.1706 + SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1.1707 + SkGlyphCache* cache = autoCache.getCache(); 1.1708 + 1.1709 + // transform our starting point 1.1710 + { 1.1711 + SkPoint loc; 1.1712 + fMatrix->mapXY(x, y, &loc); 1.1713 + x = loc.fX; 1.1714 + y = loc.fY; 1.1715 + } 1.1716 + 1.1717 + // need to measure first 1.1718 + if (paint.getTextAlign() != SkPaint::kLeft_Align) { 1.1719 + SkVector stop; 1.1720 + 1.1721 + measure_text(cache, glyphCacheProc, text, byteLength, &stop); 1.1722 + 1.1723 + SkScalar stopX = stop.fX; 1.1724 + SkScalar stopY = stop.fY; 1.1725 + 1.1726 + if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1.1727 + stopX = SkScalarHalf(stopX); 1.1728 + stopY = SkScalarHalf(stopY); 1.1729 + } 1.1730 + x -= stopX; 1.1731 + y -= stopY; 1.1732 + } 1.1733 + 1.1734 + const char* stop = text + byteLength; 1.1735 + 1.1736 + SkAAClipBlitter aaBlitter; 1.1737 + SkAutoBlitterChoose blitterChooser; 1.1738 + SkBlitter* blitter = NULL; 1.1739 + if (needsRasterTextBlit(*this)) { 1.1740 + blitterChooser.choose(*fBitmap, *fMatrix, paint); 1.1741 + blitter = blitterChooser.get(); 1.1742 + if (fRC->isAA()) { 1.1743 + aaBlitter.init(blitter, &fRC->aaRgn()); 1.1744 + blitter = &aaBlitter; 1.1745 + } 1.1746 + } 1.1747 + 1.1748 + SkAutoKern autokern; 1.1749 + SkDraw1Glyph d1g; 1.1750 + SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); 1.1751 + 1.1752 + SkFixed fxMask = ~0; 1.1753 + SkFixed fyMask = ~0; 1.1754 + if (cache->isSubpixel()) { 1.1755 + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1.1756 + if (kX_SkAxisAlignment == baseline) { 1.1757 + fyMask = 0; 1.1758 + d1g.fHalfSampleY = SK_FixedHalf; 1.1759 + } else if (kY_SkAxisAlignment == baseline) { 1.1760 + fxMask = 0; 1.1761 + d1g.fHalfSampleX = SK_FixedHalf; 1.1762 + } 1.1763 + } 1.1764 + 1.1765 + SkFixed fx = SkScalarToFixed(x) + d1g.fHalfSampleX; 1.1766 + SkFixed fy = SkScalarToFixed(y) + d1g.fHalfSampleY; 1.1767 + 1.1768 + while (text < stop) { 1.1769 + const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); 1.1770 + 1.1771 + fx += autokern.adjust(glyph); 1.1772 + 1.1773 + if (glyph.fWidth) { 1.1774 + proc(d1g, fx, fy, glyph); 1.1775 + } 1.1776 + 1.1777 + fx += glyph.fAdvanceX; 1.1778 + fy += glyph.fAdvanceY; 1.1779 + } 1.1780 +} 1.1781 + 1.1782 +// last parameter is interpreted as SkFixed [x, y] 1.1783 +// return the fixed position, which may be rounded or not by the caller 1.1784 +// e.g. subpixel doesn't round 1.1785 +typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); 1.1786 + 1.1787 +static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.1788 + dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); 1.1789 +} 1.1790 + 1.1791 +static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.1792 + dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), 1.1793 + SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); 1.1794 +} 1.1795 + 1.1796 +static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.1797 + dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, 1.1798 + SkScalarToFixed(loc.fY) - glyph.fAdvanceY); 1.1799 +} 1.1800 + 1.1801 +static AlignProc pick_align_proc(SkPaint::Align align) { 1.1802 + static const AlignProc gProcs[] = { 1.1803 + leftAlignProc, centerAlignProc, rightAlignProc 1.1804 + }; 1.1805 + 1.1806 + SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1.1807 + 1.1808 + return gProcs[align]; 1.1809 +} 1.1810 + 1.1811 +typedef void (*AlignProc_scalar)(const SkPoint&, const SkGlyph&, SkPoint*); 1.1812 + 1.1813 +static void leftAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) { 1.1814 + dst->set(loc.fX, loc.fY); 1.1815 +} 1.1816 + 1.1817 +static void centerAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) { 1.1818 + dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX >> 1), 1.1819 + loc.fY - SkFixedToScalar(glyph.fAdvanceY >> 1)); 1.1820 +} 1.1821 + 1.1822 +static void rightAlignProc_scalar(const SkPoint& loc, const SkGlyph& glyph, SkPoint* dst) { 1.1823 + dst->set(loc.fX - SkFixedToScalar(glyph.fAdvanceX), 1.1824 + loc.fY - SkFixedToScalar(glyph.fAdvanceY)); 1.1825 +} 1.1826 + 1.1827 +static AlignProc_scalar pick_align_proc_scalar(SkPaint::Align align) { 1.1828 + static const AlignProc_scalar gProcs[] = { 1.1829 + leftAlignProc_scalar, centerAlignProc_scalar, rightAlignProc_scalar 1.1830 + }; 1.1831 + 1.1832 + SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1.1833 + 1.1834 + return gProcs[align]; 1.1835 +} 1.1836 + 1.1837 +class TextMapState { 1.1838 +public: 1.1839 + mutable SkPoint fLoc; 1.1840 + 1.1841 + TextMapState(const SkMatrix& matrix, SkScalar y) 1.1842 + : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} 1.1843 + 1.1844 + typedef void (*Proc)(const TextMapState&, const SkScalar pos[]); 1.1845 + 1.1846 + Proc pickProc(int scalarsPerPosition); 1.1847 + 1.1848 +private: 1.1849 + const SkMatrix& fMatrix; 1.1850 + SkMatrix::MapXYProc fProc; 1.1851 + SkScalar fY; // ignored by MapXYProc 1.1852 + // these are only used by Only... procs 1.1853 + SkScalar fScaleX, fTransX, fTransformedY; 1.1854 + 1.1855 + static void MapXProc(const TextMapState& state, const SkScalar pos[]) { 1.1856 + state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); 1.1857 + } 1.1858 + 1.1859 + static void MapXYProc(const TextMapState& state, const SkScalar pos[]) { 1.1860 + state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); 1.1861 + } 1.1862 + 1.1863 + static void MapOnlyScaleXProc(const TextMapState& state, 1.1864 + const SkScalar pos[]) { 1.1865 + state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, 1.1866 + state.fTransformedY); 1.1867 + } 1.1868 + 1.1869 + static void MapOnlyTransXProc(const TextMapState& state, 1.1870 + const SkScalar pos[]) { 1.1871 + state.fLoc.set(*pos + state.fTransX, state.fTransformedY); 1.1872 + } 1.1873 +}; 1.1874 + 1.1875 +TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) { 1.1876 + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1.1877 + 1.1878 + if (1 == scalarsPerPosition) { 1.1879 + unsigned mtype = fMatrix.getType(); 1.1880 + if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1.1881 + return MapXProc; 1.1882 + } else { 1.1883 + fScaleX = fMatrix.getScaleX(); 1.1884 + fTransX = fMatrix.getTranslateX(); 1.1885 + fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + 1.1886 + fMatrix.getTranslateY(); 1.1887 + return (mtype & SkMatrix::kScale_Mask) ? 1.1888 + MapOnlyScaleXProc : MapOnlyTransXProc; 1.1889 + } 1.1890 + } else { 1.1891 + return MapXYProc; 1.1892 + } 1.1893 +} 1.1894 + 1.1895 +////////////////////////////////////////////////////////////////////////////// 1.1896 + 1.1897 +void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, 1.1898 + const SkScalar pos[], SkScalar constY, 1.1899 + int scalarsPerPosition, 1.1900 + const SkPaint& origPaint) const { 1.1901 + // setup our std paint, in hopes of getting hits in the cache 1.1902 + SkPaint paint(origPaint); 1.1903 + SkScalar matrixScale = paint.setupForAsPaths(); 1.1904 + 1.1905 + SkMatrix matrix; 1.1906 + matrix.setScale(matrixScale, matrixScale); 1.1907 + 1.1908 + SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1.1909 + SkAutoGlyphCache autoCache(paint, NULL, NULL); 1.1910 + SkGlyphCache* cache = autoCache.getCache(); 1.1911 + 1.1912 + const char* stop = text + byteLength; 1.1913 + AlignProc_scalar alignProc = pick_align_proc_scalar(paint.getTextAlign()); 1.1914 + TextMapState tms(SkMatrix::I(), constY); 1.1915 + TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1.1916 + 1.1917 + while (text < stop) { 1.1918 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.1919 + if (glyph.fWidth) { 1.1920 + const SkPath* path = cache->findPath(glyph); 1.1921 + if (path) { 1.1922 + tmsProc(tms, pos); 1.1923 + SkPoint loc; 1.1924 + alignProc(tms.fLoc, glyph, &loc); 1.1925 + 1.1926 + matrix[SkMatrix::kMTransX] = loc.fX; 1.1927 + matrix[SkMatrix::kMTransY] = loc.fY; 1.1928 + if (fDevice) { 1.1929 + fDevice->drawPath(*this, *path, paint, &matrix, false); 1.1930 + } else { 1.1931 + this->drawPath(*path, paint, &matrix, false); 1.1932 + } 1.1933 + } 1.1934 + } 1.1935 + pos += scalarsPerPosition; 1.1936 + } 1.1937 +} 1.1938 + 1.1939 +void SkDraw::drawPosText(const char text[], size_t byteLength, 1.1940 + const SkScalar pos[], SkScalar constY, 1.1941 + int scalarsPerPosition, const SkPaint& paint) const { 1.1942 + SkASSERT(byteLength == 0 || text != NULL); 1.1943 + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1.1944 + 1.1945 + SkDEBUGCODE(this->validate();) 1.1946 + 1.1947 + // nothing to draw 1.1948 + if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1.1949 + return; 1.1950 + } 1.1951 + 1.1952 + if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1.1953 + this->drawPosText_asPaths(text, byteLength, pos, constY, 1.1954 + scalarsPerPosition, paint); 1.1955 + return; 1.1956 + } 1.1957 + 1.1958 + SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); 1.1959 + SkAutoGlyphCache autoCache(paint, &fDevice->fLeakyProperties, fMatrix); 1.1960 + SkGlyphCache* cache = autoCache.getCache(); 1.1961 + 1.1962 + SkAAClipBlitterWrapper wrapper; 1.1963 + SkAutoBlitterChoose blitterChooser; 1.1964 + SkBlitter* blitter = NULL; 1.1965 + if (needsRasterTextBlit(*this)) { 1.1966 + blitterChooser.choose(*fBitmap, *fMatrix, paint); 1.1967 + blitter = blitterChooser.get(); 1.1968 + if (fRC->isAA()) { 1.1969 + wrapper.init(*fRC, blitter); 1.1970 + blitter = wrapper.getBlitter(); 1.1971 + } 1.1972 + } 1.1973 + 1.1974 + const char* stop = text + byteLength; 1.1975 + AlignProc alignProc = pick_align_proc(paint.getTextAlign()); 1.1976 + SkDraw1Glyph d1g; 1.1977 + SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); 1.1978 + TextMapState tms(*fMatrix, constY); 1.1979 + TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1.1980 + 1.1981 + if (cache->isSubpixel()) { 1.1982 + // maybe we should skip the rounding if linearText is set 1.1983 + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(*fMatrix); 1.1984 + 1.1985 + SkFixed fxMask = ~0; 1.1986 + SkFixed fyMask = ~0; 1.1987 + if (kX_SkAxisAlignment == baseline) { 1.1988 + fyMask = 0; 1.1989 +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1.1990 + d1g.fHalfSampleY = SK_FixedHalf; 1.1991 +#endif 1.1992 + } else if (kY_SkAxisAlignment == baseline) { 1.1993 + fxMask = 0; 1.1994 +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1.1995 + d1g.fHalfSampleX = SK_FixedHalf; 1.1996 +#endif 1.1997 + } 1.1998 + 1.1999 + if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1.2000 + while (text < stop) { 1.2001 + tmsProc(tms, pos); 1.2002 + SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + d1g.fHalfSampleX; 1.2003 + SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + d1g.fHalfSampleY; 1.2004 + 1.2005 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 1.2006 + fx & fxMask, fy & fyMask); 1.2007 + 1.2008 + if (glyph.fWidth) { 1.2009 + proc(d1g, fx, fy, glyph); 1.2010 + } 1.2011 + pos += scalarsPerPosition; 1.2012 + } 1.2013 + } else { 1.2014 + while (text < stop) { 1.2015 + const char* currentText = text; 1.2016 + const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 1.2017 + 1.2018 + if (metricGlyph.fWidth) { 1.2019 + SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 1.2020 + SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 1.2021 + 1.2022 + tmsProc(tms, pos); 1.2023 + SkIPoint fixedLoc; 1.2024 + alignProc(tms.fLoc, metricGlyph, &fixedLoc); 1.2025 + 1.2026 + SkFixed fx = fixedLoc.fX + d1g.fHalfSampleX; 1.2027 + SkFixed fy = fixedLoc.fY + d1g.fHalfSampleY; 1.2028 + 1.2029 + // have to call again, now that we've been "aligned" 1.2030 + const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, 1.2031 + fx & fxMask, fy & fyMask); 1.2032 + // the assumption is that the metrics haven't changed 1.2033 + SkASSERT(prevAdvX == glyph.fAdvanceX); 1.2034 + SkASSERT(prevAdvY == glyph.fAdvanceY); 1.2035 + SkASSERT(glyph.fWidth); 1.2036 + 1.2037 + proc(d1g, fx, fy, glyph); 1.2038 + } 1.2039 + pos += scalarsPerPosition; 1.2040 + } 1.2041 + } 1.2042 + } else { // not subpixel 1.2043 + if (SkPaint::kLeft_Align == paint.getTextAlign()) { 1.2044 + while (text < stop) { 1.2045 + // the last 2 parameters are ignored 1.2046 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.2047 + 1.2048 + if (glyph.fWidth) { 1.2049 + tmsProc(tms, pos); 1.2050 + 1.2051 + proc(d1g, 1.2052 + SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf, //d1g.fHalfSampleX, 1.2053 + SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf, //d1g.fHalfSampleY, 1.2054 + glyph); 1.2055 + } 1.2056 + pos += scalarsPerPosition; 1.2057 + } 1.2058 + } else { 1.2059 + while (text < stop) { 1.2060 + // the last 2 parameters are ignored 1.2061 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.2062 + 1.2063 + if (glyph.fWidth) { 1.2064 + tmsProc(tms, pos); 1.2065 + 1.2066 + SkIPoint fixedLoc; 1.2067 + alignProc(tms.fLoc, glyph, &fixedLoc); 1.2068 + 1.2069 + proc(d1g, 1.2070 + fixedLoc.fX + SK_FixedHalf, //d1g.fHalfSampleX, 1.2071 + fixedLoc.fY + SK_FixedHalf, //d1g.fHalfSampleY, 1.2072 + glyph); 1.2073 + } 1.2074 + pos += scalarsPerPosition; 1.2075 + } 1.2076 + } 1.2077 + } 1.2078 +} 1.2079 + 1.2080 +#if defined _WIN32 && _MSC_VER >= 1300 1.2081 +#pragma warning ( pop ) 1.2082 +#endif 1.2083 + 1.2084 +/////////////////////////////////////////////////////////////////////////////// 1.2085 + 1.2086 +#include "SkPathMeasure.h" 1.2087 + 1.2088 +static void morphpoints(SkPoint dst[], const SkPoint src[], int count, 1.2089 + SkPathMeasure& meas, const SkMatrix& matrix) { 1.2090 + SkMatrix::MapXYProc proc = matrix.getMapXYProc(); 1.2091 + 1.2092 + for (int i = 0; i < count; i++) { 1.2093 + SkPoint pos; 1.2094 + SkVector tangent; 1.2095 + 1.2096 + proc(matrix, src[i].fX, src[i].fY, &pos); 1.2097 + SkScalar sx = pos.fX; 1.2098 + SkScalar sy = pos.fY; 1.2099 + 1.2100 + if (!meas.getPosTan(sx, &pos, &tangent)) { 1.2101 + // set to 0 if the measure failed, so that we just set dst == pos 1.2102 + tangent.set(0, 0); 1.2103 + } 1.2104 + 1.2105 + /* This is the old way (that explains our approach but is way too slow 1.2106 + SkMatrix matrix; 1.2107 + SkPoint pt; 1.2108 + 1.2109 + pt.set(sx, sy); 1.2110 + matrix.setSinCos(tangent.fY, tangent.fX); 1.2111 + matrix.preTranslate(-sx, 0); 1.2112 + matrix.postTranslate(pos.fX, pos.fY); 1.2113 + matrix.mapPoints(&dst[i], &pt, 1); 1.2114 + */ 1.2115 + dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy), 1.2116 + pos.fY + SkScalarMul(tangent.fX, sy)); 1.2117 + } 1.2118 +} 1.2119 + 1.2120 +/* TODO 1.2121 + 1.2122 + Need differentially more subdivisions when the follow-path is curvy. Not sure how to 1.2123 + determine that, but we need it. I guess a cheap answer is let the caller tell us, 1.2124 + but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out. 1.2125 +*/ 1.2126 +static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, 1.2127 + const SkMatrix& matrix) { 1.2128 + SkPath::Iter iter(src, false); 1.2129 + SkPoint srcP[4], dstP[3]; 1.2130 + SkPath::Verb verb; 1.2131 + 1.2132 + while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) { 1.2133 + switch (verb) { 1.2134 + case SkPath::kMove_Verb: 1.2135 + morphpoints(dstP, srcP, 1, meas, matrix); 1.2136 + dst->moveTo(dstP[0]); 1.2137 + break; 1.2138 + case SkPath::kLine_Verb: 1.2139 + // turn lines into quads to look bendy 1.2140 + srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX); 1.2141 + srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY); 1.2142 + morphpoints(dstP, srcP, 2, meas, matrix); 1.2143 + dst->quadTo(dstP[0], dstP[1]); 1.2144 + break; 1.2145 + case SkPath::kQuad_Verb: 1.2146 + morphpoints(dstP, &srcP[1], 2, meas, matrix); 1.2147 + dst->quadTo(dstP[0], dstP[1]); 1.2148 + break; 1.2149 + case SkPath::kCubic_Verb: 1.2150 + morphpoints(dstP, &srcP[1], 3, meas, matrix); 1.2151 + dst->cubicTo(dstP[0], dstP[1], dstP[2]); 1.2152 + break; 1.2153 + case SkPath::kClose_Verb: 1.2154 + dst->close(); 1.2155 + break; 1.2156 + default: 1.2157 + SkDEBUGFAIL("unknown verb"); 1.2158 + break; 1.2159 + } 1.2160 + } 1.2161 +} 1.2162 + 1.2163 +void SkDraw::drawTextOnPath(const char text[], size_t byteLength, 1.2164 + const SkPath& follow, const SkMatrix* matrix, 1.2165 + const SkPaint& paint) const { 1.2166 + SkASSERT(byteLength == 0 || text != NULL); 1.2167 + 1.2168 + // nothing to draw 1.2169 + if (text == NULL || byteLength == 0 || fRC->isEmpty()) { 1.2170 + return; 1.2171 + } 1.2172 + 1.2173 + SkTextToPathIter iter(text, byteLength, paint, true); 1.2174 + SkPathMeasure meas(follow, false); 1.2175 + SkScalar hOffset = 0; 1.2176 + 1.2177 + // need to measure first 1.2178 + if (paint.getTextAlign() != SkPaint::kLeft_Align) { 1.2179 + SkScalar pathLen = meas.getLength(); 1.2180 + if (paint.getTextAlign() == SkPaint::kCenter_Align) { 1.2181 + pathLen = SkScalarHalf(pathLen); 1.2182 + } 1.2183 + hOffset += pathLen; 1.2184 + } 1.2185 + 1.2186 + const SkPath* iterPath; 1.2187 + SkScalar xpos; 1.2188 + SkMatrix scaledMatrix; 1.2189 + SkScalar scale = iter.getPathScale(); 1.2190 + 1.2191 + scaledMatrix.setScale(scale, scale); 1.2192 + 1.2193 + while (iter.next(&iterPath, &xpos)) { 1.2194 + if (iterPath) { 1.2195 + SkPath tmp; 1.2196 + SkMatrix m(scaledMatrix); 1.2197 + 1.2198 + m.postTranslate(xpos + hOffset, 0); 1.2199 + if (matrix) { 1.2200 + m.postConcat(*matrix); 1.2201 + } 1.2202 + morphpath(&tmp, *iterPath, meas, m); 1.2203 + if (fDevice) { 1.2204 + fDevice->drawPath(*this, tmp, iter.getPaint(), NULL, true); 1.2205 + } else { 1.2206 + this->drawPath(tmp, iter.getPaint(), NULL, true); 1.2207 + } 1.2208 + } 1.2209 + } 1.2210 +} 1.2211 + 1.2212 +/////////////////////////////////////////////////////////////////////////////// 1.2213 + 1.2214 +struct VertState { 1.2215 + int f0, f1, f2; 1.2216 + 1.2217 + VertState(int vCount, const uint16_t indices[], int indexCount) 1.2218 + : fIndices(indices) { 1.2219 + fCurrIndex = 0; 1.2220 + if (indices) { 1.2221 + fCount = indexCount; 1.2222 + } else { 1.2223 + fCount = vCount; 1.2224 + } 1.2225 + } 1.2226 + 1.2227 + typedef bool (*Proc)(VertState*); 1.2228 + Proc chooseProc(SkCanvas::VertexMode mode); 1.2229 + 1.2230 +private: 1.2231 + int fCount; 1.2232 + int fCurrIndex; 1.2233 + const uint16_t* fIndices; 1.2234 + 1.2235 + static bool Triangles(VertState*); 1.2236 + static bool TrianglesX(VertState*); 1.2237 + static bool TriangleStrip(VertState*); 1.2238 + static bool TriangleStripX(VertState*); 1.2239 + static bool TriangleFan(VertState*); 1.2240 + static bool TriangleFanX(VertState*); 1.2241 +}; 1.2242 + 1.2243 +bool VertState::Triangles(VertState* state) { 1.2244 + int index = state->fCurrIndex; 1.2245 + if (index + 3 > state->fCount) { 1.2246 + return false; 1.2247 + } 1.2248 + state->f0 = index + 0; 1.2249 + state->f1 = index + 1; 1.2250 + state->f2 = index + 2; 1.2251 + state->fCurrIndex = index + 3; 1.2252 + return true; 1.2253 +} 1.2254 + 1.2255 +bool VertState::TrianglesX(VertState* state) { 1.2256 + const uint16_t* indices = state->fIndices; 1.2257 + int index = state->fCurrIndex; 1.2258 + if (index + 3 > state->fCount) { 1.2259 + return false; 1.2260 + } 1.2261 + state->f0 = indices[index + 0]; 1.2262 + state->f1 = indices[index + 1]; 1.2263 + state->f2 = indices[index + 2]; 1.2264 + state->fCurrIndex = index + 3; 1.2265 + return true; 1.2266 +} 1.2267 + 1.2268 +bool VertState::TriangleStrip(VertState* state) { 1.2269 + int index = state->fCurrIndex; 1.2270 + if (index + 3 > state->fCount) { 1.2271 + return false; 1.2272 + } 1.2273 + state->f2 = index + 2; 1.2274 + if (index & 1) { 1.2275 + state->f0 = index + 1; 1.2276 + state->f1 = index + 0; 1.2277 + } else { 1.2278 + state->f0 = index + 0; 1.2279 + state->f1 = index + 1; 1.2280 + } 1.2281 + state->fCurrIndex = index + 1; 1.2282 + return true; 1.2283 +} 1.2284 + 1.2285 +bool VertState::TriangleStripX(VertState* state) { 1.2286 + const uint16_t* indices = state->fIndices; 1.2287 + int index = state->fCurrIndex; 1.2288 + if (index + 3 > state->fCount) { 1.2289 + return false; 1.2290 + } 1.2291 + state->f2 = indices[index + 2]; 1.2292 + if (index & 1) { 1.2293 + state->f0 = indices[index + 1]; 1.2294 + state->f1 = indices[index + 0]; 1.2295 + } else { 1.2296 + state->f0 = indices[index + 0]; 1.2297 + state->f1 = indices[index + 1]; 1.2298 + } 1.2299 + state->fCurrIndex = index + 1; 1.2300 + return true; 1.2301 +} 1.2302 + 1.2303 +bool VertState::TriangleFan(VertState* state) { 1.2304 + int index = state->fCurrIndex; 1.2305 + if (index + 3 > state->fCount) { 1.2306 + return false; 1.2307 + } 1.2308 + state->f0 = 0; 1.2309 + state->f1 = index + 1; 1.2310 + state->f2 = index + 2; 1.2311 + state->fCurrIndex = index + 1; 1.2312 + return true; 1.2313 +} 1.2314 + 1.2315 +bool VertState::TriangleFanX(VertState* state) { 1.2316 + const uint16_t* indices = state->fIndices; 1.2317 + int index = state->fCurrIndex; 1.2318 + if (index + 3 > state->fCount) { 1.2319 + return false; 1.2320 + } 1.2321 + state->f0 = indices[0]; 1.2322 + state->f1 = indices[index + 1]; 1.2323 + state->f2 = indices[index + 2]; 1.2324 + state->fCurrIndex = index + 1; 1.2325 + return true; 1.2326 +} 1.2327 + 1.2328 +VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) { 1.2329 + switch (mode) { 1.2330 + case SkCanvas::kTriangles_VertexMode: 1.2331 + return fIndices ? TrianglesX : Triangles; 1.2332 + case SkCanvas::kTriangleStrip_VertexMode: 1.2333 + return fIndices ? TriangleStripX : TriangleStrip; 1.2334 + case SkCanvas::kTriangleFan_VertexMode: 1.2335 + return fIndices ? TriangleFanX : TriangleFan; 1.2336 + default: 1.2337 + return NULL; 1.2338 + } 1.2339 +} 1.2340 + 1.2341 +typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRasterClip&, 1.2342 + SkBlitter*); 1.2343 + 1.2344 +static HairProc ChooseHairProc(bool doAntiAlias) { 1.2345 + return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 1.2346 +} 1.2347 + 1.2348 +static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 1.2349 + const SkPoint texs[], SkMatrix* matrix) { 1.2350 + SkPoint src[3], dst[3]; 1.2351 + 1.2352 + src[0] = texs[state.f0]; 1.2353 + src[1] = texs[state.f1]; 1.2354 + src[2] = texs[state.f2]; 1.2355 + dst[0] = verts[state.f0]; 1.2356 + dst[1] = verts[state.f1]; 1.2357 + dst[2] = verts[state.f2]; 1.2358 + return matrix->setPolyToPoly(src, dst, 3); 1.2359 +} 1.2360 + 1.2361 +class SkTriColorShader : public SkShader { 1.2362 +public: 1.2363 + SkTriColorShader() {} 1.2364 + 1.2365 + bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 1.2366 + 1.2367 + virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count) SK_OVERRIDE; 1.2368 + 1.2369 + SK_TO_STRING_OVERRIDE() 1.2370 + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTriColorShader) 1.2371 + 1.2372 +protected: 1.2373 + SkTriColorShader(SkReadBuffer& buffer) : SkShader(buffer) {} 1.2374 + 1.2375 +private: 1.2376 + SkMatrix fDstToUnit; 1.2377 + SkPMColor fColors[3]; 1.2378 + 1.2379 + typedef SkShader INHERITED; 1.2380 +}; 1.2381 + 1.2382 +bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[], 1.2383 + int index0, int index1, int index2) { 1.2384 + 1.2385 + fColors[0] = SkPreMultiplyColor(colors[index0]); 1.2386 + fColors[1] = SkPreMultiplyColor(colors[index1]); 1.2387 + fColors[2] = SkPreMultiplyColor(colors[index2]); 1.2388 + 1.2389 + SkMatrix m, im; 1.2390 + m.reset(); 1.2391 + m.set(0, pts[index1].fX - pts[index0].fX); 1.2392 + m.set(1, pts[index2].fX - pts[index0].fX); 1.2393 + m.set(2, pts[index0].fX); 1.2394 + m.set(3, pts[index1].fY - pts[index0].fY); 1.2395 + m.set(4, pts[index2].fY - pts[index0].fY); 1.2396 + m.set(5, pts[index0].fY); 1.2397 + if (!m.invert(&im)) { 1.2398 + return false; 1.2399 + } 1.2400 + return fDstToUnit.setConcat(im, this->getTotalInverse()); 1.2401 +} 1.2402 + 1.2403 +#include "SkColorPriv.h" 1.2404 +#include "SkComposeShader.h" 1.2405 + 1.2406 +static int ScalarTo256(SkScalar v) { 1.2407 + int scale = SkScalarToFixed(v) >> 8; 1.2408 + if (scale < 0) { 1.2409 + scale = 0; 1.2410 + } 1.2411 + if (scale > 255) { 1.2412 + scale = 255; 1.2413 + } 1.2414 + return SkAlpha255To256(scale); 1.2415 +} 1.2416 + 1.2417 +void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 1.2418 + SkPoint src; 1.2419 + 1.2420 + for (int i = 0; i < count; i++) { 1.2421 + fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 1.2422 + x += 1; 1.2423 + 1.2424 + int scale1 = ScalarTo256(src.fX); 1.2425 + int scale2 = ScalarTo256(src.fY); 1.2426 + int scale0 = 256 - scale1 - scale2; 1.2427 + if (scale0 < 0) { 1.2428 + if (scale1 > scale2) { 1.2429 + scale2 = 256 - scale1; 1.2430 + } else { 1.2431 + scale1 = 256 - scale2; 1.2432 + } 1.2433 + scale0 = 0; 1.2434 + } 1.2435 + 1.2436 + dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 1.2437 + SkAlphaMulQ(fColors[1], scale1) + 1.2438 + SkAlphaMulQ(fColors[2], scale2); 1.2439 + } 1.2440 +} 1.2441 + 1.2442 +#ifndef SK_IGNORE_TO_STRING 1.2443 +void SkTriColorShader::toString(SkString* str) const { 1.2444 + str->append("SkTriColorShader: ("); 1.2445 + 1.2446 + this->INHERITED::toString(str); 1.2447 + 1.2448 + str->append(")"); 1.2449 +} 1.2450 +#endif 1.2451 + 1.2452 +void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 1.2453 + const SkPoint vertices[], const SkPoint textures[], 1.2454 + const SkColor colors[], SkXfermode* xmode, 1.2455 + const uint16_t indices[], int indexCount, 1.2456 + const SkPaint& paint) const { 1.2457 + SkASSERT(0 == count || NULL != vertices); 1.2458 + 1.2459 + // abort early if there is nothing to draw 1.2460 + if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 1.2461 + return; 1.2462 + } 1.2463 + 1.2464 + // transform out vertices into device coordinates 1.2465 + SkAutoSTMalloc<16, SkPoint> storage(count); 1.2466 + SkPoint* devVerts = storage.get(); 1.2467 + fMatrix->mapPoints(devVerts, vertices, count); 1.2468 + 1.2469 + if (fBounder) { 1.2470 + SkRect bounds; 1.2471 + bounds.set(devVerts, count); 1.2472 + if (!fBounder->doRect(bounds, paint)) { 1.2473 + return; 1.2474 + } 1.2475 + } 1.2476 + 1.2477 + /* 1.2478 + We can draw the vertices in 1 of 4 ways: 1.2479 + 1.2480 + - solid color (no shader/texture[], no colors[]) 1.2481 + - just colors (no shader/texture[], has colors[]) 1.2482 + - just texture (has shader/texture[], no colors[]) 1.2483 + - colors * texture (has shader/texture[], has colors[]) 1.2484 + 1.2485 + Thus for texture drawing, we need both texture[] and a shader. 1.2486 + */ 1.2487 + 1.2488 + SkTriColorShader triShader; // must be above declaration of p 1.2489 + SkPaint p(paint); 1.2490 + 1.2491 + SkShader* shader = p.getShader(); 1.2492 + if (NULL == shader) { 1.2493 + // if we have no shader, we ignore the texture coordinates 1.2494 + textures = NULL; 1.2495 + } else if (NULL == textures) { 1.2496 + // if we don't have texture coordinates, ignore the shader 1.2497 + p.setShader(NULL); 1.2498 + shader = NULL; 1.2499 + } 1.2500 + 1.2501 + // setup the custom shader (if needed) 1.2502 + if (NULL != colors) { 1.2503 + if (NULL == textures) { 1.2504 + // just colors (no texture) 1.2505 + shader = p.setShader(&triShader); 1.2506 + } else { 1.2507 + // colors * texture 1.2508 + SkASSERT(shader); 1.2509 + bool releaseMode = false; 1.2510 + if (NULL == xmode) { 1.2511 + xmode = SkXfermode::Create(SkXfermode::kModulate_Mode); 1.2512 + releaseMode = true; 1.2513 + } 1.2514 + SkShader* compose = SkNEW_ARGS(SkComposeShader, 1.2515 + (&triShader, shader, xmode)); 1.2516 + p.setShader(compose)->unref(); 1.2517 + if (releaseMode) { 1.2518 + xmode->unref(); 1.2519 + } 1.2520 + } 1.2521 + } 1.2522 + 1.2523 + SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p); 1.2524 + // important that we abort early, as below we may manipulate the shader 1.2525 + // and that is only valid if the shader returned true from setContext. 1.2526 + // If it returned false, then our blitter will be the NullBlitter. 1.2527 + if (blitter->isNullBlitter()) { 1.2528 + return; 1.2529 + } 1.2530 + 1.2531 + // setup our state and function pointer for iterating triangles 1.2532 + VertState state(count, indices, indexCount); 1.2533 + VertState::Proc vertProc = state.chooseProc(vmode); 1.2534 + 1.2535 + if (NULL != textures || NULL != colors) { 1.2536 + SkMatrix tempM; 1.2537 + SkMatrix savedLocalM; 1.2538 + if (shader) { 1.2539 + savedLocalM = shader->getLocalMatrix(); 1.2540 + } 1.2541 + 1.2542 + // setContext has already been called and verified to return true 1.2543 + // by the constructor of SkAutoBlitterChoose 1.2544 + bool prevContextSuccess = true; 1.2545 + while (vertProc(&state)) { 1.2546 + if (NULL != textures) { 1.2547 + if (texture_to_matrix(state, vertices, textures, &tempM)) { 1.2548 + tempM.postConcat(savedLocalM); 1.2549 + shader->setLocalMatrix(tempM); 1.2550 + // Need to recall setContext since we changed the local matrix. 1.2551 + // However, we also need to balance the calls this with a 1.2552 + // call to endContext which requires tracking the result of 1.2553 + // the previous call to setContext. 1.2554 + if (prevContextSuccess) { 1.2555 + shader->endContext(); 1.2556 + } 1.2557 + prevContextSuccess = shader->setContext(*fBitmap, p, *fMatrix); 1.2558 + if (!prevContextSuccess) { 1.2559 + continue; 1.2560 + } 1.2561 + } 1.2562 + } 1.2563 + if (NULL != colors) { 1.2564 + if (!triShader.setup(vertices, colors, 1.2565 + state.f0, state.f1, state.f2)) { 1.2566 + continue; 1.2567 + } 1.2568 + } 1.2569 + 1.2570 + SkPoint tmp[] = { 1.2571 + devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 1.2572 + }; 1.2573 + SkScan::FillTriangle(tmp, *fRC, blitter.get()); 1.2574 + } 1.2575 + 1.2576 + // now restore the shader's original local matrix 1.2577 + if (NULL != shader) { 1.2578 + shader->setLocalMatrix(savedLocalM); 1.2579 + } 1.2580 + 1.2581 + // If the final call to setContext fails we must make it suceed so that the 1.2582 + // call to endContext in the destructor for SkAutoBlitterChoose is balanced. 1.2583 + if (!prevContextSuccess) { 1.2584 + prevContextSuccess = shader->setContext(*fBitmap, paint, SkMatrix::I()); 1.2585 + SkASSERT(prevContextSuccess); 1.2586 + } 1.2587 + } else { 1.2588 + // no colors[] and no texture 1.2589 + HairProc hairProc = ChooseHairProc(paint.isAntiAlias()); 1.2590 + const SkRasterClip& clip = *fRC; 1.2591 + while (vertProc(&state)) { 1.2592 + hairProc(devVerts[state.f0], devVerts[state.f1], clip, blitter.get()); 1.2593 + hairProc(devVerts[state.f1], devVerts[state.f2], clip, blitter.get()); 1.2594 + hairProc(devVerts[state.f2], devVerts[state.f0], clip, blitter.get()); 1.2595 + } 1.2596 + } 1.2597 +} 1.2598 + 1.2599 +/////////////////////////////////////////////////////////////////////////////// 1.2600 +/////////////////////////////////////////////////////////////////////////////// 1.2601 + 1.2602 +#ifdef SK_DEBUG 1.2603 + 1.2604 +void SkDraw::validate() const { 1.2605 + SkASSERT(fBitmap != NULL); 1.2606 + SkASSERT(fMatrix != NULL); 1.2607 + SkASSERT(fClip != NULL); 1.2608 + SkASSERT(fRC != NULL); 1.2609 + 1.2610 + const SkIRect& cr = fRC->getBounds(); 1.2611 + SkIRect br; 1.2612 + 1.2613 + br.set(0, 0, fBitmap->width(), fBitmap->height()); 1.2614 + SkASSERT(cr.isEmpty() || br.contains(cr)); 1.2615 +} 1.2616 + 1.2617 +#endif 1.2618 + 1.2619 +/////////////////////////////////////////////////////////////////////////////// 1.2620 + 1.2621 +SkBounder::SkBounder() { 1.2622 + // initialize up front. This gets reset by SkCanvas before each draw call. 1.2623 + fClip = &SkRegion::GetEmptyRegion(); 1.2624 +} 1.2625 + 1.2626 +bool SkBounder::doIRect(const SkIRect& r) { 1.2627 + SkIRect rr; 1.2628 + return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr); 1.2629 +} 1.2630 + 1.2631 +// TODO: change the prototype to take fixed, and update the callers 1.2632 +bool SkBounder::doIRectGlyph(const SkIRect& r, int x, int y, 1.2633 + const SkGlyph& glyph) { 1.2634 + SkIRect rr; 1.2635 + if (!rr.intersect(fClip->getBounds(), r)) { 1.2636 + return false; 1.2637 + } 1.2638 + GlyphRec rec; 1.2639 + rec.fLSB.set(SkIntToFixed(x), SkIntToFixed(y)); 1.2640 + rec.fRSB.set(rec.fLSB.fX + glyph.fAdvanceX, 1.2641 + rec.fLSB.fY + glyph.fAdvanceY); 1.2642 + rec.fGlyphID = glyph.getGlyphID(); 1.2643 + rec.fFlags = 0; 1.2644 + return this->onIRectGlyph(rr, rec); 1.2645 +} 1.2646 + 1.2647 +bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1, 1.2648 + const SkPaint& paint) { 1.2649 + SkIRect r; 1.2650 + SkScalar v0, v1; 1.2651 + 1.2652 + v0 = pt0.fX; 1.2653 + v1 = pt1.fX; 1.2654 + if (v0 > v1) { 1.2655 + SkTSwap<SkScalar>(v0, v1); 1.2656 + } 1.2657 + r.fLeft = SkScalarFloorToInt(v0); 1.2658 + r.fRight = SkScalarCeilToInt(v1); 1.2659 + 1.2660 + v0 = pt0.fY; 1.2661 + v1 = pt1.fY; 1.2662 + if (v0 > v1) { 1.2663 + SkTSwap<SkScalar>(v0, v1); 1.2664 + } 1.2665 + r.fTop = SkScalarFloorToInt(v0); 1.2666 + r.fBottom = SkScalarCeilToInt(v1); 1.2667 + 1.2668 + if (paint.isAntiAlias()) { 1.2669 + r.inset(-1, -1); 1.2670 + } 1.2671 + return this->doIRect(r); 1.2672 +} 1.2673 + 1.2674 +bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) { 1.2675 + SkIRect r; 1.2676 + 1.2677 + if (paint.getStyle() == SkPaint::kFill_Style) { 1.2678 + rect.round(&r); 1.2679 + } else { 1.2680 + int rad = -1; 1.2681 + rect.roundOut(&r); 1.2682 + if (paint.isAntiAlias()) { 1.2683 + rad = -2; 1.2684 + } 1.2685 + r.inset(rad, rad); 1.2686 + } 1.2687 + return this->doIRect(r); 1.2688 +} 1.2689 + 1.2690 +bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) { 1.2691 + SkIRect r; 1.2692 + const SkRect& bounds = path.getBounds(); 1.2693 + 1.2694 + if (doFill) { 1.2695 + bounds.round(&r); 1.2696 + } else { // hairline 1.2697 + bounds.roundOut(&r); 1.2698 + } 1.2699 + 1.2700 + if (paint.isAntiAlias()) { 1.2701 + r.inset(-1, -1); 1.2702 + } 1.2703 + return this->doIRect(r); 1.2704 +} 1.2705 + 1.2706 +void SkBounder::commit() { 1.2707 + // override in subclass 1.2708 +} 1.2709 + 1.2710 +//////////////////////////////////////////////////////////////////////////////////////////////// 1.2711 + 1.2712 +#include "SkPath.h" 1.2713 +#include "SkDraw.h" 1.2714 +#include "SkRegion.h" 1.2715 +#include "SkBlitter.h" 1.2716 + 1.2717 +static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 1.2718 + const SkMaskFilter* filter, const SkMatrix* filterMatrix, 1.2719 + SkIRect* bounds) { 1.2720 + if (devPath.isEmpty()) { 1.2721 + return false; 1.2722 + } 1.2723 + 1.2724 + // init our bounds from the path 1.2725 + { 1.2726 + SkRect pathBounds = devPath.getBounds(); 1.2727 + pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf); 1.2728 + pathBounds.roundOut(bounds); 1.2729 + } 1.2730 + 1.2731 + SkIPoint margin = SkIPoint::Make(0, 0); 1.2732 + if (filter) { 1.2733 + SkASSERT(filterMatrix); 1.2734 + 1.2735 + SkMask srcM, dstM; 1.2736 + 1.2737 + srcM.fBounds = *bounds; 1.2738 + srcM.fFormat = SkMask::kA8_Format; 1.2739 + srcM.fImage = NULL; 1.2740 + if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 1.2741 + return false; 1.2742 + } 1.2743 + } 1.2744 + 1.2745 + // (possibly) trim the bounds to reflect the clip 1.2746 + // (plus whatever slop the filter needs) 1.2747 + if (clipBounds) { 1.2748 + SkIRect tmp = *clipBounds; 1.2749 + // Ugh. Guard against gigantic margins from wacky filters. Without this 1.2750 + // check we can request arbitrary amounts of slop beyond our visible 1.2751 + // clip, and bring down the renderer (at least on finite RAM machines 1.2752 + // like handsets, etc.). Need to balance this invented value between 1.2753 + // quality of large filters like blurs, and the corresponding memory 1.2754 + // requests. 1.2755 + static const int MAX_MARGIN = 128; 1.2756 + tmp.inset(-SkMin32(margin.fX, MAX_MARGIN), 1.2757 + -SkMin32(margin.fY, MAX_MARGIN)); 1.2758 + if (!bounds->intersect(tmp)) { 1.2759 + return false; 1.2760 + } 1.2761 + } 1.2762 + 1.2763 + return true; 1.2764 +} 1.2765 + 1.2766 +static void draw_into_mask(const SkMask& mask, const SkPath& devPath, 1.2767 + SkPaint::Style style) { 1.2768 + SkBitmap bm; 1.2769 + SkDraw draw; 1.2770 + SkRasterClip clip; 1.2771 + SkMatrix matrix; 1.2772 + SkPaint paint; 1.2773 + 1.2774 + bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); 1.2775 + bm.setPixels(mask.fImage); 1.2776 + 1.2777 + clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 1.2778 + matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 1.2779 + -SkIntToScalar(mask.fBounds.fTop)); 1.2780 + 1.2781 + draw.fBitmap = &bm; 1.2782 + draw.fRC = &clip; 1.2783 + draw.fClip = &clip.bwRgn(); 1.2784 + draw.fMatrix = &matrix; 1.2785 + draw.fBounder = NULL; 1.2786 + paint.setAntiAlias(true); 1.2787 + paint.setStyle(style); 1.2788 + draw.drawPath(devPath, paint); 1.2789 +} 1.2790 + 1.2791 +bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 1.2792 + const SkMaskFilter* filter, const SkMatrix* filterMatrix, 1.2793 + SkMask* mask, SkMask::CreateMode mode, 1.2794 + SkPaint::Style style) { 1.2795 + if (SkMask::kJustRenderImage_CreateMode != mode) { 1.2796 + if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 1.2797 + return false; 1.2798 + } 1.2799 + 1.2800 + if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 1.2801 + mask->fFormat = SkMask::kA8_Format; 1.2802 + mask->fRowBytes = mask->fBounds.width(); 1.2803 + size_t size = mask->computeImageSize(); 1.2804 + if (0 == size) { 1.2805 + // we're too big to allocate the mask, abort 1.2806 + return false; 1.2807 + } 1.2808 + mask->fImage = SkMask::AllocImage(size); 1.2809 + memset(mask->fImage, 0, mask->computeImageSize()); 1.2810 + } 1.2811 + 1.2812 + if (SkMask::kJustComputeBounds_CreateMode != mode) { 1.2813 + draw_into_mask(*mask, devPath, style); 1.2814 + } 1.2815 + 1.2816 + return true; 1.2817 +}