SkDraw.cpp revision cfb6bdf767796c950f89985445738d2d8e7f12b0
1ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler/* 2ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * Copyright 2006 The Android Open Source Project 3ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * 4ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * Use of this source code is governed by a BSD-style license that can be 5ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * found in the LICENSE file. 6ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler */ 7ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#define __STDC_LIMIT_MACROS 8ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 9ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkDraw.h" 10ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkBlitter.h" 11ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkCanvas.h" 12ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkColorPriv.h" 13ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkDevice.h" 14ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkDeviceLooper.h" 15ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkFindAndPlaceGlyph.h" 16ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkFixed.h" 17ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkMaskFilter.h" 18ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkMatrix.h" 19ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkPaint.h" 20ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkPathEffect.h" 21ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkRasterClip.h" 22ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkRasterizer.h" 23ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkRRect.h" 24ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkScan.h" 25ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkShader.h" 26ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkSmallAllocator.h" 27ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkString.h" 28ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkStroke.h" 29ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkStrokeRec.h" 30ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkTemplates.h" 31ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkTextMapStateProc.h" 32625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler#include "SkTLazy.h" 33ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkUtils.h" 34ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkVertState.h" 35ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkXfermode.h" 36ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 37ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkBitmapProcShader.h" 38ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkDrawProcs.h" 39ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#include "SkMatrixUtils.h" 40ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 41ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler//#define TRACE_BITMAP_DRAWS 42ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 43ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler// Helper function to fix code gen bug on ARM64. 44ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler// See SkFindAndPlaceGlyph.h for more details. 45625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nisslervoid FixGCC49Arm64Bug(int v) { } 46ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 47ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler/** Helper for allocating small blitters on the stack. 48ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler */ 49ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerclass SkAutoBlitterChoose : SkNoncopyable { 50ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerpublic: 51ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkAutoBlitterChoose() { 52ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler fBlitter = nullptr; 53ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } 54625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler SkAutoBlitterChoose(const SkPixmap& dst, const SkMatrix& matrix, 55625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler const SkPaint& paint, bool drawCoverage = false) { 56625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); 57625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler } 58625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 59ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkBlitter* operator->() { return fBlitter; } 60ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkBlitter* get() const { return fBlitter; } 61625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 62625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler void choose(const SkPixmap& dst, const SkMatrix& matrix, 63625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler const SkPaint& paint, bool drawCoverage = false) { 64625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler SkASSERT(!fBlitter); 65625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler fBlitter = SkBlitter::Choose(dst, matrix, paint, &fAllocator, drawCoverage); 66625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler } 67625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 68625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nisslerprivate: 69ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // Owned by fAllocator, which will handle the delete. 70ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkBlitter* fBlitter; 71ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkTBlitterAllocator fAllocator; 72ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler}; 73625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler#define SkAutoBlitterChoose(...) SK_REQUIRE_LOCAL_VAR(SkAutoBlitterChoose) 74625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 75ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler/** 76ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * Since we are providing the storage for the shader (to avoid the perf cost 77ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler * of calling new) we insist that in our destructor we can account for all 78625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler * owners of the shader. 79625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler */ 80ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerclass SkAutoBitmapShaderInstall : SkNoncopyable { 81ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerpublic: 82ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint, 83ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler const SkMatrix* localMatrix = nullptr) 84ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler : fPaint(paint) /* makes a copy of the paint */ { 85ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler fPaint.setShader(SkMakeBitmapShader(src, SkShader::kClamp_TileMode, 86ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkShader::kClamp_TileMode, localMatrix, &fAllocator)); 87ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // we deliberately left the shader with an owner-count of 2 88ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler fPaint.getShader()->ref(); 89ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkASSERT(2 == fPaint.getShader()->getRefCnt()); 90ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } 91ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 92ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler ~SkAutoBitmapShaderInstall() { 93ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // since fAllocator will destroy shader, we insist that owners == 2 94ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkASSERT(2 == fPaint.getShader()->getRefCnt()); 95ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 96ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler fPaint.setShader(nullptr); // unref the shader by 1 97ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 98ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } 99ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 100ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // return the new paint that has the shader applied 101ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler const SkPaint& paintWithShader() const { return fPaint; } 102ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 103ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerprivate: 104ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // copy of caller's paint (which we then modify) 105ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkPaint fPaint; 106ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // Stores the shader. 107ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkTBlitterAllocator fAllocator; 108ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler}; 109ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler#define SkAutoBitmapShaderInstall(...) SK_REQUIRE_LOCAL_VAR(SkAutoBitmapShaderInstall) 110ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 111ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler/////////////////////////////////////////////////////////////////////////////// 112ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 113ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias NisslerSkDraw::SkDraw() { 114ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler sk_bzero(this, sizeof(*this)); 115ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 116ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 117ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias NisslerSkDraw::SkDraw(const SkDraw& src) { 118ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler memcpy(this, &src, sizeof(*this)); 119ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 120ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 121ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerbool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 122ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler if (fRC->isEmpty()) { 123ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler return false; 124ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } 125ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 126ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkMatrix inverse; 127ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler if (!fMatrix->invert(&inverse)) { 128ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler return false; 129ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } 130ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 131ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkIRect devBounds = fRC->getBounds(); 132ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // outset to have slop for antialasing and hairlines 133ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler devBounds.outset(1, 1); 134ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler inverse.mapRect(localBounds, SkRect::Make(devBounds)); 135625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler return true; 136625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler} 137625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 138625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler/////////////////////////////////////////////////////////////////////////////// 139625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 140625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nisslertypedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 141ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 142ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 143ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler sk_bzero(pixels, bytes); 144ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 145ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 146ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 147ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 148ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 149ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2)); 150ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 151ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 152ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 153ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1)); 154ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 155625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 156ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 157ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler memset(pixels, data, bytes); 158ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler} 159ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 160ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nisslerstatic BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint, 161ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler uint32_t* data) { 162ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // todo: we can apply colorfilter up front if no shader, so we wouldn't 163ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler // need to abort this fastpath 164ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler if (paint.getShader() || paint.getColorFilter()) { 165625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler return nullptr; 166625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler } 167625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 168625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler SkXfermode::Mode mode; 169625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler if (!SkXfermode::AsMode(paint.getXfermode(), &mode)) { 170625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler return nullptr; 171625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler } 172625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler 173ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler SkColor color = paint.getColor(); 174ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler 175625cbbe0b6f4a31079e889ac092456ac1893812bMattias Nissler // collaps modes based on color... 176ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler if (SkXfermode::kSrcOver_Mode == mode) { 177ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler unsigned alpha = SkColorGetA(color); 178ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler if (0 == alpha) { 179ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler mode = SkXfermode::kDst_Mode; 180ad80c7ab75ab15826ba825b609c3e27af4449e86Mattias Nissler } else if (0xFF == alpha) { 181 mode = SkXfermode::kSrc_Mode; 182 } 183 } 184 185 switch (mode) { 186 case SkXfermode::kClear_Mode: 187// SkDebugf("--- D_Clear_BitmapXferProc\n"); 188 return D_Clear_BitmapXferProc; // ignore data 189 case SkXfermode::kDst_Mode: 190// SkDebugf("--- D_Dst_BitmapXferProc\n"); 191 return D_Dst_BitmapXferProc; // ignore data 192 case SkXfermode::kSrc_Mode: { 193 /* 194 should I worry about dithering for the lower depths? 195 */ 196 SkPMColor pmc = SkPreMultiplyColor(color); 197 switch (dst.colorType()) { 198 case kN32_SkColorType: 199 if (data) { 200 *data = pmc; 201 } 202// SkDebugf("--- D32_Src_BitmapXferProc\n"); 203 return D32_Src_BitmapXferProc; 204 case kRGB_565_SkColorType: 205 if (data) { 206 *data = SkPixel32ToPixel16(pmc); 207 } 208// SkDebugf("--- D16_Src_BitmapXferProc\n"); 209 return D16_Src_BitmapXferProc; 210 case kAlpha_8_SkColorType: 211 if (data) { 212 *data = SkGetPackedA32(pmc); 213 } 214// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 215 return DA8_Src_BitmapXferProc; 216 default: 217 break; 218 } 219 break; 220 } 221 default: 222 break; 223 } 224 return nullptr; 225} 226 227static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc, 228 uint32_t procData) { 229 int shiftPerPixel; 230 switch (dst.colorType()) { 231 case kN32_SkColorType: 232 shiftPerPixel = 2; 233 break; 234 case kRGB_565_SkColorType: 235 shiftPerPixel = 1; 236 break; 237 case kAlpha_8_SkColorType: 238 shiftPerPixel = 0; 239 break; 240 default: 241 SkDEBUGFAIL("Can't use xferproc on this config"); 242 return; 243 } 244 245 uint8_t* pixels = (uint8_t*)dst.writable_addr(); 246 SkASSERT(pixels); 247 const size_t rowBytes = dst.rowBytes(); 248 const int widthBytes = rect.width() << shiftPerPixel; 249 250 // skip down to the first scanline and X position 251 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 252 for (int scans = rect.height() - 1; scans >= 0; --scans) { 253 proc(pixels, widthBytes, procData); 254 pixels += rowBytes; 255 } 256} 257 258void SkDraw::drawPaint(const SkPaint& paint) const { 259 SkDEBUGCODE(this->validate();) 260 261 if (fRC->isEmpty()) { 262 return; 263 } 264 265 SkIRect devRect; 266 devRect.set(0, 0, fDst.width(), fDst.height()); 267 268 if (fRC->isBW()) { 269 /* If we don't have a shader (i.e. we're just a solid color) we may 270 be faster to operate directly on the device bitmap, rather than invoking 271 a blitter. Esp. true for xfermodes, which require a colorshader to be 272 present, which is just redundant work. Since we're drawing everywhere 273 in the clip, we don't have to worry about antialiasing. 274 */ 275 uint32_t procData = 0; // to avoid the warning 276 BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData); 277 if (proc) { 278 if (D_Dst_BitmapXferProc == proc) { // nothing to do 279 return; 280 } 281 282 SkRegion::Iterator iter(fRC->bwRgn()); 283 while (!iter.done()) { 284 CallBitmapXferProc(fDst, iter.rect(), proc, procData); 285 iter.next(); 286 } 287 return; 288 } 289 } 290 291 // normal case: use a blitter 292 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 293 SkScan::FillIRect(devRect, *fRC, blitter.get()); 294} 295 296/////////////////////////////////////////////////////////////////////////////// 297 298struct PtProcRec { 299 SkCanvas::PointMode fMode; 300 const SkPaint* fPaint; 301 const SkRegion* fClip; 302 const SkRasterClip* fRC; 303 304 // computed values 305 SkFixed fRadius; 306 307 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 308 SkBlitter*); 309 310 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 311 const SkRasterClip*); 312 Proc chooseProc(SkBlitter** blitter); 313 314private: 315 SkAAClipBlitterWrapper fWrapper; 316}; 317 318static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 319 int count, SkBlitter* blitter) { 320 SkASSERT(rec.fClip->isRect()); 321 const SkIRect& r = rec.fClip->getBounds(); 322 323 for (int i = 0; i < count; i++) { 324 int x = SkScalarFloorToInt(devPts[i].fX); 325 int y = SkScalarFloorToInt(devPts[i].fY); 326 if (r.contains(x, y)) { 327 blitter->blitH(x, y, 1); 328 } 329 } 330} 331 332static void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 333 const SkPoint devPts[], int count, 334 SkBlitter* blitter) { 335 SkASSERT(rec.fRC->isRect()); 336 const SkIRect& r = rec.fRC->getBounds(); 337 uint32_t value; 338 const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 339 SkASSERT(dst); 340 341 uint16_t* addr = dst->writable_addr16(0, 0); 342 size_t rb = dst->rowBytes(); 343 344 for (int i = 0; i < count; i++) { 345 int x = SkScalarFloorToInt(devPts[i].fX); 346 int y = SkScalarFloorToInt(devPts[i].fY); 347 if (r.contains(x, y)) { 348 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 349 } 350 } 351} 352 353static void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 354 const SkPoint devPts[], int count, 355 SkBlitter* blitter) { 356 SkASSERT(rec.fRC->isRect()); 357 const SkIRect& r = rec.fRC->getBounds(); 358 uint32_t value; 359 const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 360 SkASSERT(dst); 361 362 SkPMColor* addr = dst->writable_addr32(0, 0); 363 size_t rb = dst->rowBytes(); 364 365 for (int i = 0; i < count; i++) { 366 int x = SkScalarFloorToInt(devPts[i].fX); 367 int y = SkScalarFloorToInt(devPts[i].fY); 368 if (r.contains(x, y)) { 369 ((SkPMColor*)((char*)addr + y * rb))[x] = value; 370 } 371 } 372} 373 374static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 375 int count, SkBlitter* blitter) { 376 for (int i = 0; i < count; i++) { 377 int x = SkScalarFloorToInt(devPts[i].fX); 378 int y = SkScalarFloorToInt(devPts[i].fY); 379 if (rec.fClip->contains(x, y)) { 380 blitter->blitH(x, y, 1); 381 } 382 } 383} 384 385static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 386 int count, SkBlitter* blitter) { 387 for (int i = 0; i < count; i += 2) { 388 SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter); 389 } 390} 391 392static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 393 int count, SkBlitter* blitter) { 394 SkScan::HairLine(devPts, count, *rec.fRC, blitter); 395} 396 397// aa versions 398 399static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 400 int count, SkBlitter* blitter) { 401 for (int i = 0; i < count; i += 2) { 402 SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter); 403 } 404} 405 406static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 407 int count, SkBlitter* blitter) { 408 SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter); 409} 410 411// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 412 413static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 414 int count, SkBlitter* blitter) { 415 const SkFixed radius = rec.fRadius; 416 for (int i = 0; i < count; i++) { 417 SkFixed x = SkScalarToFixed(devPts[i].fX); 418 SkFixed y = SkScalarToFixed(devPts[i].fY); 419 420 SkXRect r; 421 r.fLeft = x - radius; 422 r.fTop = y - radius; 423 r.fRight = x + radius; 424 r.fBottom = y + radius; 425 426 SkScan::FillXRect(r, *rec.fRC, blitter); 427 } 428} 429 430static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 431 int count, SkBlitter* blitter) { 432 const SkFixed radius = rec.fRadius; 433 for (int i = 0; i < count; i++) { 434 SkFixed x = SkScalarToFixed(devPts[i].fX); 435 SkFixed y = SkScalarToFixed(devPts[i].fY); 436 437 SkXRect r; 438 r.fLeft = x - radius; 439 r.fTop = y - radius; 440 r.fRight = x + radius; 441 r.fBottom = y + radius; 442 443 SkScan::AntiFillXRect(r, *rec.fRC, blitter); 444 } 445} 446 447// If this guy returns true, then chooseProc() must return a valid proc 448bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 449 const SkMatrix* matrix, const SkRasterClip* rc) { 450 if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) { 451 return false; 452 } 453 454 if (paint.getPathEffect()) { 455 return false; 456 } 457 SkScalar width = paint.getStrokeWidth(); 458 if (0 == width) { 459 fMode = mode; 460 fPaint = &paint; 461 fClip = nullptr; 462 fRC = rc; 463 fRadius = SK_FixedHalf; 464 return true; 465 } 466 if (paint.getStrokeCap() != SkPaint::kRound_Cap && 467 matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) { 468 SkScalar sx = matrix->get(SkMatrix::kMScaleX); 469 SkScalar sy = matrix->get(SkMatrix::kMScaleY); 470 if (SkScalarNearlyZero(sx - sy)) { 471 if (sx < 0) { 472 sx = -sx; 473 } 474 475 fMode = mode; 476 fPaint = &paint; 477 fClip = nullptr; 478 fRC = rc; 479 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1; 480 return true; 481 } 482 } 483 return false; 484} 485 486PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 487 Proc proc = nullptr; 488 489 SkBlitter* blitter = *blitterPtr; 490 if (fRC->isBW()) { 491 fClip = &fRC->bwRgn(); 492 } else { 493 fWrapper.init(*fRC, blitter); 494 fClip = &fWrapper.getRgn(); 495 blitter = fWrapper.getBlitter(); 496 *blitterPtr = blitter; 497 } 498 499 // for our arrays 500 SkASSERT(0 == SkCanvas::kPoints_PointMode); 501 SkASSERT(1 == SkCanvas::kLines_PointMode); 502 SkASSERT(2 == SkCanvas::kPolygon_PointMode); 503 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 504 505 if (fPaint->isAntiAlias()) { 506 if (0 == fPaint->getStrokeWidth()) { 507 static const Proc gAAProcs[] = { 508 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 509 }; 510 proc = gAAProcs[fMode]; 511 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 512 SkASSERT(SkCanvas::kPoints_PointMode == fMode); 513 proc = aa_square_proc; 514 } 515 } else { // BW 516 if (fRadius <= SK_FixedHalf) { // small radii and hairline 517 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 518 uint32_t value; 519 const SkPixmap* bm = blitter->justAnOpaqueColor(&value); 520 if (bm && kRGB_565_SkColorType == bm->colorType()) { 521 proc = bw_pt_rect_16_hair_proc; 522 } else if (bm && kN32_SkColorType == bm->colorType()) { 523 proc = bw_pt_rect_32_hair_proc; 524 } else { 525 proc = bw_pt_rect_hair_proc; 526 } 527 } else { 528 static Proc gBWProcs[] = { 529 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 530 }; 531 proc = gBWProcs[fMode]; 532 } 533 } else { 534 proc = bw_square_proc; 535 } 536 } 537 return proc; 538} 539 540// each of these costs 8-bytes of stack space, so don't make it too large 541// must be even for lines/polygon to work 542#define MAX_DEV_PTS 32 543 544void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 545 const SkPoint pts[], const SkPaint& paint, 546 bool forceUseDevice) const { 547 // if we're in lines mode, force count to be even 548 if (SkCanvas::kLines_PointMode == mode) { 549 count &= ~(size_t)1; 550 } 551 552 if ((long)count <= 0) { 553 return; 554 } 555 556 SkASSERT(pts != nullptr); 557 SkDEBUGCODE(this->validate();) 558 559 // nothing to draw 560 if (fRC->isEmpty()) { 561 return; 562 } 563 564 PtProcRec rec; 565 if (!forceUseDevice && rec.init(mode, paint, fMatrix, fRC)) { 566 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 567 568 SkPoint devPts[MAX_DEV_PTS]; 569 const SkMatrix* matrix = fMatrix; 570 SkBlitter* bltr = blitter.get(); 571 PtProcRec::Proc proc = rec.chooseProc(&bltr); 572 // we have to back up subsequent passes if we're in polygon mode 573 const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 574 575 do { 576 int n = SkToInt(count); 577 if (n > MAX_DEV_PTS) { 578 n = MAX_DEV_PTS; 579 } 580 matrix->mapPoints(devPts, pts, n); 581 proc(rec, devPts, n, bltr); 582 pts += n - backup; 583 SkASSERT(SkToInt(count) >= n); 584 count -= n; 585 if (count > 0) { 586 count += backup; 587 } 588 } while (count != 0); 589 } else { 590 switch (mode) { 591 case SkCanvas::kPoints_PointMode: { 592 // temporarily mark the paint as filling. 593 SkPaint newPaint(paint); 594 newPaint.setStyle(SkPaint::kFill_Style); 595 596 SkScalar width = newPaint.getStrokeWidth(); 597 SkScalar radius = SkScalarHalf(width); 598 599 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 600 SkPath path; 601 SkMatrix preMatrix; 602 603 path.addCircle(0, 0, radius); 604 for (size_t i = 0; i < count; i++) { 605 preMatrix.setTranslate(pts[i].fX, pts[i].fY); 606 // pass true for the last point, since we can modify 607 // then path then 608 path.setIsVolatile((count-1) == i); 609 if (fDevice) { 610 fDevice->drawPath(*this, path, newPaint, &preMatrix, 611 (count-1) == i); 612 } else { 613 this->drawPath(path, newPaint, &preMatrix, 614 (count-1) == i); 615 } 616 } 617 } else { 618 SkRect r; 619 620 for (size_t i = 0; i < count; i++) { 621 r.fLeft = pts[i].fX - radius; 622 r.fTop = pts[i].fY - radius; 623 r.fRight = r.fLeft + width; 624 r.fBottom = r.fTop + width; 625 if (fDevice) { 626 fDevice->drawRect(*this, r, newPaint); 627 } else { 628 this->drawRect(r, newPaint); 629 } 630 } 631 } 632 break; 633 } 634 case SkCanvas::kLines_PointMode: 635 if (2 == count && paint.getPathEffect()) { 636 // most likely a dashed line - see if it is one of the ones 637 // we can accelerate 638 SkStrokeRec rec(paint); 639 SkPathEffect::PointData pointData; 640 641 SkPath path; 642 path.moveTo(pts[0]); 643 path.lineTo(pts[1]); 644 645 SkRect cullRect = SkRect::Make(fRC->getBounds()); 646 647 if (paint.getPathEffect()->asPoints(&pointData, path, rec, 648 *fMatrix, &cullRect)) { 649 // 'asPoints' managed to find some fast path 650 651 SkPaint newP(paint); 652 newP.setPathEffect(nullptr); 653 newP.setStyle(SkPaint::kFill_Style); 654 655 if (!pointData.fFirst.isEmpty()) { 656 if (fDevice) { 657 fDevice->drawPath(*this, pointData.fFirst, newP); 658 } else { 659 this->drawPath(pointData.fFirst, newP); 660 } 661 } 662 663 if (!pointData.fLast.isEmpty()) { 664 if (fDevice) { 665 fDevice->drawPath(*this, pointData.fLast, newP); 666 } else { 667 this->drawPath(pointData.fLast, newP); 668 } 669 } 670 671 if (pointData.fSize.fX == pointData.fSize.fY) { 672 // The rest of the dashed line can just be drawn as points 673 SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 674 675 if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 676 newP.setStrokeCap(SkPaint::kRound_Cap); 677 } else { 678 newP.setStrokeCap(SkPaint::kButt_Cap); 679 } 680 681 if (fDevice) { 682 fDevice->drawPoints(*this, 683 SkCanvas::kPoints_PointMode, 684 pointData.fNumPoints, 685 pointData.fPoints, 686 newP); 687 } else { 688 this->drawPoints(SkCanvas::kPoints_PointMode, 689 pointData.fNumPoints, 690 pointData.fPoints, 691 newP, 692 forceUseDevice); 693 } 694 break; 695 } else { 696 // The rest of the dashed line must be drawn as rects 697 SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 698 pointData.fFlags)); 699 700 SkRect r; 701 702 for (int i = 0; i < pointData.fNumPoints; ++i) { 703 r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 704 pointData.fPoints[i].fY - pointData.fSize.fY, 705 pointData.fPoints[i].fX + pointData.fSize.fX, 706 pointData.fPoints[i].fY + pointData.fSize.fY); 707 if (fDevice) { 708 fDevice->drawRect(*this, r, newP); 709 } else { 710 this->drawRect(r, newP); 711 } 712 } 713 } 714 715 break; 716 } 717 } 718 // couldn't take fast path so fall through! 719 case SkCanvas::kPolygon_PointMode: { 720 count -= 1; 721 SkPath path; 722 SkPaint p(paint); 723 p.setStyle(SkPaint::kStroke_Style); 724 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 725 path.setIsVolatile(true); 726 for (size_t i = 0; i < count; i += inc) { 727 path.moveTo(pts[i]); 728 path.lineTo(pts[i+1]); 729 if (fDevice) { 730 fDevice->drawPath(*this, path, p, nullptr, true); 731 } else { 732 this->drawPath(path, p, nullptr, true); 733 } 734 path.rewind(); 735 } 736 break; 737 } 738 } 739 } 740} 741 742static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) { 743 SkASSERT(matrix.rectStaysRect()); 744 SkASSERT(SkPaint::kFill_Style != paint.getStyle()); 745 746 SkVector size; 747 SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 748 matrix.mapVectors(&size, &pt, 1); 749 return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY)); 750} 751 752static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 753 SkPoint* strokeSize) { 754 if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 755 paint.getStrokeMiter() < SK_ScalarSqrt2) { 756 return false; 757 } 758 759 *strokeSize = compute_stroke_size(paint, matrix); 760 return true; 761} 762 763SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 764 const SkMatrix& matrix, 765 SkPoint* strokeSize) { 766 RectType rtype; 767 const SkScalar width = paint.getStrokeWidth(); 768 const bool zeroWidth = (0 == width); 769 SkPaint::Style style = paint.getStyle(); 770 771 if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 772 style = SkPaint::kFill_Style; 773 } 774 775 if (paint.getPathEffect() || paint.getMaskFilter() || 776 paint.getRasterizer() || !matrix.rectStaysRect() || 777 SkPaint::kStrokeAndFill_Style == style) { 778 rtype = kPath_RectType; 779 } else if (SkPaint::kFill_Style == style) { 780 rtype = kFill_RectType; 781 } else if (zeroWidth) { 782 rtype = kHair_RectType; 783 } else if (easy_rect_join(paint, matrix, strokeSize)) { 784 rtype = kStroke_RectType; 785 } else { 786 rtype = kPath_RectType; 787 } 788 return rtype; 789} 790 791static const SkPoint* rect_points(const SkRect& r) { 792 return SkTCast<const SkPoint*>(&r); 793} 794 795static SkPoint* rect_points(SkRect& r) { 796 return SkTCast<SkPoint*>(&r); 797} 798 799void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint, 800 const SkMatrix* paintMatrix, const SkRect* postPaintRect) const { 801 SkDEBUGCODE(this->validate();) 802 803 // nothing to draw 804 if (fRC->isEmpty()) { 805 return; 806 } 807 808 const SkMatrix* matrix; 809 SkMatrix combinedMatrixStorage; 810 if (paintMatrix) { 811 SkASSERT(postPaintRect); 812 combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix); 813 matrix = &combinedMatrixStorage; 814 } else { 815 SkASSERT(!postPaintRect); 816 matrix = fMatrix; 817 } 818 819 SkPoint strokeSize; 820 RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 821 822 if (kPath_RectType == rtype) { 823 SkDraw draw(*this); 824 if (paintMatrix) { 825 draw.fMatrix = matrix; 826 } 827 SkPath tmp; 828 tmp.addRect(prePaintRect); 829 tmp.setFillType(SkPath::kWinding_FillType); 830 draw.drawPath(tmp, paint, nullptr, true); 831 return; 832 } 833 834 SkRect devRect; 835 const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect; 836 // skip the paintMatrix when transforming the rect by the CTM 837 fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2); 838 devRect.sort(); 839 840 // look for the quick exit, before we build a blitter 841 SkRect bbox = devRect; 842 if (paint.getStyle() != SkPaint::kFill_Style) { 843 // extra space for hairlines 844 if (paint.getStrokeWidth() == 0) { 845 bbox.outset(1, 1); 846 } else { 847 // For kStroke_RectType, strokeSize is already computed. 848 const SkPoint& ssize = (kStroke_RectType == rtype) 849 ? strokeSize 850 : compute_stroke_size(paint, *fMatrix); 851 bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y())); 852 } 853 } 854 855 SkIRect ir = bbox.roundOut(); 856 if (fRC->quickReject(ir)) { 857 return; 858 } 859 860 SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias()); 861 while (looper.next()) { 862 SkRect localDevRect; 863 looper.mapRect(&localDevRect, devRect); 864 SkMatrix localMatrix; 865 looper.mapMatrix(&localMatrix, *matrix); 866 867 SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint); 868 const SkRasterClip& clip = looper.getRC(); 869 SkBlitter* blitter = blitterStorage.get(); 870 871 // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 872 // case we are also hairline (if we've gotten to here), which devolves to 873 // effectively just kFill 874 switch (rtype) { 875 case kFill_RectType: 876 if (paint.isAntiAlias()) { 877 SkScan::AntiFillRect(localDevRect, clip, blitter); 878 } else { 879 SkScan::FillRect(localDevRect, clip, blitter); 880 } 881 break; 882 case kStroke_RectType: 883 if (paint.isAntiAlias()) { 884 SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 885 } else { 886 SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 887 } 888 break; 889 case kHair_RectType: 890 if (paint.isAntiAlias()) { 891 SkScan::AntiHairRect(localDevRect, clip, blitter); 892 } else { 893 SkScan::HairRect(localDevRect, clip, blitter); 894 } 895 break; 896 default: 897 SkDEBUGFAIL("bad rtype"); 898 } 899 } 900} 901 902void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 903 if (srcM.fBounds.isEmpty()) { 904 return; 905 } 906 907 const SkMask* mask = &srcM; 908 909 SkMask dstM; 910 if (paint.getMaskFilter() && 911 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { 912 mask = &dstM; 913 } 914 SkAutoMaskFreeImage ami(dstM.fImage); 915 916 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 917 SkBlitter* blitter = blitterChooser.get(); 918 919 SkAAClipBlitterWrapper wrapper; 920 const SkRegion* clipRgn; 921 922 if (fRC->isBW()) { 923 clipRgn = &fRC->bwRgn(); 924 } else { 925 wrapper.init(*fRC, blitter); 926 clipRgn = &wrapper.getRgn(); 927 blitter = wrapper.getBlitter(); 928 } 929 blitter->blitMaskRegion(*mask, *clipRgn); 930} 931 932static SkScalar fast_len(const SkVector& vec) { 933 SkScalar x = SkScalarAbs(vec.fX); 934 SkScalar y = SkScalarAbs(vec.fY); 935 if (x < y) { 936 SkTSwap(x, y); 937 } 938 return x + SkScalarHalf(y); 939} 940 941bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix, 942 SkScalar* coverage) { 943 SkASSERT(strokeWidth > 0); 944 // We need to try to fake a thick-stroke with a modulated hairline. 945 946 if (matrix.hasPerspective()) { 947 return false; 948 } 949 950 SkVector src[2], dst[2]; 951 src[0].set(strokeWidth, 0); 952 src[1].set(0, strokeWidth); 953 matrix.mapVectors(dst, src, 2); 954 SkScalar len0 = fast_len(dst[0]); 955 SkScalar len1 = fast_len(dst[1]); 956 if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 957 if (coverage) { 958 *coverage = SkScalarAve(len0, len1); 959 } 960 return true; 961 } 962 return false; 963} 964 965void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 966 SkDEBUGCODE(this->validate()); 967 968 if (fRC->isEmpty()) { 969 return; 970 } 971 972 { 973 // TODO: Investigate optimizing these options. They are in the same 974 // order as SkDraw::drawPath, which handles each case. It may be 975 // that there is no way to optimize for these using the SkRRect path. 976 SkScalar coverage; 977 if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 978 goto DRAW_PATH; 979 } 980 981 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 982 goto DRAW_PATH; 983 } 984 985 if (paint.getRasterizer()) { 986 goto DRAW_PATH; 987 } 988 } 989 990 if (paint.getMaskFilter()) { 991 // Transform the rrect into device space. 992 SkRRect devRRect; 993 if (rrect.transform(*fMatrix, &devRRect)) { 994 SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 995 if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get(), 996 SkPaint::kFill_Style)) { 997 return; // filterRRect() called the blitter, so we're done 998 } 999 } 1000 } 1001 1002DRAW_PATH: 1003 // Now fall back to the default case of using a path. 1004 SkPath path; 1005 path.addRRect(rrect); 1006 this->drawPath(path, paint, nullptr, true); 1007} 1008 1009SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) { 1010 if (!matrix.hasPerspective()) { 1011 SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); 1012 SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); 1013 if (SkScalarsAreFinite(sx, sy)) { 1014 return SkTMax(sx, sy); 1015 } 1016 } 1017 return 1; 1018} 1019 1020void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1021 const SkMatrix* prePathMatrix, bool pathIsMutable, 1022 bool drawCoverage, SkBlitter* customBlitter) const { 1023 SkDEBUGCODE(this->validate();) 1024 1025 // nothing to draw 1026 if (fRC->isEmpty()) { 1027 return; 1028 } 1029 1030 SkPath* pathPtr = (SkPath*)&origSrcPath; 1031 bool doFill = true; 1032 SkPath tmpPath; 1033 SkMatrix tmpMatrix; 1034 const SkMatrix* matrix = fMatrix; 1035 tmpPath.setIsVolatile(true); 1036 1037 if (prePathMatrix) { 1038 if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 1039 origPaint.getRasterizer()) { 1040 SkPath* result = pathPtr; 1041 1042 if (!pathIsMutable) { 1043 result = &tmpPath; 1044 pathIsMutable = true; 1045 } 1046 pathPtr->transform(*prePathMatrix, result); 1047 pathPtr = result; 1048 } else { 1049 tmpMatrix.setConcat(*matrix, *prePathMatrix); 1050 matrix = &tmpMatrix; 1051 } 1052 } 1053 // at this point we're done with prePathMatrix 1054 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1055 1056 SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1057 1058 { 1059 SkScalar coverage; 1060 if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1061 if (SK_Scalar1 == coverage) { 1062 paint.writable()->setStrokeWidth(0); 1063 } else if (SkXfermode::SupportsCoverageAsAlpha(origPaint.getXfermode())) { 1064 U8CPU newAlpha; 1065#if 0 1066 newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1067 origPaint.getAlpha())); 1068#else 1069 // this is the old technique, which we preserve for now so 1070 // we don't change previous results (testing) 1071 // the new way seems fine, its just (a tiny bit) different 1072 int scale = (int)SkScalarMul(coverage, 256); 1073 newAlpha = origPaint.getAlpha() * scale >> 8; 1074#endif 1075 SkPaint* writablePaint = paint.writable(); 1076 writablePaint->setStrokeWidth(0); 1077 writablePaint->setAlpha(newAlpha); 1078 } 1079 } 1080 } 1081 1082 if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 1083 SkRect cullRect; 1084 const SkRect* cullRectPtr = nullptr; 1085 if (this->computeConservativeLocalClipBounds(&cullRect)) { 1086 cullRectPtr = &cullRect; 1087 } 1088 doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr, 1089 ComputeResScaleForStroking(*fMatrix)); 1090 pathPtr = &tmpPath; 1091 } 1092 1093 if (paint->getRasterizer()) { 1094 SkMask mask; 1095 if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1096 &fRC->getBounds(), paint->getMaskFilter(), &mask, 1097 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1098 this->drawDevMask(mask, *paint); 1099 SkMask::FreeImage(mask.fImage); 1100 } 1101 return; 1102 } 1103 1104 // avoid possibly allocating a new path in transform if we can 1105 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1106 1107 // transform the path into device space 1108 pathPtr->transform(*matrix, devPathPtr); 1109 1110 SkBlitter* blitter = nullptr; 1111 SkAutoBlitterChoose blitterStorage; 1112 if (nullptr == customBlitter) { 1113 blitterStorage.choose(fDst, *fMatrix, *paint, drawCoverage); 1114 blitter = blitterStorage.get(); 1115 } else { 1116 blitter = customBlitter; 1117 } 1118 1119 if (paint->getMaskFilter()) { 1120 SkPaint::Style style = doFill ? SkPaint::kFill_Style : 1121 SkPaint::kStroke_Style; 1122 if (paint->getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fRC, blitter, style)) { 1123 return; // filterPath() called the blitter, so we're done 1124 } 1125 } 1126 1127 void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 1128 if (doFill) { 1129 if (paint->isAntiAlias()) { 1130 proc = SkScan::AntiFillPath; 1131 } else { 1132 proc = SkScan::FillPath; 1133 } 1134 } else { // hairline 1135 if (paint->isAntiAlias()) { 1136 switch (paint->getStrokeCap()) { 1137 case SkPaint::kButt_Cap: 1138 proc = SkScan::AntiHairPath; 1139 break; 1140 case SkPaint::kSquare_Cap: 1141 proc = SkScan::AntiHairSquarePath; 1142 break; 1143 case SkPaint::kRound_Cap: 1144 proc = SkScan::AntiHairRoundPath; 1145 break; 1146 default: 1147 proc SK_INIT_TO_AVOID_WARNING; 1148 SkDEBUGFAIL("unknown paint cap type"); 1149 } 1150 } else { 1151 switch (paint->getStrokeCap()) { 1152 case SkPaint::kButt_Cap: 1153 proc = SkScan::HairPath; 1154 break; 1155 case SkPaint::kSquare_Cap: 1156 proc = SkScan::HairSquarePath; 1157 break; 1158 case SkPaint::kRound_Cap: 1159 proc = SkScan::HairRoundPath; 1160 break; 1161 default: 1162 proc SK_INIT_TO_AVOID_WARNING; 1163 SkDEBUGFAIL("unknown paint cap type"); 1164 } 1165 } 1166 } 1167 proc(*devPathPtr, *fRC, blitter); 1168} 1169 1170void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, 1171 const SkPaint& paint) const { 1172 SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); 1173 1174 if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { 1175 int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); 1176 int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); 1177 1178 SkAutoPixmapUnlock result; 1179 if (!bitmap.requestLock(&result)) { 1180 return; 1181 } 1182 const SkPixmap& pmap = result.pixmap(); 1183 SkMask mask; 1184 mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height()); 1185 mask.fFormat = SkMask::kA8_Format; 1186 mask.fRowBytes = SkToU32(pmap.rowBytes()); 1187 // fImage is typed as writable, but in this case it is used read-only 1188 mask.fImage = (uint8_t*)pmap.addr8(0, 0); 1189 1190 this->drawDevMask(mask, paint); 1191 } else { // need to xform the bitmap first 1192 SkRect r; 1193 SkMask mask; 1194 1195 r.set(0, 0, 1196 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1197 fMatrix->mapRect(&r); 1198 r.round(&mask.fBounds); 1199 1200 // set the mask's bounds to the transformed bitmap-bounds, 1201 // clipped to the actual device 1202 { 1203 SkIRect devBounds; 1204 devBounds.set(0, 0, fDst.width(), fDst.height()); 1205 // need intersect(l, t, r, b) on irect 1206 if (!mask.fBounds.intersect(devBounds)) { 1207 return; 1208 } 1209 } 1210 1211 mask.fFormat = SkMask::kA8_Format; 1212 mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1213 size_t size = mask.computeImageSize(); 1214 if (0 == size) { 1215 // the mask is too big to allocated, draw nothing 1216 return; 1217 } 1218 1219 // allocate (and clear) our temp buffer to hold the transformed bitmap 1220 SkAutoTMalloc<uint8_t> storage(size); 1221 mask.fImage = storage.get(); 1222 memset(mask.fImage, 0, size); 1223 1224 // now draw our bitmap(src) into mask(dst), transformed by the matrix 1225 { 1226 SkBitmap device; 1227 device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()), 1228 mask.fImage, mask.fRowBytes); 1229 1230 SkCanvas c(device); 1231 // need the unclipped top/left for the translate 1232 c.translate(-SkIntToScalar(mask.fBounds.fLeft), 1233 -SkIntToScalar(mask.fBounds.fTop)); 1234 c.concat(*fMatrix); 1235 1236 // We can't call drawBitmap, or we'll infinitely recurse. Instead 1237 // we manually build a shader and draw that into our new mask 1238 SkPaint tmpPaint; 1239 tmpPaint.setFlags(paint.getFlags()); 1240 SkAutoBitmapShaderInstall install(bitmap, tmpPaint); 1241 SkRect rr; 1242 rr.set(0, 0, SkIntToScalar(bitmap.width()), 1243 SkIntToScalar(bitmap.height())); 1244 c.drawRect(rr, install.paintWithShader()); 1245 } 1246 this->drawDevMask(mask, paint); 1247 } 1248} 1249 1250static bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 1251 const SkRect& srcR) { 1252 SkRect dstR; 1253 m.mapRect(&dstR, srcR); 1254 return c.quickReject(dstR.roundOut()); 1255} 1256 1257static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 1258 int width, int height) { 1259 SkRect r; 1260 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 1261 return clipped_out(matrix, clip, r); 1262} 1263 1264static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) { 1265 return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height()); 1266} 1267 1268void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 1269 const SkRect* dstBounds, const SkPaint& origPaint) const { 1270 SkDEBUGCODE(this->validate();) 1271 1272 // nothing to draw 1273 if (fRC->isEmpty() || 1274 bitmap.width() == 0 || bitmap.height() == 0 || 1275 bitmap.colorType() == kUnknown_SkColorType) { 1276 return; 1277 } 1278 1279 SkPaint paint(origPaint); 1280 paint.setStyle(SkPaint::kFill_Style); 1281 1282 SkMatrix matrix; 1283 matrix.setConcat(*fMatrix, prematrix); 1284 1285 if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 1286 return; 1287 } 1288 1289 if (bitmap.colorType() != kAlpha_8_SkColorType 1290 && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) { 1291 // 1292 // It is safe to call lock pixels now, since we know the matrix is 1293 // (more or less) identity. 1294 // 1295 SkAutoPixmapUnlock unlocker; 1296 if (!bitmap.requestLock(&unlocker)) { 1297 return; 1298 } 1299 const SkPixmap& pmap = unlocker.pixmap(); 1300 int ix = SkScalarRoundToInt(matrix.getTranslateX()); 1301 int iy = SkScalarRoundToInt(matrix.getTranslateY()); 1302 if (clipHandlesSprite(*fRC, ix, iy, pmap)) { 1303 SkTBlitterAllocator allocator; 1304 // blitter will be owned by the allocator. 1305 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, ix, iy, &allocator); 1306 if (blitter) { 1307 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()), 1308 *fRC, blitter); 1309 return; 1310 } 1311 // if !blitter, then we fall-through to the slower case 1312 } 1313 } 1314 1315 // now make a temp draw on the stack, and use it 1316 // 1317 SkDraw draw(*this); 1318 draw.fMatrix = &matrix; 1319 1320 if (bitmap.colorType() == kAlpha_8_SkColorType) { 1321 draw.drawBitmapAsMask(bitmap, paint); 1322 } else { 1323 SkAutoBitmapShaderInstall install(bitmap, paint); 1324 const SkPaint& paintWithShader = install.paintWithShader(); 1325 const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 1326 if (dstBounds) { 1327 this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds); 1328 } else { 1329 draw.drawRect(srcBounds, paintWithShader); 1330 } 1331 } 1332} 1333 1334void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const { 1335 SkDEBUGCODE(this->validate();) 1336 1337 // nothing to draw 1338 if (fRC->isEmpty() || 1339 bitmap.width() == 0 || bitmap.height() == 0 || 1340 bitmap.colorType() == kUnknown_SkColorType) { 1341 return; 1342 } 1343 1344 const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 1345 1346 if (fRC->quickReject(bounds)) { 1347 return; // nothing to draw 1348 } 1349 1350 SkPaint paint(origPaint); 1351 paint.setStyle(SkPaint::kFill_Style); 1352 1353 SkAutoPixmapUnlock unlocker; 1354 if (!bitmap.requestLock(&unlocker)) { 1355 return; 1356 } 1357 const SkPixmap& pmap = unlocker.pixmap(); 1358 1359 if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) { 1360 SkTBlitterAllocator allocator; 1361 // blitter will be owned by the allocator. 1362 SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator); 1363 if (blitter) { 1364 SkScan::FillIRect(bounds, *fRC, blitter); 1365 return; 1366 } 1367 } 1368 1369 SkMatrix matrix; 1370 SkRect r; 1371 1372 // get a scalar version of our rect 1373 r.set(bounds); 1374 1375 // create shader with offset 1376 matrix.setTranslate(r.fLeft, r.fTop); 1377 SkAutoBitmapShaderInstall install(bitmap, paint, &matrix); 1378 const SkPaint& shaderPaint = install.paintWithShader(); 1379 1380 SkDraw draw(*this); 1381 matrix.reset(); 1382 draw.fMatrix = &matrix; 1383 // call ourself with a rect 1384 // is this OK if paint has a rasterizer? 1385 draw.drawRect(r, shaderPaint); 1386} 1387 1388/////////////////////////////////////////////////////////////////////////////// 1389 1390#include "SkScalerContext.h" 1391#include "SkGlyphCache.h" 1392#include "SkTextToPathIter.h" 1393#include "SkUtils.h" 1394 1395bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 1396 // hairline glyphs are fast enough so we don't need to cache them 1397 if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { 1398 return true; 1399 } 1400 1401 // we don't cache perspective 1402 if (ctm.hasPerspective()) { 1403 return true; 1404 } 1405 1406 SkMatrix textM; 1407 return SkPaint::TooBigToUseCache(ctm, *paint.setTextMatrix(&textM)); 1408} 1409 1410void SkDraw::drawText_asPaths(const char text[], size_t byteLength, 1411 SkScalar x, SkScalar y, 1412 const SkPaint& paint) const { 1413 SkDEBUGCODE(this->validate();) 1414 1415 SkTextToPathIter iter(text, byteLength, paint, true); 1416 1417 SkMatrix matrix; 1418 matrix.setScale(iter.getPathScale(), iter.getPathScale()); 1419 matrix.postTranslate(x, y); 1420 1421 const SkPath* iterPath; 1422 SkScalar xpos, prevXPos = 0; 1423 1424 while (iter.next(&iterPath, &xpos)) { 1425 matrix.postTranslate(xpos - prevXPos, 0); 1426 if (iterPath) { 1427 const SkPaint& pnt = iter.getPaint(); 1428 if (fDevice) { 1429 fDevice->drawPath(*this, *iterPath, pnt, &matrix, false); 1430 } else { 1431 this->drawPath(*iterPath, pnt, &matrix, false); 1432 } 1433 } 1434 prevXPos = xpos; 1435 } 1436} 1437 1438// disable warning : local variable used without having been initialized 1439#if defined _WIN32 1440#pragma warning ( push ) 1441#pragma warning ( disable : 4701 ) 1442#endif 1443 1444//////////////////////////////////////////////////////////////////////////////////////////////////// 1445 1446class DrawOneGlyph { 1447public: 1448 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) 1449 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) 1450 , fGlyphCache(cache) 1451 , fBlitter(blitter) 1452 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) 1453 , fDraw(draw) 1454 , fPaint(paint) 1455 , fClipBounds(PickClipBounds(draw)) { } 1456 1457 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1458 position += rounding; 1459 // Prevent glyphs from being drawn outside of or straddling the edge of device space. 1460 if (position.fX > INT_MAX - (INT16_MAX + UINT16_MAX) || 1461 position.fX < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || 1462 position.fY > INT_MAX - (INT16_MAX + UINT16_MAX) || 1463 position.fY < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) { 1464 return; 1465 } 1466 1467 int left = SkScalarFloorToInt(position.fX); 1468 int top = SkScalarFloorToInt(position.fY); 1469 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1470 1471 left += glyph.fLeft; 1472 top += glyph.fTop; 1473 1474 int right = left + glyph.fWidth; 1475 int bottom = top + glyph.fHeight; 1476 1477 SkMask mask; 1478 mask.fBounds.set(left, top, right, bottom); 1479 1480 if (fUseRegionToDraw) { 1481 SkRegion::Cliperator clipper(*fClip, mask.fBounds); 1482 1483 if (!clipper.done() && this->getImageData(glyph, &mask)) { 1484 const SkIRect& cr = clipper.rect(); 1485 do { 1486 this->blitMask(mask, cr); 1487 clipper.next(); 1488 } while (!clipper.done()); 1489 } 1490 } else { 1491 SkIRect storage; 1492 SkIRect* bounds = &mask.fBounds; 1493 1494 // this extra test is worth it, assuming that most of the time it succeeds 1495 // since we can avoid writing to storage 1496 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { 1497 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) 1498 return; 1499 bounds = &storage; 1500 } 1501 1502 if (this->getImageData(glyph, &mask)) { 1503 this->blitMask(mask, *bounds); 1504 } 1505 } 1506 } 1507 1508private: 1509 static bool UsingRegionToDraw(const SkRasterClip* rClip) { 1510 return rClip->isBW() && !rClip->isRect(); 1511 } 1512 1513 static SkIRect PickClipBounds(const SkDraw& draw) { 1514 const SkRasterClip& rasterClip = *draw.fRC; 1515 1516 if (rasterClip.isBW()) { 1517 return rasterClip.bwRgn().getBounds(); 1518 } else { 1519 return rasterClip.aaRgn().getBounds(); 1520 } 1521 } 1522 1523 bool getImageData(const SkGlyph& glyph, SkMask* mask) { 1524 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); 1525 if (nullptr == bits) { 1526 return false; // can't rasterize glyph 1527 } 1528 mask->fImage = bits; 1529 mask->fRowBytes = glyph.rowBytes(); 1530 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1531 return true; 1532 } 1533 1534 void blitMask(const SkMask& mask, const SkIRect& clip) const { 1535 if (SkMask::kARGB32_Format == mask.fFormat) { 1536 SkBitmap bm; 1537 bm.installPixels( 1538 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), 1539 (SkPMColor*)mask.fImage, mask.fRowBytes); 1540 1541 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); 1542 } else { 1543 fBlitter->blitMask(mask, clip); 1544 } 1545 } 1546 1547 const bool fUseRegionToDraw; 1548 SkGlyphCache * const fGlyphCache; 1549 SkBlitter * const fBlitter; 1550 const SkRegion* const fClip; 1551 const SkDraw& fDraw; 1552 const SkPaint& fPaint; 1553 const SkIRect fClipBounds; 1554}; 1555 1556//////////////////////////////////////////////////////////////////////////////////////////////////// 1557 1558SkPaint::FakeGamma SkDraw::fakeGamma() const { 1559 return fDevice->imageInfo().isLinear() ? SkPaint::FakeGamma::On : SkPaint::FakeGamma::Off; 1560} 1561 1562void SkDraw::drawText(const char text[], size_t byteLength, 1563 SkScalar x, SkScalar y, const SkPaint& paint) const { 1564 SkASSERT(byteLength == 0 || text != nullptr); 1565 1566 SkDEBUGCODE(this->validate();) 1567 1568 // nothing to draw 1569 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1570 return; 1571 } 1572 1573 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1574 // will fill if its frame-width is 0. 1575 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1576 this->drawText_asPaths(text, byteLength, x, y, paint); 1577 return; 1578 } 1579 1580 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix); 1581 1582 // The Blitter Choose needs to be live while using the blitter below. 1583 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1584 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1585 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1586 1587 SkFindAndPlaceGlyph::ProcessText( 1588 paint.getTextEncoding(), text, byteLength, 1589 {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph); 1590} 1591 1592////////////////////////////////////////////////////////////////////////////// 1593 1594void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, 1595 const SkScalar pos[], int scalarsPerPosition, 1596 const SkPoint& offset, const SkPaint& origPaint) const { 1597 // setup our std paint, in hopes of getting hits in the cache 1598 SkPaint paint(origPaint); 1599 SkScalar matrixScale = paint.setupForAsPaths(); 1600 1601 SkMatrix matrix; 1602 matrix.setScale(matrixScale, matrixScale); 1603 1604 // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. 1605 paint.setStyle(SkPaint::kFill_Style); 1606 paint.setPathEffect(nullptr); 1607 1608 SkPaint::GlyphCacheProc glyphCacheProc = paint.getGlyphCacheProc(true); 1609 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), nullptr); 1610 1611 const char* stop = text + byteLength; 1612 SkTextAlignProc alignProc(paint.getTextAlign()); 1613 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); 1614 1615 // Now restore the original settings, so we "draw" with whatever style/stroking. 1616 paint.setStyle(origPaint.getStyle()); 1617 paint.setPathEffect(sk_ref_sp(origPaint.getPathEffect())); 1618 1619 while (text < stop) { 1620 const SkGlyph& glyph = glyphCacheProc(cache.get(), &text); 1621 if (glyph.fWidth) { 1622 const SkPath* path = cache->findPath(glyph); 1623 if (path) { 1624 SkPoint tmsLoc; 1625 tmsProc(pos, &tmsLoc); 1626 SkPoint loc; 1627 alignProc(tmsLoc, glyph, &loc); 1628 1629 matrix[SkMatrix::kMTransX] = loc.fX; 1630 matrix[SkMatrix::kMTransY] = loc.fY; 1631 if (fDevice) { 1632 fDevice->drawPath(*this, *path, paint, &matrix, false); 1633 } else { 1634 this->drawPath(*path, paint, &matrix, false); 1635 } 1636 } 1637 } 1638 pos += scalarsPerPosition; 1639 } 1640} 1641 1642void SkDraw::drawPosText(const char text[], size_t byteLength, 1643 const SkScalar pos[], int scalarsPerPosition, 1644 const SkPoint& offset, const SkPaint& paint) const { 1645 SkASSERT(byteLength == 0 || text != nullptr); 1646 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1647 1648 SkDEBUGCODE(this->validate();) 1649 1650 // nothing to draw 1651 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1652 return; 1653 } 1654 1655 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1656 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint); 1657 return; 1658 } 1659 1660 SkAutoGlyphCache cache(paint, &fDevice->surfaceProps(), this->fakeGamma(), fMatrix); 1661 1662 // The Blitter Choose needs to be live while using the blitter below. 1663 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1664 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1665 DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1666 SkPaint::Align textAlignment = paint.getTextAlign(); 1667 1668 SkFindAndPlaceGlyph::ProcessPosText( 1669 paint.getTextEncoding(), text, byteLength, 1670 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph); 1671} 1672 1673#if defined _WIN32 1674#pragma warning ( pop ) 1675#endif 1676 1677/////////////////////////////////////////////////////////////////////////////// 1678 1679static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { 1680 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; 1681} 1682 1683static bool texture_to_matrix(const VertState& state, const SkPoint verts[], 1684 const SkPoint texs[], SkMatrix* matrix) { 1685 SkPoint src[3], dst[3]; 1686 1687 src[0] = texs[state.f0]; 1688 src[1] = texs[state.f1]; 1689 src[2] = texs[state.f2]; 1690 dst[0] = verts[state.f0]; 1691 dst[1] = verts[state.f1]; 1692 dst[2] = verts[state.f2]; 1693 return matrix->setPolyToPoly(src, dst, 3); 1694} 1695 1696class SkTriColorShader : public SkShader { 1697public: 1698 SkTriColorShader(); 1699 1700 class TriColorShaderContext : public SkShader::Context { 1701 public: 1702 TriColorShaderContext(const SkTriColorShader& shader, const ContextRec&); 1703 virtual ~TriColorShaderContext(); 1704 void shadeSpan(int x, int y, SkPMColor dstC[], int count) override; 1705 1706 private: 1707 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int); 1708 1709 SkMatrix fDstToUnit; 1710 SkPMColor fColors[3]; 1711 bool fSetup; 1712 1713 typedef SkShader::Context INHERITED; 1714 }; 1715 1716 struct TriColorShaderData { 1717 const SkPoint* pts; 1718 const SkColor* colors; 1719 const VertState *state; 1720 }; 1721 1722 SK_TO_STRING_OVERRIDE() 1723 1724 // For serialization. This will never be called. 1725 Factory getFactory() const override { sk_throw(); return nullptr; } 1726 1727 // Supply setup data to context from drawing setup 1728 void bindSetupData(TriColorShaderData* setupData) { fSetupData = setupData; } 1729 1730 // Take the setup data from context when needed. 1731 TriColorShaderData* takeSetupData() { 1732 TriColorShaderData *data = fSetupData; 1733 fSetupData = NULL; 1734 return data; 1735 } 1736 1737protected: 1738 size_t onContextSize(const ContextRec&) const override; 1739 Context* onCreateContext(const ContextRec& rec, void* storage) const override { 1740 return new (storage) TriColorShaderContext(*this, rec); 1741 } 1742 1743private: 1744 TriColorShaderData *fSetupData; 1745 1746 typedef SkShader INHERITED; 1747}; 1748 1749bool SkTriColorShader::TriColorShaderContext::setup(const SkPoint pts[], const SkColor colors[], 1750 int index0, int index1, int index2) { 1751 1752 fColors[0] = SkPreMultiplyColor(colors[index0]); 1753 fColors[1] = SkPreMultiplyColor(colors[index1]); 1754 fColors[2] = SkPreMultiplyColor(colors[index2]); 1755 1756 SkMatrix m, im; 1757 m.reset(); 1758 m.set(0, pts[index1].fX - pts[index0].fX); 1759 m.set(1, pts[index2].fX - pts[index0].fX); 1760 m.set(2, pts[index0].fX); 1761 m.set(3, pts[index1].fY - pts[index0].fY); 1762 m.set(4, pts[index2].fY - pts[index0].fY); 1763 m.set(5, pts[index0].fY); 1764 if (!m.invert(&im)) { 1765 return false; 1766 } 1767 // We can't call getTotalInverse(), because we explicitly don't want to look at the localmatrix 1768 // as our interators are intrinsically tied to the vertices, and nothing else. 1769 SkMatrix ctmInv; 1770 if (!this->getCTM().invert(&ctmInv)) { 1771 return false; 1772 } 1773 // TODO replace INV(m) * INV(ctm) with INV(ctm * m) 1774 fDstToUnit.setConcat(im, ctmInv); 1775 return true; 1776} 1777 1778#include "SkColorPriv.h" 1779#include "SkComposeShader.h" 1780 1781static int ScalarTo256(SkScalar v) { 1782 return static_cast<int>(SkScalarPin(v, 0, 1) * 256 + 0.5); 1783} 1784 1785SkTriColorShader::SkTriColorShader() 1786 : INHERITED(NULL) 1787 , fSetupData(NULL) {} 1788 1789SkTriColorShader::TriColorShaderContext::TriColorShaderContext(const SkTriColorShader& shader, 1790 const ContextRec& rec) 1791 : INHERITED(shader, rec) 1792 , fSetup(false) {} 1793 1794SkTriColorShader::TriColorShaderContext::~TriColorShaderContext() {} 1795 1796size_t SkTriColorShader::onContextSize(const ContextRec&) const { 1797 return sizeof(TriColorShaderContext); 1798} 1799 1800void SkTriColorShader::TriColorShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { 1801 SkTriColorShader* parent = static_cast<SkTriColorShader*>(const_cast<SkShader*>(&fShader)); 1802 TriColorShaderData* set = parent->takeSetupData(); 1803 if (set) { 1804 fSetup = setup(set->pts, set->colors, set->state->f0, set->state->f1, set->state->f2); 1805 } 1806 1807 if (!fSetup) { 1808 // Invalid matrices. Not checked before so no need to assert. 1809 return; 1810 } 1811 1812 const int alphaScale = Sk255To256(this->getPaintAlpha()); 1813 1814 SkPoint src; 1815 1816 for (int i = 0; i < count; i++) { 1817 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src); 1818 x += 1; 1819 1820 int scale1 = ScalarTo256(src.fX); 1821 int scale2 = ScalarTo256(src.fY); 1822 int scale0 = 256 - scale1 - scale2; 1823 if (scale0 < 0) { 1824 if (scale1 > scale2) { 1825 scale2 = 256 - scale1; 1826 } else { 1827 scale1 = 256 - scale2; 1828 } 1829 scale0 = 0; 1830 } 1831 1832 if (256 != alphaScale) { 1833 scale0 = SkAlphaMul(scale0, alphaScale); 1834 scale1 = SkAlphaMul(scale1, alphaScale); 1835 scale2 = SkAlphaMul(scale2, alphaScale); 1836 } 1837 1838 dstC[i] = SkAlphaMulQ(fColors[0], scale0) + 1839 SkAlphaMulQ(fColors[1], scale1) + 1840 SkAlphaMulQ(fColors[2], scale2); 1841 } 1842} 1843 1844#ifndef SK_IGNORE_TO_STRING 1845void SkTriColorShader::toString(SkString* str) const { 1846 str->append("SkTriColorShader: ("); 1847 1848 this->INHERITED::toString(str); 1849 1850 str->append(")"); 1851} 1852#endif 1853 1854void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count, 1855 const SkPoint vertices[], const SkPoint textures[], 1856 const SkColor colors[], SkXfermode* xmode, 1857 const uint16_t indices[], int indexCount, 1858 const SkPaint& paint) const { 1859 SkASSERT(0 == count || vertices); 1860 1861 // abort early if there is nothing to draw 1862 if (count < 3 || (indices && indexCount < 3) || fRC->isEmpty()) { 1863 return; 1864 } 1865 1866 // transform out vertices into device coordinates 1867 SkAutoSTMalloc<16, SkPoint> storage(count); 1868 SkPoint* devVerts = storage.get(); 1869 fMatrix->mapPoints(devVerts, vertices, count); 1870 1871 /* 1872 We can draw the vertices in 1 of 4 ways: 1873 1874 - solid color (no shader/texture[], no colors[]) 1875 - just colors (no shader/texture[], has colors[]) 1876 - just texture (has shader/texture[], no colors[]) 1877 - colors * texture (has shader/texture[], has colors[]) 1878 1879 Thus for texture drawing, we need both texture[] and a shader. 1880 */ 1881 1882 auto triShader = sk_make_sp<SkTriColorShader>(); 1883 SkPaint p(paint); 1884 1885 SkShader* shader = p.getShader(); 1886 if (nullptr == shader) { 1887 // if we have no shader, we ignore the texture coordinates 1888 textures = nullptr; 1889 } else if (nullptr == textures) { 1890 // if we don't have texture coordinates, ignore the shader 1891 p.setShader(nullptr); 1892 shader = nullptr; 1893 } 1894 1895 // setup the custom shader (if needed) 1896 if (colors) { 1897 if (nullptr == textures) { 1898 // just colors (no texture) 1899 p.setShader(triShader); 1900 shader = p.getShader(); 1901 } else { 1902 // colors * texture 1903 SkASSERT(shader); 1904 sk_sp<SkXfermode> xfer = xmode ? sk_ref_sp(xmode) 1905 : SkXfermode::Make(SkXfermode::kModulate_Mode); 1906 p.setShader(SkShader::MakeComposeShader(triShader, sk_ref_sp(shader), std::move(xfer))); 1907 } 1908 } 1909 1910 SkAutoBlitterChoose blitter(fDst, *fMatrix, p); 1911 // Abort early if we failed to create a shader context. 1912 if (blitter->isNullBlitter()) { 1913 return; 1914 } 1915 1916 // setup our state and function pointer for iterating triangles 1917 VertState state(count, indices, indexCount); 1918 VertState::Proc vertProc = state.chooseProc(vmode); 1919 1920 if (textures || colors) { 1921 SkTriColorShader::TriColorShaderData verticesSetup = { vertices, colors, &state }; 1922 1923 while (vertProc(&state)) { 1924 if (textures) { 1925 SkMatrix tempM; 1926 if (texture_to_matrix(state, vertices, textures, &tempM)) { 1927 SkShader::ContextRec rec(p, *fMatrix, &tempM, 1928 SkBlitter::PreferredShaderDest(fDst.info())); 1929 if (!blitter->resetShaderContext(rec)) { 1930 continue; 1931 } 1932 } 1933 } 1934 if (colors) { 1935 triShader->bindSetupData(&verticesSetup); 1936 } 1937 1938 SkPoint tmp[] = { 1939 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2] 1940 }; 1941 SkScan::FillTriangle(tmp, *fRC, blitter.get()); 1942 triShader->bindSetupData(NULL); 1943 } 1944 } else { 1945 // no colors[] and no texture, stroke hairlines with paint's color. 1946 SkScan::HairRCProc hairProc = ChooseHairProc(paint.isAntiAlias()); 1947 const SkRasterClip& clip = *fRC; 1948 while (vertProc(&state)) { 1949 SkPoint array[] = { 1950 devVerts[state.f0], devVerts[state.f1], devVerts[state.f2], devVerts[state.f0] 1951 }; 1952 hairProc(array, 4, clip, blitter.get()); 1953 } 1954 } 1955} 1956 1957/////////////////////////////////////////////////////////////////////////////// 1958/////////////////////////////////////////////////////////////////////////////// 1959 1960#ifdef SK_DEBUG 1961 1962void SkDraw::validate() const { 1963 SkASSERT(fMatrix != nullptr); 1964 SkASSERT(fClip != nullptr); 1965 SkASSERT(fRC != nullptr); 1966 1967 const SkIRect& cr = fRC->getBounds(); 1968 SkIRect br; 1969 1970 br.set(0, 0, fDst.width(), fDst.height()); 1971 SkASSERT(cr.isEmpty() || br.contains(cr)); 1972} 1973 1974#endif 1975 1976//////////////////////////////////////////////////////////////////////////////////////////////// 1977 1978#include "SkPath.h" 1979#include "SkDraw.h" 1980#include "SkRegion.h" 1981#include "SkBlitter.h" 1982 1983static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 1984 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 1985 SkIRect* bounds) { 1986 if (devPath.isEmpty()) { 1987 return false; 1988 } 1989 1990 // init our bounds from the path 1991 *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut(); 1992 1993 SkIPoint margin = SkIPoint::Make(0, 0); 1994 if (filter) { 1995 SkASSERT(filterMatrix); 1996 1997 SkMask srcM, dstM; 1998 1999 srcM.fBounds = *bounds; 2000 srcM.fFormat = SkMask::kA8_Format; 2001 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 2002 return false; 2003 } 2004 } 2005 2006 // (possibly) trim the bounds to reflect the clip 2007 // (plus whatever slop the filter needs) 2008 if (clipBounds) { 2009 // Ugh. Guard against gigantic margins from wacky filters. Without this 2010 // check we can request arbitrary amounts of slop beyond our visible 2011 // clip, and bring down the renderer (at least on finite RAM machines 2012 // like handsets, etc.). Need to balance this invented value between 2013 // quality of large filters like blurs, and the corresponding memory 2014 // requests. 2015 static const int MAX_MARGIN = 128; 2016 if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN), 2017 SkMin32(margin.fY, MAX_MARGIN)))) { 2018 return false; 2019 } 2020 } 2021 2022 return true; 2023} 2024 2025static void draw_into_mask(const SkMask& mask, const SkPath& devPath, SkPaint::Style style) { 2026 SkDraw draw; 2027 if (!draw.fDst.reset(mask)) { 2028 return; 2029 } 2030 2031 SkRasterClip clip; 2032 SkMatrix matrix; 2033 SkPaint paint; 2034 2035 clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 2036 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 2037 -SkIntToScalar(mask.fBounds.fTop)); 2038 2039 draw.fRC = &clip; 2040 draw.fClip = &clip.bwRgn(); 2041 draw.fMatrix = &matrix; 2042 paint.setAntiAlias(true); 2043 paint.setStyle(style); 2044 draw.drawPath(devPath, paint); 2045} 2046 2047bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 2048 const SkMaskFilter* filter, const SkMatrix* filterMatrix, 2049 SkMask* mask, SkMask::CreateMode mode, 2050 SkPaint::Style style) { 2051 if (SkMask::kJustRenderImage_CreateMode != mode) { 2052 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 2053 return false; 2054 } 2055 2056 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 2057 mask->fFormat = SkMask::kA8_Format; 2058 mask->fRowBytes = mask->fBounds.width(); 2059 size_t size = mask->computeImageSize(); 2060 if (0 == size) { 2061 // we're too big to allocate the mask, abort 2062 return false; 2063 } 2064 mask->fImage = SkMask::AllocImage(size); 2065 memset(mask->fImage, 0, mask->computeImageSize()); 2066 } 2067 2068 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2069 draw_into_mask(*mask, devPath, style); 2070 } 2071 2072 return true; 2073} 2074