1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 8787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed#define __STDC_LIMIT_MACROS 983e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby 1083e939bcb79790f5ae3b28c398fbcf034675a6e5Herb Derby#include "SkArenaAlloc.h" 11787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed#include "SkAutoBlitterChoose.h" 12374772bd61951f01bf84fe17bf53d8867681c9aereed#include "SkBlendModePriv.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h" 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCanvas.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h" 16986480a71f4e860663ced7ad90a1fe346a164afbMike Reed#include "SkDevice.h" 171c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com#include "SkDeviceLooper.h" 18787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed#include "SkDraw.h" 19787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed#include "SkDrawProcs.h" 20e5911c9c5b859d60208f4b9ac4bf2a638f4bc35fherb#include "SkFindAndPlaceGlyph.h" 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h" 22f553e4e09cd2baf15fc041daab8a08bd46e352f0herb#include "SkMatrix.h" 23787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed#include "SkMatrixUtils.h" 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPaint.h" 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPathEffect.h" 26045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h" 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRasterizer.h" 28a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com#include "SkRRect.h" 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScan.h" 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkShader.h" 3176f9e938df0b5826fd4c80b854ceafaf385cfbe1robertphillips@google.com#include "SkString.h" 328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStroke.h" 33435657fd62960ceffb1c3c63f63e836373560bc5halcanary#include "SkStrokeRec.h" 34f553e4e09cd2baf15fc041daab8a08bd46e352f0herb#include "SkTemplates.h" 35cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen#include "SkTextMapStateProc.h" 3632e5d97ccf60f859db063ebd6e903c362e625767reed@google.com#include "SkTLazy.h" 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h" 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 394bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derbystatic SkPaint make_paint_with_image( 404bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby const SkPaint& origPaint, const SkBitmap& bitmap, SkMatrix* matrix = nullptr) { 414bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paint(origPaint); 424bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby paint.setShader(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode, 434bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkShader::kClamp_TileMode, matrix, 444bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby kNever_SkCopyPixelsMode)); 454bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby return paint; 464bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby} 478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 50f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comSkDraw::SkDraw() { 51f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com sk_bzero(this, sizeof(*this)); 52f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com} 53f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 544bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.combool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 554bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (fRC->isEmpty()) { 564bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return false; 574bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 584bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 594bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkMatrix inverse; 604bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (!fMatrix->invert(&inverse)) { 614bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return false; 624bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 634bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 644bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkIRect devBounds = fRC->getBounds(); 654bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com // outset to have slop for antialasing and hairlines 664bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com devBounds.outset(1, 1); 674bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com inverse.mapRect(localBounds, SkRect::Make(devBounds)); 684bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return true; 694bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com} 704bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 764516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com sk_bzero(pixels, bytes); 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 82a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2)); 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 86a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1)); 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(pixels, data, bytes); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9341e010cb901c0da9066c4df562030808c9ccd7f8reedstatic BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint, 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t* data) { 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // todo: we can apply colorfilter up front if no shader, so we wouldn't 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need to abort this fastpath 97555ea8e994cede6508a6d8fb6c16f99331b2ed37Mike Klein if (paint.getShader() || paint.getColorFilter() || dst.colorSpace()) { 9896fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 101374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode mode = paint.getBlendMode(); 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkColor color = paint.getColor(); 103a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // collaps modes based on color... 105374772bd61951f01bf84fe17bf53d8867681c9aereed if (SkBlendMode::kSrcOver == mode) { 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned alpha = SkColorGetA(color); 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (0 == alpha) { 108374772bd61951f01bf84fe17bf53d8867681c9aereed mode = SkBlendMode::kDst; 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (0xFF == alpha) { 110374772bd61951f01bf84fe17bf53d8867681c9aereed mode = SkBlendMode::kSrc; 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 113a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (mode) { 115374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kClear: 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D_Clear_BitmapXferProc\n"); 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D_Clear_BitmapXferProc; // ignore data 118374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kDst: 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D_Dst_BitmapXferProc\n"); 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D_Dst_BitmapXferProc; // ignore data 121374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kSrc: { 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* 123a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com should I worry about dithering for the lower depths? 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPMColor pmc = SkPreMultiplyColor(color); 12641e010cb901c0da9066c4df562030808c9ccd7f8reed switch (dst.colorType()) { 12728fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org case kN32_SkColorType: 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = pmc; 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D32_Src_BitmapXferProc\n"); 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D32_Src_BitmapXferProc; 133900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kRGB_565_SkColorType: 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = SkPixel32ToPixel16(pmc); 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D16_Src_BitmapXferProc\n"); 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D16_Src_BitmapXferProc; 139900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kAlpha_8_SkColorType: 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = SkGetPackedA32(pmc); 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return DA8_Src_BitmapXferProc; 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15396fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15641e010cb901c0da9066c4df562030808c9ccd7f8reedstatic void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc, 15741e010cb901c0da9066c4df562030808c9ccd7f8reed uint32_t procData) { 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int shiftPerPixel; 15941e010cb901c0da9066c4df562030808c9ccd7f8reed switch (dst.colorType()) { 16028fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org case kN32_SkColorType: 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 2; 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 163900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kRGB_565_SkColorType: 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 1; 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 166900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kAlpha_8_SkColorType: 1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 0; 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1700c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("Can't use xferproc on this config"); 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17441e010cb901c0da9066c4df562030808c9ccd7f8reed uint8_t* pixels = (uint8_t*)dst.writable_addr(); 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(pixels); 17641e010cb901c0da9066c4df562030808c9ccd7f8reed const size_t rowBytes = dst.rowBytes(); 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int widthBytes = rect.width() << shiftPerPixel; 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // skip down to the first scanline and X position 1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int scans = rect.height() - 1; scans >= 0; --scans) { 1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(pixels, widthBytes, procData); 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pixels += rowBytes; 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawPaint(const SkPaint& paint) const { 188f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 190045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect devRect; 19541e010cb901c0da9066c4df562030808c9ccd7f8reed devRect.set(0, 0, fDst.width(), fDst.height()); 196a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 197045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 198045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com /* If we don't have a shader (i.e. we're just a solid color) we may 199045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com be faster to operate directly on the device bitmap, rather than invoking 200045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com a blitter. Esp. true for xfermodes, which require a colorshader to be 201045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com present, which is just redundant work. Since we're drawing everywhere 202045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com in the clip, we don't have to worry about antialiasing. 203045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com */ 204045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com uint32_t procData = 0; // to avoid the warning 20541e010cb901c0da9066c4df562030808c9ccd7f8reed BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData); 206045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (proc) { 207045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (D_Dst_BitmapXferProc == proc) { // nothing to do 208045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 209045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 210a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 211045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkRegion::Iterator iter(fRC->bwRgn()); 212045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com while (!iter.done()) { 21341e010cb901c0da9066c4df562030808c9ccd7f8reed CallBitmapXferProc(fDst, iter.rect(), proc, procData); 214045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com iter.next(); 215045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 216045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 219045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 220045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com // normal case: use a blitter 22141e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 222045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillIRect(devRect, *fRC, blitter.get()); 2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct PtProcRec { 2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkCanvas::PointMode fMode; 2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPaint* fPaint; 2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkRegion* fClip; 231045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRasterClip* fRC; 232a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // computed values 2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed fRadius; 235a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter*); 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 240045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRasterClip*); 241045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com Proc chooseProc(SkBlitter** blitter); 242045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 243045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comprivate: 244045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper fWrapper; 2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(rec.fClip->isRect()); 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkIRect& r = rec.fClip->getBounds(); 251a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 2532d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 2542d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (r.contains(x, y)) { 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitH(x, y, 1); 2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPoint devPts[], int count, 2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* blitter) { 264045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkASSERT(rec.fRC->isRect()); 265045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkIRect& r = rec.fRC->getBounds(); 2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t value; 26741e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 26841e010cb901c0da9066c4df562030808c9ccd7f8reed SkASSERT(dst); 269c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 27041e010cb901c0da9066c4df562030808c9ccd7f8reed uint16_t* addr = dst->writable_addr16(0, 0); 27141e010cb901c0da9066c4df562030808c9ccd7f8reed size_t rb = dst->rowBytes(); 272c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 2742d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 2752d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (r.contains(x, y)) { 2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2822d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.comstatic void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 2832d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com const SkPoint devPts[], int count, 2842d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkBlitter* blitter) { 2852d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkASSERT(rec.fRC->isRect()); 2862d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com const SkIRect& r = rec.fRC->getBounds(); 2872d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com uint32_t value; 28841e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 28941e010cb901c0da9066c4df562030808c9ccd7f8reed SkASSERT(dst); 290c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 29141e010cb901c0da9066c4df562030808c9ccd7f8reed SkPMColor* addr = dst->writable_addr32(0, 0); 29241e010cb901c0da9066c4df562030808c9ccd7f8reed size_t rb = dst->rowBytes(); 293c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 2942d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com for (int i = 0; i < count; i++) { 2952d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 2962d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 2972d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (r.contains(x, y)) { 2982d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com ((SkPMColor*)((char*)addr + y * rb))[x] = value; 2992d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 3002d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 3012d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com} 3022d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com 3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 306e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 307e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (rec.fClip->contains(x, y)) { 3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitH(x, y, 1); 3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i += 2) { 3175dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter); 3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3235dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::HairLine(devPts, count, *rec.fRC, blitter); 3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// aa versions 3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i += 2) { 3315dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter); 3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3375dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter); 3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 3418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkFixed radius = rec.fRadius; 3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed x = SkScalarToFixed(devPts[i].fX); 3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed y = SkScalarToFixed(devPts[i].fY); 348c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXRect r; 3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = x - radius; 3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = y - radius; 3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = x + radius; 3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = y + radius; 354c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 355045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillXRect(r, *rec.fRC, blitter); 3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkFixed radius = rec.fRadius; 3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed x = SkScalarToFixed(devPts[i].fX); 3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed y = SkScalarToFixed(devPts[i].fY); 365a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXRect r; 3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = x - radius; 3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = y - radius; 3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = x + radius; 3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = y + radius; 371a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 372045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::AntiFillXRect(r, *rec.fRC, blitter); 3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 376b4f404ac4195e5b1f49e49c591bd69f98b246f9breed@android.com// If this guy returns true, then chooseProc() must return a valid proc 3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 378045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkMatrix* matrix, const SkRasterClip* rc) { 3793ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) { 3803ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang return false; 3813ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang } 3823ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang 3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getPathEffect()) { 3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar width = paint.getStrokeWidth(); 3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (0 == width) { 3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = mode; 3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPaint = &paint; 39096fcdcc219d2a0d3579719b84b28bede76efba64halcanary fClip = nullptr; 391045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fRC = rc; 3922d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com fRadius = SK_FixedHalf; 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 395b4f404ac4195e5b1f49e49c591bd69f98b246f9breed@android.com if (paint.getStrokeCap() != SkPaint::kRound_Cap && 3969f2251c73ed6f417dd1057d487bf523e04488440robertphillips matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) { 3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar sx = matrix->get(SkMatrix::kMScaleX); 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar sy = matrix->get(SkMatrix::kMScaleY); 3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkScalarNearlyZero(sx - sy)) { 4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (sx < 0) { 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sx = -sx; 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = mode; 4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPaint = &paint; 40696fcdcc219d2a0d3579719b84b28bede76efba64halcanary fClip = nullptr; 407045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fRC = rc; 408a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed fRadius = SkScalarToFixed(width * sx) >> 1; 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 415045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comPtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 41696fcdcc219d2a0d3579719b84b28bede76efba64halcanary Proc proc = nullptr; 417a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 418045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkBlitter* blitter = *blitterPtr; 419045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 420045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fClip = &fRC->bwRgn(); 421045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 422045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fWrapper.init(*fRC, blitter); 423045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fClip = &fWrapper.getRgn(); 424045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter = fWrapper.getBlitter(); 425045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com *blitterPtr = blitter; 426045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 427045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // for our arrays 4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(0 == SkCanvas::kPoints_PointMode); 4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(1 == SkCanvas::kLines_PointMode); 4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(2 == SkCanvas::kPolygon_PointMode); 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4342d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (fPaint->isAntiAlias()) { 4352d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (0 == fPaint->getStrokeWidth()) { 4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static const Proc gAAProcs[] = { 4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com }; 4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = gAAProcs[fMode]; 4402d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 4412d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkASSERT(SkCanvas::kPoints_PointMode == fMode); 4422d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com proc = aa_square_proc; 4432d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 4442d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } else { // BW 4452d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (fRadius <= SK_FixedHalf) { // small radii and hairline 4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t value; 44841e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* bm = blitter->justAnOpaqueColor(&value); 449900ecf2f1579d42c9d2959831787af0346320f86reed@google.com if (bm && kRGB_565_SkColorType == bm->colorType()) { 4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_pt_rect_16_hair_proc; 45128fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org } else if (bm && kN32_SkColorType == bm->colorType()) { 4522d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com proc = bw_pt_rect_32_hair_proc; 4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_pt_rect_hair_proc; 4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static Proc gBWProcs[] = { 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com }; 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = gBWProcs[fMode]; 4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_square_proc; 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return proc; 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// each of these costs 8-bytes of stack space, so don't make it too large 4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// must be even for lines/polygon to work 4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_DEV_PTS 32 4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 474f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com const SkPoint pts[], const SkPaint& paint, 47599330ba6227137866a0dbd63478d36f335203ebdMike Reed SkBaseDevice* device) const { 4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // if we're in lines mode, force count to be even 4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkCanvas::kLines_PointMode == mode) { 4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count &= ~(size_t)1; 4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if ((long)count <= 0) { 4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 484a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 48596fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(pts != nullptr); 486f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 487a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 489045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com PtProcRec rec; 49499330ba6227137866a0dbd63478d36f335203ebdMike Reed if (!device && rec.init(mode, paint, fMatrix, fRC)) { 49541e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint devPts[MAX_DEV_PTS]; 4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkMatrix* matrix = fMatrix; 4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* bltr = blitter.get(); 500045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com PtProcRec::Proc proc = rec.chooseProc(&bltr); 5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we have to back up subsequent passes if we're in polygon mode 5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 503a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 505a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org int n = SkToInt(count); 5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (n > MAX_DEV_PTS) { 5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n = MAX_DEV_PTS; 5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix->mapPoints(devPts, pts, n); 5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(rec, devPts, n, bltr); 5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts += n - backup; 512a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org SkASSERT(SkToInt(count) >= n); 5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count -= n; 5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (count > 0) { 5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count += backup; 5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (count != 0); 5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (mode) { 5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kPoints_PointMode: { 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // temporarily mark the paint as filling. 52240c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkPaint newPaint(paint); 52340c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com newPaint.setStyle(SkPaint::kFill_Style); 5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 52540c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkScalar width = newPaint.getStrokeWidth(); 5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar radius = SkScalarHalf(width); 527a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 52840c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath path; 5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix preMatrix; 5317ef849d45a4de02697697ea213bfae7c215a0c38mtklein 5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.addCircle(0, 0, radius); 5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i++) { 5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com preMatrix.setTranslate(pts[i].fX, pts[i].fY); 5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // pass true for the last point, since we can modify 5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // then path then 537b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth path.setIsVolatile((count-1) == i); 53899330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 539a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(path, newPaint, &preMatrix, (count-1) == i); 540f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 541a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed this->drawPath(path, newPaint, &preMatrix, (count-1) == i); 542f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 546a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i++) { 5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = pts[i].fX - radius; 5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = pts[i].fY - radius; 5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = r.fLeft + width; 5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = r.fTop + width; 55299330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 553a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawRect(r, newPaint); 554f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 55540c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com this->drawRect(r, newPaint); 556f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kLines_PointMode: 56249f085dddff10473b6ebf832a974288300224e60bsalomon if (2 == count && paint.getPathEffect()) { 563629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // most likely a dashed line - see if it is one of the ones 564629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // we can accelerate 565629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkStrokeRec rec(paint); 5666d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkPathEffect::PointData pointData; 567629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 568629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkPath path; 569629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com path.moveTo(pts[0]); 570629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com path.lineTo(pts[1]); 571629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 5724bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkRect cullRect = SkRect::Make(fRC->getBounds()); 5734024f32d99b63a599c544a49f526e53c25135159skia.committer@gmail.com 5744bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (paint.getPathEffect()->asPoints(&pointData, path, rec, 5754bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com *fMatrix, &cullRect)) { 5766d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // 'asPoints' managed to find some fast path 5776d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 578629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkPaint newP(paint); 57996fcdcc219d2a0d3579719b84b28bede76efba64halcanary newP.setPathEffect(nullptr); 580935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com newP.setStyle(SkPaint::kFill_Style); 581629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 5826d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (!pointData.fFirst.isEmpty()) { 58399330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 584a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(pointData.fFirst, newP); 5856d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 5866d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPath(pointData.fFirst, newP); 5876d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 588629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 5896d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 5906d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (!pointData.fLast.isEmpty()) { 59199330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 592a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(pointData.fLast, newP); 5936d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 5946d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPath(pointData.fLast, newP); 5956d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 5966d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 5976d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 5986d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (pointData.fSize.fX == pointData.fSize.fY) { 5996d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // The rest of the dashed line can just be drawn as points 6006d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 6016d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6026d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 6036d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP.setStrokeCap(SkPaint::kRound_Cap); 6046d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6056d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP.setStrokeCap(SkPaint::kButt_Cap); 6066d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6076d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 60899330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 609a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPoints(SkCanvas::kPoints_PointMode, 610a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed pointData.fNumPoints, 611a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed pointData.fPoints, 612a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed newP); 6136d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6146d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPoints(SkCanvas::kPoints_PointMode, 6156d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fNumPoints, 6166d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints, 6176d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP, 61899330ba6227137866a0dbd63478d36f335203ebdMike Reed device); 6196d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6206d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com break; 621935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com } else { 6226d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // The rest of the dashed line must be drawn as rects 6237a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 6246d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fFlags)); 6256d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6266d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkRect r; 6276d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6286d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com for (int i = 0; i < pointData.fNumPoints; ++i) { 6296d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 6306d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fY - pointData.fSize.fY, 6316d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fX + pointData.fSize.fX, 6326d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fY + pointData.fSize.fY); 63399330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 634a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawRect(r, newP); 6356d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6366d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawRect(r, newP); 6376d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6386d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 639935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com } 6406d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 641629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com break; 642629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 643629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 644629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // couldn't take fast path so fall through! 6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kPolygon_PointMode: { 6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count -= 1; 6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath path; 6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPaint p(paint); 6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p.setStyle(SkPaint::kStroke_Style); 6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 651b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth path.setIsVolatile(true); 6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i += inc) { 6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.moveTo(pts[i]); 6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.lineTo(pts[i+1]); 65599330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 656a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(path, p, nullptr, true); 657f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 65896fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->drawPath(path, p, nullptr, true); 659f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.rewind(); 6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6681a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalitastatic inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) { 6691a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkASSERT(matrix.rectStaysRect()); 6701a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkASSERT(SkPaint::kFill_Style != paint.getStyle()); 6711a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 6721a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkVector size; 6731a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 6741a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita matrix.mapVectors(&size, &pt, 1); 6751a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY)); 6761a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita} 6771a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 678761fb62b0eb174783316d2a8b933fba896ca6355reed@google.comstatic bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 679761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com SkPoint* strokeSize) { 680761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 681761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com paint.getStrokeMiter() < SK_ScalarSqrt2) { 682761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com return false; 683761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com } 684fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 6851a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita *strokeSize = compute_stroke_size(paint, matrix); 686761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com return true; 6877ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 6887ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 68962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.comSkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 69062ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com const SkMatrix& matrix, 69162ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkPoint* strokeSize) { 6927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org RectType rtype; 6937ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org const SkScalar width = paint.getStrokeWidth(); 69462ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com const bool zeroWidth = (0 == width); 6957ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkPaint::Style style = paint.getStyle(); 696fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 6977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 6987ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org style = SkPaint::kFill_Style; 6997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 700fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getPathEffect() || paint.getMaskFilter() || 70262ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com paint.getRasterizer() || !matrix.rectStaysRect() || 7037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkPaint::kStrokeAndFill_Style == style) { 70462ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com rtype = kPath_RectType; 70562ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } else if (SkPaint::kFill_Style == style) { 7067ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kFill_RectType; 7077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } else if (zeroWidth) { 7087ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kHair_RectType; 70962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } else if (easy_rect_join(paint, matrix, strokeSize)) { 7107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kStroke_RectType; 7117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } else { 7127ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kPath_RectType; 7137ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 71462ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com return rtype; 71562ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com} 71662ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7177324415759fe0c5a0902877b664aa942a89bd940reed@google.comstatic const SkPoint* rect_points(const SkRect& r) { 718fc2f0d0e6e6f72503ff9504296556dc637059c15reed@google.com return SkTCast<const SkPoint*>(&r); 7197324415759fe0c5a0902877b664aa942a89bd940reed@google.com} 7207324415759fe0c5a0902877b664aa942a89bd940reed@google.com 7217324415759fe0c5a0902877b664aa942a89bd940reed@google.comstatic SkPoint* rect_points(SkRect& r) { 722fc2f0d0e6e6f72503ff9504296556dc637059c15reed@google.com return SkTCast<SkPoint*>(&r); 72340c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com} 72440c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com 7250393912de72bc3d8b3640c122c53470dd0da1e6dreedvoid SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint, 7260393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkMatrix* paintMatrix, const SkRect* postPaintRect) const { 72762ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkDEBUGCODE(this->validate();) 7287ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 72962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com // nothing to draw 730045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 73162ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com return; 73262ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } 73362ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7340393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkMatrix* matrix; 7350393912de72bc3d8b3640c122c53470dd0da1e6dreed SkMatrix combinedMatrixStorage; 7360393912de72bc3d8b3640c122c53470dd0da1e6dreed if (paintMatrix) { 7370393912de72bc3d8b3640c122c53470dd0da1e6dreed SkASSERT(postPaintRect); 7380393912de72bc3d8b3640c122c53470dd0da1e6dreed combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix); 7390393912de72bc3d8b3640c122c53470dd0da1e6dreed matrix = &combinedMatrixStorage; 7400393912de72bc3d8b3640c122c53470dd0da1e6dreed } else { 7410393912de72bc3d8b3640c122c53470dd0da1e6dreed SkASSERT(!postPaintRect); 7420393912de72bc3d8b3640c122c53470dd0da1e6dreed matrix = fMatrix; 7430393912de72bc3d8b3640c122c53470dd0da1e6dreed } 7440393912de72bc3d8b3640c122c53470dd0da1e6dreed 74562ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkPoint strokeSize; 74662ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 74762ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7487ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (kPath_RectType == rtype) { 7490393912de72bc3d8b3640c122c53470dd0da1e6dreed SkDraw draw(*this); 7500393912de72bc3d8b3640c122c53470dd0da1e6dreed if (paintMatrix) { 7510393912de72bc3d8b3640c122c53470dd0da1e6dreed draw.fMatrix = matrix; 7520393912de72bc3d8b3640c122c53470dd0da1e6dreed } 7538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath tmp; 7540393912de72bc3d8b3640c122c53470dd0da1e6dreed tmp.addRect(prePaintRect); 7558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.setFillType(SkPath::kWinding_FillType); 75696fcdcc219d2a0d3579719b84b28bede76efba64halcanary draw.drawPath(tmp, paint, nullptr, true); 7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 7588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7600393912de72bc3d8b3640c122c53470dd0da1e6dreed SkRect devRect; 7611a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect; 7621a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita // skip the paintMatrix when transforming the rect by the CTM 7631a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2); 7647324415759fe0c5a0902877b664aa942a89bd940reed@google.com devRect.sort(); 7658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // look for the quick exit, before we build a blitter 7671a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkRect bbox = devRect; 7681c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.getStyle() != SkPaint::kFill_Style) { 7691c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // extra space for hairlines 770b3eba478d5bed5fb2b5f0f224738c8c292cebf36george if (paint.getStrokeWidth() == 0) { 7711a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita bbox.outset(1, 1); 772b3eba478d5bed5fb2b5f0f224738c8c292cebf36george } else { 7731a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita // For kStroke_RectType, strokeSize is already computed. 7741a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita const SkPoint& ssize = (kStroke_RectType == rtype) 7751a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita ? strokeSize 7761a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita : compute_stroke_size(paint, *fMatrix); 7771a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y())); 778b3eba478d5bed5fb2b5f0f224738c8c292cebf36george } 7791c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 7801a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 7811a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkIRect ir = bbox.roundOut(); 7821c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (fRC->quickReject(ir)) { 7831c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com return; 7848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 78641e010cb901c0da9066c4df562030808c9ccd7f8reed SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias()); 7871c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com while (looper.next()) { 7881c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkRect localDevRect; 7891c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com looper.mapRect(&localDevRect, devRect); 7901c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkMatrix localMatrix; 7910393912de72bc3d8b3640c122c53470dd0da1e6dreed looper.mapMatrix(&localMatrix, *matrix); 7921c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com 79341e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint); 7941c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com const SkRasterClip& clip = looper.getRC(); 7951c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkBlitter* blitter = blitterStorage.get(); 7961c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com 7971c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 7981c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // case we are also hairline (if we've gotten to here), which devolves to 7991c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // effectively just kFill 8001c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com switch (rtype) { 8011c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kFill_RectType: 8021c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8031c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiFillRect(localDevRect, clip, blitter); 8041c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8051c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::FillRect(localDevRect, clip, blitter); 8061c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8071c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8081c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kStroke_RectType: 8091c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8101c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 8111c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8121c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 8131c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8141c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8151c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kHair_RectType: 8161c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8171c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiHairRect(localDevRect, clip, blitter); 8181c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8191c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::HairRect(localDevRect, clip, blitter); 8201c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8211c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8221c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com default: 8231c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkDEBUGFAIL("bad rtype"); 8241c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (srcM.fBounds.isEmpty()) { 8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8330a60b3d32eae945688b69599f11679662657f751bungeman@google.com const SkMask* mask = &srcM; 8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8350a60b3d32eae945688b69599f11679662657f751bungeman@google.com SkMask dstM; 8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getMaskFilter() && 837e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { 8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask = &dstM; 8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 84002f55841854ae32f21a13417e9ee711463e488cfbungeman@google.com SkAutoMaskFreeImage ami(dstM.fImage); 8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 84241e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 843045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkBlitter* blitter = blitterChooser.get(); 844045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 845045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper wrapper; 846045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRegion* clipRgn; 8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 848045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 849045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clipRgn = &fRC->bwRgn(); 850045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 851045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com wrapper.init(*fRC, blitter); 852045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clipRgn = &wrapper.getRgn(); 853045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter = wrapper.getBlitter(); 854045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 855045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter->blitMaskRegion(*mask, *clipRgn); 8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 858ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.comstatic SkScalar fast_len(const SkVector& vec) { 859ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar x = SkScalarAbs(vec.fX); 860ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar y = SkScalarAbs(vec.fY); 861ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com if (x < y) { 862ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkTSwap(x, y); 863ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 864ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return x + SkScalarHalf(y); 865ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com} 866ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com 867e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.orgbool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix, 868e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org SkScalar* coverage) { 869e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org SkASSERT(strokeWidth > 0); 870e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org // We need to try to fake a thick-stroke with a modulated hairline. 871ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com 8728d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com if (matrix.hasPerspective()) { 873ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return false; 874ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 875ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com 876ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkVector src[2], dst[2]; 877ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com src[0].set(strokeWidth, 0); 878ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com src[1].set(0, strokeWidth); 879ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com matrix.mapVectors(dst, src, 2); 880ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar len0 = fast_len(dst[0]); 881ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar len1 = fast_len(dst[1]); 882652807bbc8c57e5fa9622126b51fd369f5c67935agl@chromium.org if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 88349f085dddff10473b6ebf832a974288300224e60bsalomon if (coverage) { 884e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org *coverage = SkScalarAve(len0, len1); 885e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org } 886ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return true; 887ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 888ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return false; 889ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com} 890ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com 891a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comvoid SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 892a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkDEBUGCODE(this->validate()); 893a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 894a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (fRC->isEmpty()) { 895a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com return; 896a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 897a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 898a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com { 899a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // TODO: Investigate optimizing these options. They are in the same 900a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // order as SkDraw::drawPath, which handles each case. It may be 901a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // that there is no way to optimize for these using the SkRRect path. 902a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkScalar coverage; 903a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 904a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 905a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 906a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 907a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 908a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 909a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 910a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 911a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getRasterizer()) { 912a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 913a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 914a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 915a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 916a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getMaskFilter()) { 917a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // Transform the rrect into device space. 918a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkRRect devRRect; 919a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (rrect.transform(*fMatrix, &devRRect)) { 92041e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 921055e192adc0072ae2548ef5431ceee652945f9c2bsalomon if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) { 922a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com return; // filterRRect() called the blitter, so we're done 923a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 924a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 925a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 926a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 927a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comDRAW_PATH: 928a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // Now fall back to the default case of using a path. 929a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkPath path; 930a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com path.addRRect(rrect); 93196fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->drawPath(path, paint, nullptr, true); 932a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com} 933a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 9341a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkSkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) { 93505d9044de4f1c6e791df66a425638752daac4c6breed if (!matrix.hasPerspective()) { 93605d9044de4f1c6e791df66a425638752daac4c6breed SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); 93705d9044de4f1c6e791df66a425638752daac4c6breed SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); 93805d9044de4f1c6e791df66a425638752daac4c6breed if (SkScalarsAreFinite(sx, sy)) { 939a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman SkScalar scale = SkTMax(sx, sy); 940a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman if (scale > 0) { 941a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman return scale; 942a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman } 94305d9044de4f1c6e791df66a425638752daac4c6breed } 94405d9044de4f1c6e791df66a425638752daac4c6breed } 94505d9044de4f1c6e791df66a425638752daac4c6breed return 1; 94605d9044de4f1c6e791df66a425638752daac4c6breed} 94705d9044de4f1c6e791df66a425638752daac4c6breed 94882595b6fa4733e1525f357bdcac22db058790550reedvoid SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage, 94982595b6fa4733e1525f357bdcac22db058790550reed SkBlitter* customBlitter, bool doFill) const { 95001a2ff8a325e17221b139968e337413df0c2e60creed // Do a conservative quick-reject test, since a looper or other modifier may have moved us 95101a2ff8a325e17221b139968e337413df0c2e60creed // out of range. 95201a2ff8a325e17221b139968e337413df0c2e60creed if (!devPath.isInverseFillType()) { 95301a2ff8a325e17221b139968e337413df0c2e60creed // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't 95401a2ff8a325e17221b139968e337413df0c2e60creed // appear empty to the intersects call. This also gives us slop in case we're antialiasing 95501a2ff8a325e17221b139968e337413df0c2e60creed SkRect pathBounds = devPath.getBounds().makeOutset(1, 1); 95601a2ff8a325e17221b139968e337413df0c2e60creed 95701a2ff8a325e17221b139968e337413df0c2e60creed if (paint.getMaskFilter()) { 95801a2ff8a325e17221b139968e337413df0c2e60creed paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds); 95901a2ff8a325e17221b139968e337413df0c2e60creed 96001a2ff8a325e17221b139968e337413df0c2e60creed // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed 96101a2ff8a325e17221b139968e337413df0c2e60creed // we can remove this hack. See skbug.com/5542 96201a2ff8a325e17221b139968e337413df0c2e60creed pathBounds.outset(7, 7); 96301a2ff8a325e17221b139968e337413df0c2e60creed } 96401a2ff8a325e17221b139968e337413df0c2e60creed 96501a2ff8a325e17221b139968e337413df0c2e60creed // Now compare against the clip's bounds 96601a2ff8a325e17221b139968e337413df0c2e60creed if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) { 96701a2ff8a325e17221b139968e337413df0c2e60creed return; 96801a2ff8a325e17221b139968e337413df0c2e60creed } 96901a2ff8a325e17221b139968e337413df0c2e60creed } 97001a2ff8a325e17221b139968e337413df0c2e60creed 97182595b6fa4733e1525f357bdcac22db058790550reed SkBlitter* blitter = nullptr; 97282595b6fa4733e1525f357bdcac22db058790550reed SkAutoBlitterChoose blitterStorage; 97382595b6fa4733e1525f357bdcac22db058790550reed if (nullptr == customBlitter) { 97482595b6fa4733e1525f357bdcac22db058790550reed blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage); 97582595b6fa4733e1525f357bdcac22db058790550reed blitter = blitterStorage.get(); 97682595b6fa4733e1525f357bdcac22db058790550reed } else { 97782595b6fa4733e1525f357bdcac22db058790550reed blitter = customBlitter; 97882595b6fa4733e1525f357bdcac22db058790550reed } 97982595b6fa4733e1525f357bdcac22db058790550reed 98082595b6fa4733e1525f357bdcac22db058790550reed if (paint.getMaskFilter()) { 98182595b6fa4733e1525f357bdcac22db058790550reed SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle 98282595b6fa4733e1525f357bdcac22db058790550reed : SkStrokeRec::kHairline_InitStyle; 98382595b6fa4733e1525f357bdcac22db058790550reed if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { 98482595b6fa4733e1525f357bdcac22db058790550reed return; // filterPath() called the blitter, so we're done 98582595b6fa4733e1525f357bdcac22db058790550reed } 98682595b6fa4733e1525f357bdcac22db058790550reed } 98782595b6fa4733e1525f357bdcac22db058790550reed 98882595b6fa4733e1525f357bdcac22db058790550reed void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 98982595b6fa4733e1525f357bdcac22db058790550reed if (doFill) { 99082595b6fa4733e1525f357bdcac22db058790550reed if (paint.isAntiAlias()) { 99182595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiFillPath; 99282595b6fa4733e1525f357bdcac22db058790550reed } else { 99382595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::FillPath; 99482595b6fa4733e1525f357bdcac22db058790550reed } 99582595b6fa4733e1525f357bdcac22db058790550reed } else { // hairline 99682595b6fa4733e1525f357bdcac22db058790550reed if (paint.isAntiAlias()) { 99782595b6fa4733e1525f357bdcac22db058790550reed switch (paint.getStrokeCap()) { 99882595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kButt_Cap: 99982595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairPath; 100082595b6fa4733e1525f357bdcac22db058790550reed break; 100182595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kSquare_Cap: 100282595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairSquarePath; 100382595b6fa4733e1525f357bdcac22db058790550reed break; 100482595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kRound_Cap: 100582595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairRoundPath; 100682595b6fa4733e1525f357bdcac22db058790550reed break; 100782595b6fa4733e1525f357bdcac22db058790550reed default: 100882595b6fa4733e1525f357bdcac22db058790550reed proc SK_INIT_TO_AVOID_WARNING; 100982595b6fa4733e1525f357bdcac22db058790550reed SkDEBUGFAIL("unknown paint cap type"); 101082595b6fa4733e1525f357bdcac22db058790550reed } 101182595b6fa4733e1525f357bdcac22db058790550reed } else { 101282595b6fa4733e1525f357bdcac22db058790550reed switch (paint.getStrokeCap()) { 101382595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kButt_Cap: 101482595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairPath; 101582595b6fa4733e1525f357bdcac22db058790550reed break; 101682595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kSquare_Cap: 101782595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairSquarePath; 101882595b6fa4733e1525f357bdcac22db058790550reed break; 101982595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kRound_Cap: 102082595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairRoundPath; 102182595b6fa4733e1525f357bdcac22db058790550reed break; 102282595b6fa4733e1525f357bdcac22db058790550reed default: 102382595b6fa4733e1525f357bdcac22db058790550reed proc SK_INIT_TO_AVOID_WARNING; 102482595b6fa4733e1525f357bdcac22db058790550reed SkDEBUGFAIL("unknown paint cap type"); 102582595b6fa4733e1525f357bdcac22db058790550reed } 102682595b6fa4733e1525f357bdcac22db058790550reed } 102782595b6fa4733e1525f357bdcac22db058790550reed } 102882595b6fa4733e1525f357bdcac22db058790550reed proc(devPath, *fRC, blitter); 102982595b6fa4733e1525f357bdcac22db058790550reed} 103082595b6fa4733e1525f357bdcac22db058790550reed 103132e5d97ccf60f859db063ebd6e903c362e625767reed@google.comvoid SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1032126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com const SkMatrix* prePathMatrix, bool pathIsMutable, 103353f0959fc024c56dc55fe6bf86380127b59abec9krajcevski bool drawCoverage, SkBlitter* customBlitter) const { 1034f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 10358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1037045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 10388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 10398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* pathPtr = (SkPath*)&origSrcPath; 10428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool doFill = true; 10438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath tmpPath; 10448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix tmpMatrix; 10458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkMatrix* matrix = fMatrix; 1046b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth tmpPath.setIsVolatile(true); 10478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (prePathMatrix) { 104932e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 105032e5d97ccf60f859db063ebd6e903c362e625767reed@google.com origPaint.getRasterizer()) { 10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* result = pathPtr; 1052a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 10538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!pathIsMutable) { 10548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com result = &tmpPath; 10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathIsMutable = true; 10568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr->transform(*prePathMatrix, result); 10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr = result; 10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 106092362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org tmpMatrix.setConcat(*matrix, *prePathMatrix); 10618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix = &tmpMatrix; 10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // at this point we're done with prePathMatrix 10658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1066a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 10675dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1068a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1069ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com { 1070dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com SkScalar coverage; 1071dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1072dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com if (SK_Scalar1 == coverage) { 10735dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com paint.writable()->setStrokeWidth(0); 1074374772bd61951f01bf84fe17bf53d8867681c9aereed } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) { 1075dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com U8CPU newAlpha; 1076dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#if 0 1077dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1078dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com origPaint.getAlpha())); 1079dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#else 1080dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // this is the old technique, which we preserve for now so 1081dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // we don't change previous results (testing) 1082dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // the new way seems fine, its just (a tiny bit) different 1083a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed int scale = (int)(coverage * 256); 1084dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com newAlpha = origPaint.getAlpha() * scale >> 8; 1085dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#endif 10865dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com SkPaint* writablePaint = paint.writable(); 10875dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com writablePaint->setStrokeWidth(0); 10885dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com writablePaint->setAlpha(newAlpha); 1089dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com } 10908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1092a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 109332e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 10944bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkRect cullRect; 109596fcdcc219d2a0d3579719b84b28bede76efba64halcanary const SkRect* cullRectPtr = nullptr; 10964bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (this->computeConservativeLocalClipBounds(&cullRect)) { 10974bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com cullRectPtr = &cullRect; 10984bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 109905d9044de4f1c6e791df66a425638752daac4c6breed doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr, 11001a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark ComputeResScaleForStroking(*fMatrix)); 11018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr = &tmpPath; 11028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1103a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 110432e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getRasterizer()) { 11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 110632e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1107045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com &fRC->getBounds(), paint->getMaskFilter(), &mask, 11088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 110932e5d97ccf60f859db063ebd6e903c362e625767reed@google.com this->drawDevMask(mask, *paint); 11108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::FreeImage(mask.fImage); 11118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 11138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // avoid possibly allocating a new path in transform if we can 11168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // transform the path into device space 11198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr->transform(*matrix, devPathPtr); 11208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 112182595b6fa4733e1525f357bdcac22db058790550reed this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill); 11228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 11238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 112482595b6fa4733e1525f357bdcac22db058790550reedvoid SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { 1125900ecf2f1579d42c9d2959831787af0346320f86reed@google.com SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); 11268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1127c7e211acd0c9201688de7ff0c9a2271c67440adffmalita if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { 1128e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); 1129e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); 11308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11314edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 11324edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1133a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com return; 1134a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com } 11358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 113692fc2ae58331662ec411a048686cb4801e0a909areed mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height()); 11378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fFormat = SkMask::kA8_Format; 113892fc2ae58331662ec411a048686cb4801e0a909areed mask.fRowBytes = SkToU32(pmap.rowBytes()); 113992fc2ae58331662ec411a048686cb4801e0a909areed // fImage is typed as writable, but in this case it is used read-only 114092fc2ae58331662ec411a048686cb4801e0a909areed mask.fImage = (uint8_t*)pmap.addr8(0, 0); 1141a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawDevMask(mask, paint); 11438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { // need to xform the bitmap first 11448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 11458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 1146a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(0, 0, 11488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 11498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMatrix->mapRect(&r); 11508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.round(&mask.fBounds); 1151a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // set the mask's bounds to the transformed bitmap-bounds, 11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // clipped to the actual device 11548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 11558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect devBounds; 115641e010cb901c0da9066c4df562030808c9ccd7f8reed devBounds.set(0, 0, fDst.width(), fDst.height()); 11578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need intersect(l, t, r, b) on irect 11588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!mask.fBounds.intersect(devBounds)) { 11598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 11608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1162543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com 11638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fFormat = SkMask::kA8_Format; 11648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1165543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com size_t size = mask.computeImageSize(); 1166543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com if (0 == size) { 1167543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com // the mask is too big to allocated, draw nothing 1168543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com return; 1169543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com } 11708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // allocate (and clear) our temp buffer to hold the transformed bitmap 1172565901db954c231840750ea955ed31b820b9ade8scroggo SkAutoTMalloc<uint8_t> storage(size); 1173565901db954c231840750ea955ed31b820b9ade8scroggo mask.fImage = storage.get(); 11748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(mask.fImage, 0, size); 1175a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now draw our bitmap(src) into mask(dst), transformed by the matrix 11778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 11788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBitmap device; 1179a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()), 1180a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org mask.fImage, mask.fRowBytes); 1181a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkCanvas c(device); 11838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need the unclipped top/left for the translate 11848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com c.translate(-SkIntToScalar(mask.fBounds.fLeft), 11858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com -SkIntToScalar(mask.fBounds.fTop)); 11868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com c.concat(*fMatrix); 11873469c76c40790b409621fd7eff34f56240718549reed@android.com 11883469c76c40790b409621fd7eff34f56240718549reed@android.com // We can't call drawBitmap, or we'll infinitely recurse. Instead 1189fb12c3e6ba84f95dc15fbaddc239dede0ba1d60ereed@android.com // we manually build a shader and draw that into our new mask 11903469c76c40790b409621fd7eff34f56240718549reed@android.com SkPaint tmpPaint; 11913469c76c40790b409621fd7eff34f56240718549reed@android.com tmpPaint.setFlags(paint.getFlags()); 119266a96d07d5583cc018cb70127bd5483799b69d0ebrianosman tmpPaint.setFilterQuality(paint.getFilterQuality()); 11934bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap); 11943469c76c40790b409621fd7eff34f56240718549reed@android.com SkRect rr; 11953469c76c40790b409621fd7eff34f56240718549reed@android.com rr.set(0, 0, SkIntToScalar(bitmap.width()), 11963469c76c40790b409621fd7eff34f56240718549reed@android.com SkIntToScalar(bitmap.height())); 11974bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby c.drawRect(rr, paintWithShader); 11988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawDevMask(mask, paint); 12008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1203045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comstatic bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 12048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkRect& srcR) { 12058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect dstR; 12068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com m.mapRect(&dstR, srcR); 1207b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed return c.quickReject(dstR.roundOut()); 12088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1210045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comstatic bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 12118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width, int height) { 12128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 12138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 12148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return clipped_out(matrix, clip, r); 12158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1217c240e719b2bebd3711ade4e6fe056921aa7b0521reedstatic bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) { 1218c240e719b2bebd3711ade4e6fe056921aa7b0521reed return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height()); 1219045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com} 1220045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 12218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 12220393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkRect* dstBounds, const SkPaint& origPaint) const { 1223f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 12248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1226045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty() || 12278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bitmap.width() == 0 || bitmap.height() == 0 || 1228900ecf2f1579d42c9d2959831787af0346320f86reed@google.com bitmap.colorType() == kUnknown_SkColorType) { 12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1231a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1232f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1233f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita if (origPaint.getStyle() != SkPaint::kFill_Style) { 1234f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita paint.writable()->setStyle(SkPaint::kFill_Style); 1235f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita } 1236a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 123892362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org matrix.setConcat(*fMatrix, prematrix); 12398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1240045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1244c7e211acd0c9201688de7ff0c9a2271c67440adffmalita if (bitmap.colorType() != kAlpha_8_SkColorType 1245f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) { 1246f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // 1247f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // It is safe to call lock pixels now, since we know the matrix is 1248f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // (more or less) identity. 1249f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // 12504edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 12514edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1252f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com return; 1253f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com } 1254e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int ix = SkScalarRoundToInt(matrix.getTranslateX()); 1255e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int iy = SkScalarRoundToInt(matrix.getTranslateY()); 1256c240e719b2bebd3711ade4e6fe056921aa7b0521reed if (clipHandlesSprite(*fRC, ix, iy, pmap)) { 125714a6430b7bcf92bcabf4aef18805969d1335aab1Florin Malita SkSTArenaAlloc<kSkBlitterContextSize> allocator; 1258a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org // blitter will be owned by the allocator. 1259f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator); 1260045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (blitter) { 1261c240e719b2bebd3711ade4e6fe056921aa7b0521reed SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()), 1262c240e719b2bebd3711ade4e6fe056921aa7b0521reed *fRC, blitter); 1263045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 12648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1265c240e719b2bebd3711ade4e6fe056921aa7b0521reed // if !blitter, then we fall-through to the slower case 12668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1268a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now make a temp draw on the stack, and use it 12708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // 12718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDraw draw(*this); 12728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 1273a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 127470ac8a9d091d385bf5244125159c4d8509a0c470Matt Sarett if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) { 1275f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita draw.drawBitmapAsMask(bitmap, *paint); 12768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 12774bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(*paint, bitmap); 12780393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 12790393912de72bc3d8b3640c122c53470dd0da1e6dreed if (dstBounds) { 12800393912de72bc3d8b3640c122c53470dd0da1e6dreed this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds); 12810393912de72bc3d8b3640c122c53470dd0da1e6dreed } else { 12820393912de72bc3d8b3640c122c53470dd0da1e6dreed draw.drawRect(srcBounds, paintWithShader); 12830393912de72bc3d8b3640c122c53470dd0da1e6dreed } 12848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1287c240e719b2bebd3711ade4e6fe056921aa7b0521reedvoid SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const { 1288f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 1289a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1291045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty() || 12928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bitmap.width() == 0 || bitmap.height() == 0 || 1293900ecf2f1579d42c9d2959831787af0346320f86reed@google.com bitmap.colorType() == kUnknown_SkColorType) { 12948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1297c240e719b2bebd3711ade4e6fe056921aa7b0521reed const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1299045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->quickReject(bounds)) { 13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; // nothing to draw 13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 130340c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkPaint paint(origPaint); 130440c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com paint.setStyle(SkPaint::kFill_Style); 13058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13064edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 13074edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1308c240e719b2bebd3711ade4e6fe056921aa7b0521reed return; 1309c240e719b2bebd3711ade4e6fe056921aa7b0521reed } 1310c240e719b2bebd3711ade4e6fe056921aa7b0521reed 131196fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) { 1312a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org // blitter will be owned by the allocator. 131314a6430b7bcf92bcabf4aef18805969d1335aab1Florin Malita SkSTArenaAlloc<kSkBlitterContextSize> allocator; 131441e010cb901c0da9066c4df562030808c9ccd7f8reed SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator); 13158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (blitter) { 1316045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillIRect(bounds, *fRC, blitter); 13178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 13188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 13228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 13238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // get a scalar version of our rect 13258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(bounds); 13268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13279c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org // create shader with offset 13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(r.fLeft, r.fTop); 13294bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix); 13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDraw draw(*this); 13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.reset(); 13328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 13338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // call ourself with a rect 1334a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com // is this OK if paint has a rasterizer? 13354bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby draw.drawRect(r, paintWithShader); 13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 13378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 13398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13407120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed#include "SkPaintPriv.h" 13418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalerContext.h" 13428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkGlyphCache.h" 1343e69137620ab0b5b40d230318c8e11b822f63cb9dreed@google.com#include "SkTextToPathIter.h" 13448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h" 13458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13468128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.orgbool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 13478128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org // hairline glyphs are fast enough so we don't need to cache them 13488128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { 13498128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org return true; 13508128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org } 13518128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 13528128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org // we don't cache perspective 13538128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org if (ctm.hasPerspective()) { 13548128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org return true; 13558128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org } 13568128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 13578128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org SkMatrix textM; 13587120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed SkPaintPriv::MakeTextMatrix(&textM, paint); 13597120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed return SkPaint::TooBigToUseCache(ctm, textM); 13608128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org} 13618128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 136299330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, 13638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPaint& paint) const { 1364f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 13658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1366166e653f67f3fffc3846184a25ce45ab083f07a2djsollen@google.com SkTextToPathIter iter(text, byteLength, paint, true); 13678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 13698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setScale(iter.getPathScale(), iter.getPathScale()); 13708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.postTranslate(x, y); 13718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPath* iterPath; 13738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar xpos, prevXPos = 0; 13748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13757b4531f64cbd85d32a77ceab1bdec8335c5a7864reed@google.com while (iter.next(&iterPath, &xpos)) { 13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.postTranslate(xpos - prevXPos, 0); 13777b4531f64cbd85d32a77ceab1bdec8335c5a7864reed@google.com if (iterPath) { 1378a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed this->drawPath(*iterPath, iter.getPaint(), &matrix, false); 1379f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 13808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com prevXPos = xpos; 13818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 13838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// disable warning : local variable used without having been initialized 1385d7dc76f7e99309cbd09a5420c22e55b951067debbungeman#if defined _WIN32 13868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( push ) 13878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( disable : 4701 ) 13888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 13898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1390f553e4e09cd2baf15fc041daab8a08bd46e352f0herb//////////////////////////////////////////////////////////////////////////////////////////////////// 13912e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1392d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbclass DrawOneGlyph { 1393d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbpublic: 1394d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) 1395d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) 1396d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fGlyphCache(cache) 1397d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fBlitter(blitter) 1398d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) 1399d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fDraw(draw) 1400d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fPaint(paint) 1401d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fClipBounds(PickClipBounds(draw)) { } 1402d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1403d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1404d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb position += rounding; 1405d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // Prevent glyphs from being drawn outside of or straddling the edge of device space. 1406875e13ca0990e32da9db639743a913efe77f7e89mtklein // Comparisons written a little weirdly so that NaN coordinates are treated safely. 1407875e13ca0990e32da9db639743a913efe77f7e89mtklein auto gt = [](float a, int b) { return !(a <= (float)b); }; 1408875e13ca0990e32da9db639743a913efe77f7e89mtklein auto lt = [](float a, int b) { return !(a >= (float)b); }; 1409875e13ca0990e32da9db639743a913efe77f7e89mtklein if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1410875e13ca0990e32da9db639743a913efe77f7e89mtklein lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) || 1411875e13ca0990e32da9db639743a913efe77f7e89mtklein gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1412875e13ca0990e32da9db639743a913efe77f7e89mtklein lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) { 1413d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return; 1414d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1415d095f2bf06ca810844233bea9fb06de585643b32bungeman 141677a9cc1dead147fc547895d3725d9ee2150cda73benjaminwagner int left = SkScalarFloorToInt(position.fX); 141777a9cc1dead147fc547895d3725d9ee2150cda73benjaminwagner int top = SkScalarFloorToInt(position.fY); 1418d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 14198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1420d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb left += glyph.fLeft; 1421d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb top += glyph.fTop; 14228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1423d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb int right = left + glyph.fWidth; 1424d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb int bottom = top + glyph.fHeight; 14258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1426d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkMask mask; 1427d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask.fBounds.set(left, top, right, bottom); 1428875e13ca0990e32da9db639743a913efe77f7e89mtklein SkASSERT(!mask.fBounds.isEmpty()); 142983a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1430d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (fUseRegionToDraw) { 1431d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkRegion::Cliperator clipper(*fClip, mask.fBounds); 143283a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1433d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!clipper.done() && this->getImageData(glyph, &mask)) { 1434d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkIRect& cr = clipper.rect(); 1435d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb do { 1436d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb this->blitMask(mask, cr); 1437d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb clipper.next(); 1438d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } while (!clipper.done()); 1439d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1440d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } else { 1441d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkIRect storage; 1442d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkIRect* bounds = &mask.fBounds; 1443d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1444d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // this extra test is worth it, assuming that most of the time it succeeds 1445d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // since we can avoid writing to storage 1446d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { 1447d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) 1448d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return; 1449d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bounds = &storage; 1450d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 145183a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1452d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (this->getImageData(glyph, &mask)) { 1453d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb this->blitMask(mask, *bounds); 1454d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1455cd7f03597475ea423aa819bdae03996b26874dd5herb } 145683a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com } 14578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1458d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbprivate: 1459d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb static bool UsingRegionToDraw(const SkRasterClip* rClip) { 1460d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rClip->isBW() && !rClip->isRect(); 1461d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 14622e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1463d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb static SkIRect PickClipBounds(const SkDraw& draw) { 1464d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkRasterClip& rasterClip = *draw.fRC; 14652e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1466d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (rasterClip.isBW()) { 1467d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rasterClip.bwRgn().getBounds(); 1468d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } else { 1469d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rasterClip.aaRgn().getBounds(); 1470001e74426672e00f3f2783ccf728031662d4a358herb } 14719447103029273a9f8dd7f5997e8af7a1e3ee7488bungeman@google.com } 1472001e74426672e00f3f2783ccf728031662d4a358herb 1473d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bool getImageData(const SkGlyph& glyph, SkMask* mask) { 1474d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); 1475d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (nullptr == bits) { 1476d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return false; // can't rasterize glyph 1477d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1478d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fImage = bits; 1479d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fRowBytes = glyph.rowBytes(); 1480d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1481d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return true; 14822e8fec79658baef06f4a9fca5e91a4e116b47b3dherb } 14832e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1484d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb void blitMask(const SkMask& mask, const SkIRect& clip) const { 1485d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (SkMask::kARGB32_Format == mask.fFormat) { 1486d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkBitmap bm; 1487d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bm.installPixels( 1488d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), 1489d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb (SkPMColor*)mask.fImage, mask.fRowBytes); 1490d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1491d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); 1492045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 1493d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb fBlitter->blitMask(mask, clip); 1494045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 14958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 14965bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 1497d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const bool fUseRegionToDraw; 1498d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkGlyphCache * const fGlyphCache; 1499d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkBlitter * const fBlitter; 1500d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkRegion* const fClip; 1501d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkDraw& fDraw; 1502d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkPaint& fPaint; 1503d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkIRect fClipBounds; 1504d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb}; 15052e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1506d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb//////////////////////////////////////////////////////////////////////////////////////////////////// 15078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1508a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosmanuint32_t SkDraw::scalerContextFlags() const { 1509a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag; 151099330ba6227137866a0dbd63478d36f335203ebdMike Reed if (!fDst.colorSpace()) { 1511a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman flags |= SkPaint::kFakeGamma_ScalerContextFlag; 1512a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman } 1513a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman return flags; 1514f6d1e605317917146362706ed460b5ed6624fcc5bungeman} 1515f6d1e605317917146362706ed460b5ed6624fcc5bungeman 151699330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, 151799330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkPaint& paint, const SkSurfaceProps* props) const { 151896fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(byteLength == 0 || text != nullptr); 15198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1520f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 15218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 152396fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 15248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 15258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 152736d6edac9f3e63d9a5f499d0076550d08b80eacabsalomon@google.com // SkScalarRec doesn't currently have a way of representing hairline stroke and 152836d6edac9f3e63d9a5f499d0076550d08b80eacabsalomon@google.com // will fill if its frame-width is 0. 1529ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 15308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawText_asPaths(text, byteLength, x, y, paint); 15318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 15328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 153499330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); 153511a7f7f5998cb3d5605741e37a7f12f7477d480cherb 153611a7f7f5998cb3d5605741e37a7f12f7477d480cherb // The Blitter Choose needs to be live while using the blitter below. 153711a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 153811a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1539f6d1e605317917146362706ed460b5ed6624fcc5bungeman DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 15408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1541e59124ed1a62f1fec79679c38cabed622a756f75herb SkFindAndPlaceGlyph::ProcessText( 15424c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb paint.getTextEncoding(), text, byteLength, 1543f6d1e605317917146362706ed460b5ed6624fcc5bungeman {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph); 15448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 15458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////// 15478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 154899330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], 154999330ba6227137866a0dbd63478d36f335203ebdMike Reed int scalarsPerPosition, const SkPoint& offset, 155099330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkPaint& origPaint, const SkSurfaceProps* props) const { 1551ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com // setup our std paint, in hopes of getting hits in the cache 1552ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com SkPaint paint(origPaint); 1553ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com SkScalar matrixScale = paint.setupForAsPaths(); 1554ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 15555a64902ee92847f53dfc5b211da19d074179be64reed@google.com SkMatrix matrix; 15565a64902ee92847f53dfc5b211da19d074179be64reed@google.com matrix.setScale(matrixScale, matrixScale); 15578f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 15584e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. 15594e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org paint.setStyle(SkPaint::kFill_Style); 156096fcdcc219d2a0d3579719b84b28bede76efba64halcanary paint.setPathEffect(nullptr); 15614e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org 1562e34f17d23699abfc672289f51319b37294b3c257robertphillips SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), 1563e34f17d23699abfc672289f51319b37294b3c257robertphillips paint.isDevKernText(), 1564e34f17d23699abfc672289f51319b37294b3c257robertphillips true); 156599330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), nullptr); 1566ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 1567ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com const char* stop = text + byteLength; 156879738cc7bf12d212bef4ff80591d1bf6f383663dbungeman SkTextAlignProc alignProc(paint.getTextAlign()); 156905c4a4322e7d4f3417b7df33825bab8603d52051fmalita SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); 15708f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 15714e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org // Now restore the original settings, so we "draw" with whatever style/stroking. 15724e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org paint.setStyle(origPaint.getStyle()); 1573693fdbd6b81a860657612e7604430dd55d6e721bMike Reed paint.setPathEffect(origPaint.refPathEffect()); 15744e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org 1575ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com while (text < stop) { 1576d936f63c35fb7dfb2b6c20802206adbfc3cc48d0benjaminwagner const SkGlyph& glyph = glyphCacheProc(cache.get(), &text); 1577ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (glyph.fWidth) { 1578ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com const SkPath* path = cache->findPath(glyph); 1579ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (path) { 1580cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen SkPoint tmsLoc; 1581cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen tmsProc(pos, &tmsLoc); 1582cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com SkPoint loc; 1583cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen alignProc(tmsLoc, glyph, &loc); 15848f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 1585cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com matrix[SkMatrix::kMTransX] = loc.fX; 1586cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com matrix[SkMatrix::kMTransY] = loc.fY; 158799330ba6227137866a0dbd63478d36f335203ebdMike Reed this->drawPath(*path, paint, &matrix, false); 1588ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1589ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1590ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com pos += scalarsPerPosition; 1591ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1592ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com} 1593ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 159499330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar pos[], 159599330ba6227137866a0dbd63478d36f335203ebdMike Reed int scalarsPerPosition, const SkPoint& offset, const SkPaint& paint, 159699330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkSurfaceProps* props) const { 159796fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(byteLength == 0 || text != nullptr); 15988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 15998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1600f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 16018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 160396fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 16048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 16058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1607ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 160899330ba6227137866a0dbd63478d36f335203ebdMike Reed this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint, props); 16098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 16108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 161299330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); 1613d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 16149be5ff6f9871ef22740094e7c25dd67329a73d20herb // The Blitter Choose needs to be live while using the blitter below. 161511a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 161611a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1617f6d1e605317917146362706ed460b5ed6624fcc5bungeman DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1618d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkPaint::Align textAlignment = paint.getTextAlign(); 16198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16209be5ff6f9871ef22740094e7c25dd67329a73d20herb SkFindAndPlaceGlyph::ProcessPosText( 16214c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb paint.getTextEncoding(), text, byteLength, 1622f6d1e605317917146362706ed460b5ed6624fcc5bungeman offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph); 16238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1625d7dc76f7e99309cbd09a5420c22e55b951067debbungeman#if defined _WIN32 16268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( pop ) 16278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 16288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1629787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed//////////////////////////////////////////////////////////////////////////////////////////////// 16308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 16328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1633f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkDraw::validate() const { 163496fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(fMatrix != nullptr); 163596fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(fRC != nullptr); 16368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1637045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkIRect& cr = fRC->getBounds(); 16388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect br; 16398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 164041e010cb901c0da9066c4df562030808c9ccd7f8reed br.set(0, 0, fDst.width(), fDst.height()); 16418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(cr.isEmpty() || br.contains(cr)); 16428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 16458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////////////////////// 16478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h" 16498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDraw.h" 16508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h" 16518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h" 16528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 1654b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed const SkMaskFilter* filter, const SkMatrix* filterMatrix, 16558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect* bounds) { 16568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (devPath.isEmpty()) { 16578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 16588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // init our bounds from the path 166111fa2247b747eb75e2f158dc7571d458ed6c0115reed *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut(); 1662a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16636db75fc2c393ba86a3f533597a8bcd348477e79ctomhudson@google.com SkIPoint margin = SkIPoint::Make(0, 0); 16648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (filter) { 16658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(filterMatrix); 1666a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16675af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com SkMask srcM, dstM; 1668a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcM.fBounds = *bounds; 16708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcM.fFormat = SkMask::kA8_Format; 16718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 16728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 16738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1675a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16765af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com // (possibly) trim the bounds to reflect the clip 16778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // (plus whatever slop the filter needs) 16785af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com if (clipBounds) { 16793555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // Ugh. Guard against gigantic margins from wacky filters. Without this 16803555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // check we can request arbitrary amounts of slop beyond our visible 16813555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // clip, and bring down the renderer (at least on finite RAM machines 16823555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // like handsets, etc.). Need to balance this invented value between 16833555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // quality of large filters like blurs, and the corresponding memory 16843555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // requests. 16853555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com static const int MAX_MARGIN = 128; 168611fa2247b747eb75e2f158dc7571d458ed6c0115reed if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN), 168711fa2247b747eb75e2f158dc7571d458ed6c0115reed SkMin32(margin.fY, MAX_MARGIN)))) { 16885af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com return false; 16895af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com } 16908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 16938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1695055e192adc0072ae2548ef5431ceee652945f9c2bsalomonstatic void draw_into_mask(const SkMask& mask, const SkPath& devPath, 1696055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkStrokeRec::InitStyle style) { 169741e010cb901c0da9066c4df562030808c9ccd7f8reed SkDraw draw; 169841e010cb901c0da9066c4df562030808c9ccd7f8reed if (!draw.fDst.reset(mask)) { 169941e010cb901c0da9066c4df562030808c9ccd7f8reed return; 170041e010cb901c0da9066c4df562030808c9ccd7f8reed } 170141e010cb901c0da9066c4df562030808c9ccd7f8reed 1702045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkRasterClip clip; 1703045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkMatrix matrix; 1704045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkPaint paint; 17058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1706045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 17078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 17088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com -SkIntToScalar(mask.fBounds.fTop)); 17098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1710045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com draw.fRC = &clip; 17118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 17128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com paint.setAntiAlias(true); 1713055e192adc0072ae2548ef5431ceee652945f9c2bsalomon switch (style) { 1714055e192adc0072ae2548ef5431ceee652945f9c2bsalomon case SkStrokeRec::kHairline_InitStyle: 1715055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkASSERT(!paint.getStrokeWidth()); 1716055e192adc0072ae2548ef5431ceee652945f9c2bsalomon paint.setStyle(SkPaint::kStroke_Style); 1717055e192adc0072ae2548ef5431ceee652945f9c2bsalomon break; 1718055e192adc0072ae2548ef5431ceee652945f9c2bsalomon case SkStrokeRec::kFill_InitStyle: 1719055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkASSERT(paint.getStyle() == SkPaint::kFill_Style); 1720055e192adc0072ae2548ef5431ceee652945f9c2bsalomon break; 1721055e192adc0072ae2548ef5431ceee652945f9c2bsalomon 1722055e192adc0072ae2548ef5431ceee652945f9c2bsalomon } 17238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.drawPath(devPath, paint); 17248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 172730711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com const SkMaskFilter* filter, const SkMatrix* filterMatrix, 17282ac4ef5e6e0c9c95c9200408ba25a95ca758eac2junov@chromium.org SkMask* mask, SkMask::CreateMode mode, 1729055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkStrokeRec::InitStyle style) { 17308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kJustRenderImage_CreateMode != mode) { 17318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 17328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 17338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1734a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 17358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 17368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fFormat = SkMask::kA8_Format; 17378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fRowBytes = mask->fBounds.width(); 1738543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com size_t size = mask->computeImageSize(); 1739543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com if (0 == size) { 1740543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com // we're too big to allocate the mask, abort 1741543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com return false; 1742543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com } 1743543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com mask->fImage = SkMask::AllocImage(size); 17448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(mask->fImage, 0, mask->computeImageSize()); 17458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kJustComputeBounds_CreateMode != mode) { 17482ac4ef5e6e0c9c95c9200408ba25a95ca758eac2junov@chromium.org draw_into_mask(*mask, devPath, style); 17498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1750a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 17518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 17528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1753