SkDraw.cpp revision 787a16dd9e03f3971898131dd778206c8cb9a0df
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 39d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// Helper function to fix code gen bug on ARM64. 40d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb// See SkFindAndPlaceGlyph.h for more details. 41d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbvoid FixGCC49Arm64Bug(int v) { } 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 434bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derbystatic SkPaint make_paint_with_image( 444bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby const SkPaint& origPaint, const SkBitmap& bitmap, SkMatrix* matrix = nullptr) { 454bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paint(origPaint); 464bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby paint.setShader(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode, 474bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkShader::kClamp_TileMode, matrix, 484bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby kNever_SkCopyPixelsMode)); 494bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby return paint; 504bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby} 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 54f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comSkDraw::SkDraw() { 55f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com sk_bzero(this, sizeof(*this)); 56f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com} 57f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com 584bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.combool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const { 594bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (fRC->isEmpty()) { 604bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return false; 614bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 624bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 634bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkMatrix inverse; 644bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (!fMatrix->invert(&inverse)) { 654bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return false; 664bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 674bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 684bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkIRect devBounds = fRC->getBounds(); 694bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com // outset to have slop for antialasing and hairlines 704bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com devBounds.outset(1, 1); 714bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com inverse.mapRect(localBounds, SkRect::Make(devBounds)); 724bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com return true; 734bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com} 744bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtypedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data); 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) { 804516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com sk_bzero(pixels, bytes); 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {} 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 86a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2)); 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 90a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1)); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) { 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(pixels, data, bytes); 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9741e010cb901c0da9066c4df562030808c9ccd7f8reedstatic BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint, 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t* data) { 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // todo: we can apply colorfilter up front if no shader, so we wouldn't 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need to abort this fastpath 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getShader() || paint.getColorFilter()) { 10296fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 105374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode mode = paint.getBlendMode(); 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkColor color = paint.getColor(); 107a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // collaps modes based on color... 109374772bd61951f01bf84fe17bf53d8867681c9aereed if (SkBlendMode::kSrcOver == mode) { 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com unsigned alpha = SkColorGetA(color); 1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (0 == alpha) { 112374772bd61951f01bf84fe17bf53d8867681c9aereed mode = SkBlendMode::kDst; 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else if (0xFF == alpha) { 114374772bd61951f01bf84fe17bf53d8867681c9aereed mode = SkBlendMode::kSrc; 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 117a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (mode) { 119374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kClear: 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D_Clear_BitmapXferProc\n"); 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D_Clear_BitmapXferProc; // ignore data 122374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kDst: 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D_Dst_BitmapXferProc\n"); 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D_Dst_BitmapXferProc; // ignore data 125374772bd61951f01bf84fe17bf53d8867681c9aereed case SkBlendMode::kSrc: { 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com /* 127a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com should I worry about dithering for the lower depths? 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPMColor pmc = SkPreMultiplyColor(color); 13041e010cb901c0da9066c4df562030808c9ccd7f8reed switch (dst.colorType()) { 13128fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org case kN32_SkColorType: 1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = pmc; 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D32_Src_BitmapXferProc\n"); 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D32_Src_BitmapXferProc; 137900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kRGB_565_SkColorType: 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = SkPixel32ToPixel16(pmc); 1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- D16_Src_BitmapXferProc\n"); 1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return D16_Src_BitmapXferProc; 143900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kAlpha_8_SkColorType: 1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (data) { 1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *data = SkGetPackedA32(pmc); 1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// SkDebugf("--- DA8_Src_BitmapXferProc\n"); 1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return DA8_Src_BitmapXferProc; 1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15796fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16041e010cb901c0da9066c4df562030808c9ccd7f8reedstatic void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc, 16141e010cb901c0da9066c4df562030808c9ccd7f8reed uint32_t procData) { 1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int shiftPerPixel; 16341e010cb901c0da9066c4df562030808c9ccd7f8reed switch (dst.colorType()) { 16428fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org case kN32_SkColorType: 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 2; 1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 167900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kRGB_565_SkColorType: 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 1; 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 170900ecf2f1579d42c9d2959831787af0346320f86reed@google.com case kAlpha_8_SkColorType: 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com shiftPerPixel = 0; 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 1740c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("Can't use xferproc on this config"); 1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17841e010cb901c0da9066c4df562030808c9ccd7f8reed uint8_t* pixels = (uint8_t*)dst.writable_addr(); 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(pixels); 18041e010cb901c0da9066c4df562030808c9ccd7f8reed const size_t rowBytes = dst.rowBytes(); 1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int widthBytes = rect.width() << shiftPerPixel; 1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // skip down to the first scanline and X position 1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel); 1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int scans = rect.height() - 1; scans >= 0; --scans) { 1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(pixels, widthBytes, procData); 1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pixels += rowBytes; 1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawPaint(const SkPaint& paint) const { 192f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 194045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect devRect; 19941e010cb901c0da9066c4df562030808c9ccd7f8reed devRect.set(0, 0, fDst.width(), fDst.height()); 200a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 201045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 202045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com /* If we don't have a shader (i.e. we're just a solid color) we may 203045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com be faster to operate directly on the device bitmap, rather than invoking 204045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com a blitter. Esp. true for xfermodes, which require a colorshader to be 205045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com present, which is just redundant work. Since we're drawing everywhere 206045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com in the clip, we don't have to worry about antialiasing. 207045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com */ 208045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com uint32_t procData = 0; // to avoid the warning 20941e010cb901c0da9066c4df562030808c9ccd7f8reed BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData); 210045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (proc) { 211045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (D_Dst_BitmapXferProc == proc) { // nothing to do 212045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 213045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 214a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 215045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkRegion::Iterator iter(fRC->bwRgn()); 216045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com while (!iter.done()) { 21741e010cb901c0da9066c4df562030808c9ccd7f8reed CallBitmapXferProc(fDst, iter.rect(), proc, procData); 218045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com iter.next(); 219045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 220045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 223045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 224045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com // normal case: use a blitter 22541e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 226045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillIRect(devRect, *fRC, blitter.get()); 2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 2308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct PtProcRec { 2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkCanvas::PointMode fMode; 2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPaint* fPaint; 2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkRegion* fClip; 235045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRasterClip* fRC; 236a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // computed values 2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed fRadius; 239a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count, 2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter*); 2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix, 244045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRasterClip*); 245045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com Proc chooseProc(SkBlitter** blitter); 246045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 247045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comprivate: 248045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper fWrapper; 2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(rec.fClip->isRect()); 2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkIRect& r = rec.fClip->getBounds(); 255a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 2572d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 2582d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (r.contains(x, y)) { 2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitH(x, y, 1); 2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_rect_16_hair_proc(const PtProcRec& rec, 2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPoint devPts[], int count, 2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* blitter) { 268045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkASSERT(rec.fRC->isRect()); 269045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkIRect& r = rec.fRC->getBounds(); 2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t value; 27141e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 27241e010cb901c0da9066c4df562030808c9ccd7f8reed SkASSERT(dst); 273c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 27441e010cb901c0da9066c4df562030808c9ccd7f8reed uint16_t* addr = dst->writable_addr16(0, 0); 27541e010cb901c0da9066c4df562030808c9ccd7f8reed size_t rb = dst->rowBytes(); 276c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 2782d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 2792d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (r.contains(x, y)) { 2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value); 2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2862d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.comstatic void bw_pt_rect_32_hair_proc(const PtProcRec& rec, 2872d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com const SkPoint devPts[], int count, 2882d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkBlitter* blitter) { 2892d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkASSERT(rec.fRC->isRect()); 2902d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com const SkIRect& r = rec.fRC->getBounds(); 2912d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com uint32_t value; 29241e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* dst = blitter->justAnOpaqueColor(&value); 29341e010cb901c0da9066c4df562030808c9ccd7f8reed SkASSERT(dst); 294c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 29541e010cb901c0da9066c4df562030808c9ccd7f8reed SkPMColor* addr = dst->writable_addr32(0, 0); 29641e010cb901c0da9066c4df562030808c9ccd7f8reed size_t rb = dst->rowBytes(); 297c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 2982d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com for (int i = 0; i < count; i++) { 2992d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 3002d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 3012d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (r.contains(x, y)) { 3022d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com ((SkPMColor*)((char*)addr + y * rb))[x] = value; 3032d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 3042d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 3052d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com} 3062d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com 3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 310e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int x = SkScalarFloorToInt(devPts[i].fX); 311e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int y = SkScalarFloorToInt(devPts[i].fY); 3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (rec.fClip->contains(x, y)) { 3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com blitter->blitH(x, y, 1); 3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i += 2) { 3215dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter); 3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3275dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::HairLine(devPts, count, *rec.fRC, blitter); 3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// aa versions 3318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i += 2) { 3355dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter); 3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[], 3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3415dc6b7d1a8bc591d62366ff83c434ff74f3e10fcreed SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter); 3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// square procs (strokeWidth > 0 but matrix is square-scale (sx == sy) 3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[], 3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkFixed radius = rec.fRadius; 3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed x = SkScalarToFixed(devPts[i].fX); 3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed y = SkScalarToFixed(devPts[i].fY); 352c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXRect r; 3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = x - radius; 3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = y - radius; 3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = x + radius; 3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = y + radius; 358c3d7d90973528527131c72549b10c2a21300e0acskia.committer@gmail.com 359045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillXRect(r, *rec.fRC, blitter); 3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[], 3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int count, SkBlitter* blitter) { 3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkFixed radius = rec.fRadius; 3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < count; i++) { 3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed x = SkScalarToFixed(devPts[i].fX); 3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkFixed y = SkScalarToFixed(devPts[i].fY); 369a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkXRect r; 3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = x - radius; 3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = y - radius; 3738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = x + radius; 3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = y + radius; 375a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 376045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::AntiFillXRect(r, *rec.fRC, blitter); 3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 380b4f404ac4195e5b1f49e49c591bd69f98b246f9breed@android.com// If this guy returns true, then chooseProc() must return a valid proc 3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint, 382045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkMatrix* matrix, const SkRasterClip* rc) { 3833ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) { 3843ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang return false; 3853ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang } 3863ece53ed30b934894c87c8adb2a77cfdf2ecfcfeochang 3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getPathEffect()) { 3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar width = paint.getStrokeWidth(); 3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (0 == width) { 3928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = mode; 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPaint = &paint; 39496fcdcc219d2a0d3579719b84b28bede76efba64halcanary fClip = nullptr; 395045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fRC = rc; 3962d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com fRadius = SK_FixedHalf; 3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 399b4f404ac4195e5b1f49e49c591bd69f98b246f9breed@android.com if (paint.getStrokeCap() != SkPaint::kRound_Cap && 4009f2251c73ed6f417dd1057d487bf523e04488440robertphillips matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) { 4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar sx = matrix->get(SkMatrix::kMScaleX); 4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar sy = matrix->get(SkMatrix::kMScaleY); 4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkScalarNearlyZero(sx - sy)) { 4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (sx < 0) { 4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com sx = -sx; 4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMode = mode; 4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPaint = &paint; 41096fcdcc219d2a0d3579719b84b28bede76efba64halcanary fClip = nullptr; 411045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fRC = rc; 412a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed fRadius = SkScalarToFixed(width * sx) >> 1; 4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 419045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comPtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) { 42096fcdcc219d2a0d3579719b84b28bede76efba64halcanary Proc proc = nullptr; 421a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 422045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkBlitter* blitter = *blitterPtr; 423045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 424045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fClip = &fRC->bwRgn(); 425045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 426045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fWrapper.init(*fRC, blitter); 427045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com fClip = &fWrapper.getRgn(); 428045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter = fWrapper.getBlitter(); 429045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com *blitterPtr = blitter; 430045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 431045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // for our arrays 4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(0 == SkCanvas::kPoints_PointMode); 4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(1 == SkCanvas::kLines_PointMode); 4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(2 == SkCanvas::kPolygon_PointMode); 4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode); 4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4382d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (fPaint->isAntiAlias()) { 4392d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (0 == fPaint->getStrokeWidth()) { 4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static const Proc gAAProcs[] = { 4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc 4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com }; 4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = gAAProcs[fMode]; 4442d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) { 4452d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com SkASSERT(SkCanvas::kPoints_PointMode == fMode); 4462d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com proc = aa_square_proc; 4472d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } 4482d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com } else { // BW 4492d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com if (fRadius <= SK_FixedHalf) { // small radii and hairline 4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) { 4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com uint32_t value; 45241e010cb901c0da9066c4df562030808c9ccd7f8reed const SkPixmap* bm = blitter->justAnOpaqueColor(&value); 453900ecf2f1579d42c9d2959831787af0346320f86reed@google.com if (bm && kRGB_565_SkColorType == bm->colorType()) { 4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_pt_rect_16_hair_proc; 45528fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org } else if (bm && kN32_SkColorType == bm->colorType()) { 4562d47a21b27035798d53de4d5cb8ac7c03534ab27reed@google.com proc = bw_pt_rect_32_hair_proc; 4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_pt_rect_hair_proc; 4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com static Proc gBWProcs[] = { 4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc 4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com }; 4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = gBWProcs[fMode]; 4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc = bw_square_proc; 4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return proc; 4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// each of these costs 8-bytes of stack space, so don't make it too large 4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// must be even for lines/polygon to work 4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MAX_DEV_PTS 32 4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, 478f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com const SkPoint pts[], const SkPaint& paint, 47999330ba6227137866a0dbd63478d36f335203ebdMike Reed SkBaseDevice* device) const { 4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // if we're in lines mode, force count to be even 4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkCanvas::kLines_PointMode == mode) { 4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count &= ~(size_t)1; 4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if ((long)count <= 0) { 4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 488a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 48996fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(pts != nullptr); 490f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 491a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 493045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com PtProcRec rec; 49899330ba6227137866a0dbd63478d36f335203ebdMike Reed if (!device && rec.init(mode, paint, fMatrix, fRC)) { 49941e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint devPts[MAX_DEV_PTS]; 5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkMatrix* matrix = fMatrix; 5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBlitter* bltr = blitter.get(); 504045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com PtProcRec::Proc proc = rec.chooseProc(&bltr); 5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // we have to back up subsequent passes if we're in polygon mode 5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const size_t backup = (SkCanvas::kPolygon_PointMode == mode); 507a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 5088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com do { 509a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org int n = SkToInt(count); 5108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (n > MAX_DEV_PTS) { 5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com n = MAX_DEV_PTS; 5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix->mapPoints(devPts, pts, n); 5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(rec, devPts, n, bltr); 5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts += n - backup; 516a8c7f7702fb4bbedb615031bc653c5cd161a038ecommit-bot@chromium.org SkASSERT(SkToInt(count) >= n); 5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count -= n; 5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (count > 0) { 5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count += backup; 5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } while (count != 0); 5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (mode) { 5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kPoints_PointMode: { 5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // temporarily mark the paint as filling. 52640c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkPaint newPaint(paint); 52740c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com newPaint.setStyle(SkPaint::kFill_Style); 5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 52940c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkScalar width = newPaint.getStrokeWidth(); 5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar radius = SkScalarHalf(width); 531a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 53240c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) { 5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath path; 5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix preMatrix; 5357ef849d45a4de02697697ea213bfae7c215a0c38mtklein 5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.addCircle(0, 0, radius); 5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i++) { 5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com preMatrix.setTranslate(pts[i].fX, pts[i].fY); 5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // pass true for the last point, since we can modify 5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // then path then 541b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth path.setIsVolatile((count-1) == i); 54299330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 543a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(path, newPaint, &preMatrix, (count-1) == i); 544f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 545a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed this->drawPath(path, newPaint, &preMatrix, (count-1) == i); 546f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 550a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i++) { 5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fLeft = pts[i].fX - radius; 5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fTop = pts[i].fY - radius; 5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fRight = r.fLeft + width; 5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.fBottom = r.fTop + width; 55699330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 557a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawRect(r, newPaint); 558f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 55940c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com this->drawRect(r, newPaint); 560f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kLines_PointMode: 56649f085dddff10473b6ebf832a974288300224e60bsalomon if (2 == count && paint.getPathEffect()) { 567629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // most likely a dashed line - see if it is one of the ones 568629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // we can accelerate 569629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkStrokeRec rec(paint); 5706d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkPathEffect::PointData pointData; 571629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 572629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkPath path; 573629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com path.moveTo(pts[0]); 574629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com path.lineTo(pts[1]); 575629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 5764bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkRect cullRect = SkRect::Make(fRC->getBounds()); 5774024f32d99b63a599c544a49f526e53c25135159skia.committer@gmail.com 5784bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (paint.getPathEffect()->asPoints(&pointData, path, rec, 5794bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com *fMatrix, &cullRect)) { 5806d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // 'asPoints' managed to find some fast path 5816d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 582629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com SkPaint newP(paint); 58396fcdcc219d2a0d3579719b84b28bede76efba64halcanary newP.setPathEffect(nullptr); 584935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com newP.setStyle(SkPaint::kFill_Style); 585629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com 5866d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (!pointData.fFirst.isEmpty()) { 58799330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 588a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(pointData.fFirst, newP); 5896d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 5906d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPath(pointData.fFirst, newP); 5916d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 592629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 5936d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 5946d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (!pointData.fLast.isEmpty()) { 59599330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 596a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(pointData.fLast, newP); 5976d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 5986d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPath(pointData.fLast, newP); 5996d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6006d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6016d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6026d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (pointData.fSize.fX == pointData.fSize.fY) { 6036d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // The rest of the dashed line can just be drawn as points 6046d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth())); 6056d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6066d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) { 6076d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP.setStrokeCap(SkPaint::kRound_Cap); 6086d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6096d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP.setStrokeCap(SkPaint::kButt_Cap); 6106d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6116d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 61299330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 613a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPoints(SkCanvas::kPoints_PointMode, 614a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed pointData.fNumPoints, 615a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed pointData.fPoints, 616a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed newP); 6176d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6186d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawPoints(SkCanvas::kPoints_PointMode, 6196d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fNumPoints, 6206d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints, 6216d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com newP, 62299330ba6227137866a0dbd63478d36f335203ebdMike Reed device); 6236d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6246d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com break; 625935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com } else { 6266d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com // The rest of the dashed line must be drawn as rects 6277a03d86a3d9adcb13432fbd82039725149487c97skia.committer@gmail.com SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag & 6286d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fFlags)); 6296d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6306d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com SkRect r; 6316d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 6326d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com for (int i = 0; i < pointData.fNumPoints; ++i) { 6336d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com r.set(pointData.fPoints[i].fX - pointData.fSize.fX, 6346d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fY - pointData.fSize.fY, 6356d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fX + pointData.fSize.fX, 6366d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com pointData.fPoints[i].fY + pointData.fSize.fY); 63799330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 638a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawRect(r, newP); 6396d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } else { 6406d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com this->drawRect(r, newP); 6416d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 6426d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com } 643935ad026826fb7d31d562ff7326b84ec3a827456robertphillips@google.com } 6446d87557278052c131957e5d6e093d3a675162d22robertphillips@google.com 645629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com break; 646629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 647629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com } 648629ab540667422d3edcb97c51e9628b7051e1ba4robertphillips@google.com // couldn't take fast path so fall through! 6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case SkCanvas::kPolygon_PointMode: { 6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com count -= 1; 6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath path; 6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPaint p(paint); 6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com p.setStyle(SkPaint::kStroke_Style); 6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1; 655b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth path.setIsVolatile(true); 6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (size_t i = 0; i < count; i += inc) { 6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.moveTo(pts[i]); 6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.lineTo(pts[i+1]); 65999330ba6227137866a0dbd63478d36f335203ebdMike Reed if (device) { 660a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed device->drawPath(path, p, nullptr, true); 661f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } else { 66296fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->drawPath(path, p, nullptr, true); 663f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path.rewind(); 6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6721a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalitastatic inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) { 6731a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkASSERT(matrix.rectStaysRect()); 6741a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkASSERT(SkPaint::kFill_Style != paint.getStyle()); 6751a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 6761a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkVector size; 6771a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() }; 6781a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita matrix.mapVectors(&size, &pt, 1); 6791a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY)); 6801a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita} 6811a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 682761fb62b0eb174783316d2a8b933fba896ca6355reed@google.comstatic bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix, 683761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com SkPoint* strokeSize) { 684761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com if (SkPaint::kMiter_Join != paint.getStrokeJoin() || 685761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com paint.getStrokeMiter() < SK_ScalarSqrt2) { 686761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com return false; 687761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com } 688fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 6891a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita *strokeSize = compute_stroke_size(paint, matrix); 690761fb62b0eb174783316d2a8b933fba896ca6355reed@google.com return true; 6917ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org} 6927ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 69362ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.comSkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint, 69462ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com const SkMatrix& matrix, 69562ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkPoint* strokeSize) { 6967ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org RectType rtype; 6977ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org const SkScalar width = paint.getStrokeWidth(); 69862ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com const bool zeroWidth = (0 == width); 6997ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkPaint::Style style = paint.getStyle(); 700fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7017ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) { 7027ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org style = SkPaint::kFill_Style; 7037ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 704fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getPathEffect() || paint.getMaskFilter() || 70662ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com paint.getRasterizer() || !matrix.rectStaysRect() || 7077ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org SkPaint::kStrokeAndFill_Style == style) { 70862ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com rtype = kPath_RectType; 70962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } else if (SkPaint::kFill_Style == style) { 7107ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kFill_RectType; 7117ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } else if (zeroWidth) { 7127ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kHair_RectType; 71362ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } else if (easy_rect_join(paint, matrix, strokeSize)) { 7147ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kStroke_RectType; 7157ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } else { 7167ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org rtype = kPath_RectType; 7177ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org } 71862ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com return rtype; 71962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com} 72062ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7217324415759fe0c5a0902877b664aa942a89bd940reed@google.comstatic const SkPoint* rect_points(const SkRect& r) { 722fc2f0d0e6e6f72503ff9504296556dc637059c15reed@google.com return SkTCast<const SkPoint*>(&r); 7237324415759fe0c5a0902877b664aa942a89bd940reed@google.com} 7247324415759fe0c5a0902877b664aa942a89bd940reed@google.com 7257324415759fe0c5a0902877b664aa942a89bd940reed@google.comstatic SkPoint* rect_points(SkRect& r) { 726fc2f0d0e6e6f72503ff9504296556dc637059c15reed@google.com return SkTCast<SkPoint*>(&r); 72740c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com} 72840c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com 7290393912de72bc3d8b3640c122c53470dd0da1e6dreedvoid SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint, 7300393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkMatrix* paintMatrix, const SkRect* postPaintRect) const { 73162ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkDEBUGCODE(this->validate();) 7327ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org 73362ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com // nothing to draw 734045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 73562ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com return; 73662ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com } 73762ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7380393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkMatrix* matrix; 7390393912de72bc3d8b3640c122c53470dd0da1e6dreed SkMatrix combinedMatrixStorage; 7400393912de72bc3d8b3640c122c53470dd0da1e6dreed if (paintMatrix) { 7410393912de72bc3d8b3640c122c53470dd0da1e6dreed SkASSERT(postPaintRect); 7420393912de72bc3d8b3640c122c53470dd0da1e6dreed combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix); 7430393912de72bc3d8b3640c122c53470dd0da1e6dreed matrix = &combinedMatrixStorage; 7440393912de72bc3d8b3640c122c53470dd0da1e6dreed } else { 7450393912de72bc3d8b3640c122c53470dd0da1e6dreed SkASSERT(!postPaintRect); 7460393912de72bc3d8b3640c122c53470dd0da1e6dreed matrix = fMatrix; 7470393912de72bc3d8b3640c122c53470dd0da1e6dreed } 7480393912de72bc3d8b3640c122c53470dd0da1e6dreed 74962ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com SkPoint strokeSize; 75062ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize); 75162ab7addb06bbc5b93460eaf2f70a9f8399308d3reed@google.com 7527ff678bc1618dc669648198a7bdca8adfb189505mike@reedtribe.org if (kPath_RectType == rtype) { 7530393912de72bc3d8b3640c122c53470dd0da1e6dreed SkDraw draw(*this); 7540393912de72bc3d8b3640c122c53470dd0da1e6dreed if (paintMatrix) { 7550393912de72bc3d8b3640c122c53470dd0da1e6dreed draw.fMatrix = matrix; 7560393912de72bc3d8b3640c122c53470dd0da1e6dreed } 7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath tmp; 7580393912de72bc3d8b3640c122c53470dd0da1e6dreed tmp.addRect(prePaintRect); 7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.setFillType(SkPath::kWinding_FillType); 76096fcdcc219d2a0d3579719b84b28bede76efba64halcanary draw.drawPath(tmp, paint, nullptr, true); 7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7640393912de72bc3d8b3640c122c53470dd0da1e6dreed SkRect devRect; 7651a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect; 7661a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita // skip the paintMatrix when transforming the rect by the CTM 7671a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2); 7687324415759fe0c5a0902877b664aa942a89bd940reed@google.com devRect.sort(); 7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // look for the quick exit, before we build a blitter 7711a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkRect bbox = devRect; 7721c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.getStyle() != SkPaint::kFill_Style) { 7731c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // extra space for hairlines 774b3eba478d5bed5fb2b5f0f224738c8c292cebf36george if (paint.getStrokeWidth() == 0) { 7751a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita bbox.outset(1, 1); 776b3eba478d5bed5fb2b5f0f224738c8c292cebf36george } else { 7771a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita // For kStroke_RectType, strokeSize is already computed. 7781a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita const SkPoint& ssize = (kStroke_RectType == rtype) 7791a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita ? strokeSize 7801a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita : compute_stroke_size(paint, *fMatrix); 7811a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y())); 782b3eba478d5bed5fb2b5f0f224738c8c292cebf36george } 7831c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 7841a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita 7851a178ca6dd2ff7f62c684f7d0ee94e54fc31c91bfmalita SkIRect ir = bbox.roundOut(); 7861c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (fRC->quickReject(ir)) { 7871c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com return; 7888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 79041e010cb901c0da9066c4df562030808c9ccd7f8reed SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias()); 7911c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com while (looper.next()) { 7921c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkRect localDevRect; 7931c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com looper.mapRect(&localDevRect, devRect); 7941c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkMatrix localMatrix; 7950393912de72bc3d8b3640c122c53470dd0da1e6dreed looper.mapMatrix(&localMatrix, *matrix); 7961c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com 79741e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint); 7981c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com const SkRasterClip& clip = looper.getRC(); 7991c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkBlitter* blitter = blitterStorage.get(); 8001c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com 8011c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter 8021c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // case we are also hairline (if we've gotten to here), which devolves to 8031c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com // effectively just kFill 8041c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com switch (rtype) { 8051c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kFill_RectType: 8061c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8071c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiFillRect(localDevRect, clip, blitter); 8081c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8091c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::FillRect(localDevRect, clip, blitter); 8101c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8111c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8121c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kStroke_RectType: 8131c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8141c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter); 8151c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8161c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::FrameRect(localDevRect, strokeSize, clip, blitter); 8171c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8181c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8191c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com case kHair_RectType: 8201c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com if (paint.isAntiAlias()) { 8211c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::AntiHairRect(localDevRect, clip, blitter); 8221c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } else { 8231c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkScan::HairRect(localDevRect, clip, blitter); 8241c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8251c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com break; 8261c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com default: 8271c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com SkDEBUGFAIL("bad rtype"); 8281c028bd395dc52ca12b99f85f0c297d15a288c2dreed@google.com } 8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const { 8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (srcM.fBounds.isEmpty()) { 8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 8358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8370a60b3d32eae945688b69599f11679662657f751bungeman@google.com const SkMask* mask = &srcM; 8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8390a60b3d32eae945688b69599f11679662657f751bungeman@google.com SkMask dstM; 8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (paint.getMaskFilter() && 841e80eb928ba0248a5a5dea6e1f0005aa08ecf8740robertphillips paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, nullptr)) { 8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask = &dstM; 8438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 84402f55841854ae32f21a13417e9ee711463e488cfbungeman@google.com SkAutoMaskFreeImage ami(dstM.fImage); 8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 84641e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 847045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkBlitter* blitter = blitterChooser.get(); 848045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 849045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkAAClipBlitterWrapper wrapper; 850045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkRegion* clipRgn; 8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 852045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isBW()) { 853045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clipRgn = &fRC->bwRgn(); 854045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 855045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com wrapper.init(*fRC, blitter); 856045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clipRgn = &wrapper.getRgn(); 857045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter = wrapper.getBlitter(); 858045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 859045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com blitter->blitMaskRegion(*mask, *clipRgn); 8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 862ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.comstatic SkScalar fast_len(const SkVector& vec) { 863ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar x = SkScalarAbs(vec.fX); 864ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar y = SkScalarAbs(vec.fY); 865ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com if (x < y) { 866ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkTSwap(x, y); 867ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 868ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return x + SkScalarHalf(y); 869ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com} 870ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com 871e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.orgbool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix, 872e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org SkScalar* coverage) { 873e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org SkASSERT(strokeWidth > 0); 874e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org // We need to try to fake a thick-stroke with a modulated hairline. 875ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com 8768d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com if (matrix.hasPerspective()) { 877ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return false; 878ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 879ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com 880ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkVector src[2], dst[2]; 881ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com src[0].set(strokeWidth, 0); 882ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com src[1].set(0, strokeWidth); 883ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com matrix.mapVectors(dst, src, 2); 884ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar len0 = fast_len(dst[0]); 885ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com SkScalar len1 = fast_len(dst[1]); 886652807bbc8c57e5fa9622126b51fd369f5c67935agl@chromium.org if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) { 88749f085dddff10473b6ebf832a974288300224e60bsalomon if (coverage) { 888e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org *coverage = SkScalarAve(len0, len1); 889e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org } 890ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return true; 891ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com } 892ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com return false; 893ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com} 894ebdeeb8a018f2df01e190fd961d68a94f0e0fcb9reed@android.com 895a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comvoid SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const { 896a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkDEBUGCODE(this->validate()); 897a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 898a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (fRC->isEmpty()) { 899a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com return; 900a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 901a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 902a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com { 903a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // TODO: Investigate optimizing these options. They are in the same 904a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // order as SkDraw::drawPath, which handles each case. It may be 905a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // that there is no way to optimize for these using the SkRRect path. 906a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkScalar coverage; 907a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) { 908a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 909a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 910a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 911a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { 912a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 913a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 914a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 915a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getRasterizer()) { 916a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com goto DRAW_PATH; 917a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 918a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 919a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 920a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (paint.getMaskFilter()) { 921a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // Transform the rrect into device space. 922a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkRRect devRRect; 923a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com if (rrect.transform(*fMatrix, &devRRect)) { 92441e010cb901c0da9066c4df562030808c9ccd7f8reed SkAutoBlitterChoose blitter(fDst, *fMatrix, paint); 925055e192adc0072ae2548ef5431ceee652945f9c2bsalomon if (paint.getMaskFilter()->filterRRect(devRRect, *fMatrix, *fRC, blitter.get())) { 926a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com return; // filterRRect() called the blitter, so we're done 927a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 928a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 929a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com } 930a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 931a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.comDRAW_PATH: 932a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com // Now fall back to the default case of using a path. 933a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com SkPath path; 934a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com path.addRRect(rrect); 93596fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->drawPath(path, paint, nullptr, true); 936a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com} 937a8e33a92e27ca1523601226cad83c79a7e00c93bscroggo@google.com 9381a7eb266644d2e1b0968dbca606ca0a91903419dcaryclarkSkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) { 93905d9044de4f1c6e791df66a425638752daac4c6breed if (!matrix.hasPerspective()) { 94005d9044de4f1c6e791df66a425638752daac4c6breed SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); 94105d9044de4f1c6e791df66a425638752daac4c6breed SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); 94205d9044de4f1c6e791df66a425638752daac4c6breed if (SkScalarsAreFinite(sx, sy)) { 943a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman SkScalar scale = SkTMax(sx, sy); 944a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman if (scale > 0) { 945a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman return scale; 946a4b8704e76cb2136a3ff8c1553690f30b96870e0lsalzman } 94705d9044de4f1c6e791df66a425638752daac4c6breed } 94805d9044de4f1c6e791df66a425638752daac4c6breed } 94905d9044de4f1c6e791df66a425638752daac4c6breed return 1; 95005d9044de4f1c6e791df66a425638752daac4c6breed} 95105d9044de4f1c6e791df66a425638752daac4c6breed 95282595b6fa4733e1525f357bdcac22db058790550reedvoid SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage, 95382595b6fa4733e1525f357bdcac22db058790550reed SkBlitter* customBlitter, bool doFill) const { 95401a2ff8a325e17221b139968e337413df0c2e60creed // Do a conservative quick-reject test, since a looper or other modifier may have moved us 95501a2ff8a325e17221b139968e337413df0c2e60creed // out of range. 95601a2ff8a325e17221b139968e337413df0c2e60creed if (!devPath.isInverseFillType()) { 95701a2ff8a325e17221b139968e337413df0c2e60creed // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't 95801a2ff8a325e17221b139968e337413df0c2e60creed // appear empty to the intersects call. This also gives us slop in case we're antialiasing 95901a2ff8a325e17221b139968e337413df0c2e60creed SkRect pathBounds = devPath.getBounds().makeOutset(1, 1); 96001a2ff8a325e17221b139968e337413df0c2e60creed 96101a2ff8a325e17221b139968e337413df0c2e60creed if (paint.getMaskFilter()) { 96201a2ff8a325e17221b139968e337413df0c2e60creed paint.getMaskFilter()->computeFastBounds(pathBounds, &pathBounds); 96301a2ff8a325e17221b139968e337413df0c2e60creed 96401a2ff8a325e17221b139968e337413df0c2e60creed // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed 96501a2ff8a325e17221b139968e337413df0c2e60creed // we can remove this hack. See skbug.com/5542 96601a2ff8a325e17221b139968e337413df0c2e60creed pathBounds.outset(7, 7); 96701a2ff8a325e17221b139968e337413df0c2e60creed } 96801a2ff8a325e17221b139968e337413df0c2e60creed 96901a2ff8a325e17221b139968e337413df0c2e60creed // Now compare against the clip's bounds 97001a2ff8a325e17221b139968e337413df0c2e60creed if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) { 97101a2ff8a325e17221b139968e337413df0c2e60creed return; 97201a2ff8a325e17221b139968e337413df0c2e60creed } 97301a2ff8a325e17221b139968e337413df0c2e60creed } 97401a2ff8a325e17221b139968e337413df0c2e60creed 97582595b6fa4733e1525f357bdcac22db058790550reed SkBlitter* blitter = nullptr; 97682595b6fa4733e1525f357bdcac22db058790550reed SkAutoBlitterChoose blitterStorage; 97782595b6fa4733e1525f357bdcac22db058790550reed if (nullptr == customBlitter) { 97882595b6fa4733e1525f357bdcac22db058790550reed blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage); 97982595b6fa4733e1525f357bdcac22db058790550reed blitter = blitterStorage.get(); 98082595b6fa4733e1525f357bdcac22db058790550reed } else { 98182595b6fa4733e1525f357bdcac22db058790550reed blitter = customBlitter; 98282595b6fa4733e1525f357bdcac22db058790550reed } 98382595b6fa4733e1525f357bdcac22db058790550reed 98482595b6fa4733e1525f357bdcac22db058790550reed if (paint.getMaskFilter()) { 98582595b6fa4733e1525f357bdcac22db058790550reed SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle 98682595b6fa4733e1525f357bdcac22db058790550reed : SkStrokeRec::kHairline_InitStyle; 98782595b6fa4733e1525f357bdcac22db058790550reed if (paint.getMaskFilter()->filterPath(devPath, *fMatrix, *fRC, blitter, style)) { 98882595b6fa4733e1525f357bdcac22db058790550reed return; // filterPath() called the blitter, so we're done 98982595b6fa4733e1525f357bdcac22db058790550reed } 99082595b6fa4733e1525f357bdcac22db058790550reed } 99182595b6fa4733e1525f357bdcac22db058790550reed 99282595b6fa4733e1525f357bdcac22db058790550reed void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*); 99382595b6fa4733e1525f357bdcac22db058790550reed if (doFill) { 99482595b6fa4733e1525f357bdcac22db058790550reed if (paint.isAntiAlias()) { 99582595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiFillPath; 99682595b6fa4733e1525f357bdcac22db058790550reed } else { 99782595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::FillPath; 99882595b6fa4733e1525f357bdcac22db058790550reed } 99982595b6fa4733e1525f357bdcac22db058790550reed } else { // hairline 100082595b6fa4733e1525f357bdcac22db058790550reed if (paint.isAntiAlias()) { 100182595b6fa4733e1525f357bdcac22db058790550reed switch (paint.getStrokeCap()) { 100282595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kButt_Cap: 100382595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairPath; 100482595b6fa4733e1525f357bdcac22db058790550reed break; 100582595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kSquare_Cap: 100682595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairSquarePath; 100782595b6fa4733e1525f357bdcac22db058790550reed break; 100882595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kRound_Cap: 100982595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::AntiHairRoundPath; 101082595b6fa4733e1525f357bdcac22db058790550reed break; 101182595b6fa4733e1525f357bdcac22db058790550reed default: 101282595b6fa4733e1525f357bdcac22db058790550reed proc SK_INIT_TO_AVOID_WARNING; 101382595b6fa4733e1525f357bdcac22db058790550reed SkDEBUGFAIL("unknown paint cap type"); 101482595b6fa4733e1525f357bdcac22db058790550reed } 101582595b6fa4733e1525f357bdcac22db058790550reed } else { 101682595b6fa4733e1525f357bdcac22db058790550reed switch (paint.getStrokeCap()) { 101782595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kButt_Cap: 101882595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairPath; 101982595b6fa4733e1525f357bdcac22db058790550reed break; 102082595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kSquare_Cap: 102182595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairSquarePath; 102282595b6fa4733e1525f357bdcac22db058790550reed break; 102382595b6fa4733e1525f357bdcac22db058790550reed case SkPaint::kRound_Cap: 102482595b6fa4733e1525f357bdcac22db058790550reed proc = SkScan::HairRoundPath; 102582595b6fa4733e1525f357bdcac22db058790550reed break; 102682595b6fa4733e1525f357bdcac22db058790550reed default: 102782595b6fa4733e1525f357bdcac22db058790550reed proc SK_INIT_TO_AVOID_WARNING; 102882595b6fa4733e1525f357bdcac22db058790550reed SkDEBUGFAIL("unknown paint cap type"); 102982595b6fa4733e1525f357bdcac22db058790550reed } 103082595b6fa4733e1525f357bdcac22db058790550reed } 103182595b6fa4733e1525f357bdcac22db058790550reed } 103282595b6fa4733e1525f357bdcac22db058790550reed proc(devPath, *fRC, blitter); 103382595b6fa4733e1525f357bdcac22db058790550reed} 103482595b6fa4733e1525f357bdcac22db058790550reed 103532e5d97ccf60f859db063ebd6e903c362e625767reed@google.comvoid SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, 1036126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com const SkMatrix* prePathMatrix, bool pathIsMutable, 103753f0959fc024c56dc55fe6bf86380127b59abec9krajcevski bool drawCoverage, SkBlitter* customBlitter) const { 1038f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 10398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1041045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty()) { 10428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 10438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* pathPtr = (SkPath*)&origSrcPath; 10468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool doFill = true; 10478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath tmpPath; 10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix tmpMatrix; 10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkMatrix* matrix = fMatrix; 1050b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth tmpPath.setIsVolatile(true); 10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 10528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (prePathMatrix) { 105332e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style || 105432e5d97ccf60f859db063ebd6e903c362e625767reed@google.com origPaint.getRasterizer()) { 10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* result = pathPtr; 1056a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!pathIsMutable) { 10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com result = &tmpPath; 10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathIsMutable = true; 10608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr->transform(*prePathMatrix, result); 10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr = result; 10638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 106492362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org tmpMatrix.setConcat(*matrix, *prePathMatrix); 10658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix = &tmpMatrix; 10668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // at this point we're done with prePathMatrix 10698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1070a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 10715dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1072a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1073ecadf99c8450646dfd9c2754f3e845245beab8b6reed@google.com { 1074dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com SkScalar coverage; 1075dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) { 1076dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com if (SK_Scalar1 == coverage) { 10775dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com paint.writable()->setStrokeWidth(0); 1078374772bd61951f01bf84fe17bf53d8867681c9aereed } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) { 1079dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com U8CPU newAlpha; 1080dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#if 0 1081dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com newAlpha = SkToU8(SkScalarRoundToInt(coverage * 1082dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com origPaint.getAlpha())); 1083dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#else 1084dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // this is the old technique, which we preserve for now so 1085dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // we don't change previous results (testing) 1086dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com // the new way seems fine, its just (a tiny bit) different 1087a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed int scale = (int)(coverage * 256); 1088dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com newAlpha = origPaint.getAlpha() * scale >> 8; 1089dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com#endif 10905dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com SkPaint* writablePaint = paint.writable(); 10915dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com writablePaint->setStrokeWidth(0); 10925dc26b97366934ba0f896cea02a3fec027d5d5c1bsalomon@google.com writablePaint->setAlpha(newAlpha); 1093dd1be60702b3622f49d97651e31d13eaf2175cf8bsalomon@google.com } 10948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 10958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1096a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 109732e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) { 10984bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com SkRect cullRect; 109996fcdcc219d2a0d3579719b84b28bede76efba64halcanary const SkRect* cullRectPtr = nullptr; 11004bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com if (this->computeConservativeLocalClipBounds(&cullRect)) { 11014bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com cullRectPtr = &cullRect; 11024bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com } 110305d9044de4f1c6e791df66a425638752daac4c6breed doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr, 11041a7eb266644d2e1b0968dbca606ca0a91903419dcaryclark ComputeResScaleForStroking(*fMatrix)); 11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr = &tmpPath; 11068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1107a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 110832e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getRasterizer()) { 11098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 111032e5d97ccf60f859db063ebd6e903c362e625767reed@google.com if (paint->getRasterizer()->rasterize(*pathPtr, *matrix, 1111045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com &fRC->getBounds(), paint->getMaskFilter(), &mask, 11128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 111332e5d97ccf60f859db063ebd6e903c362e625767reed@google.com this->drawDevMask(mask, *paint); 11148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask::FreeImage(mask.fImage); 11158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // avoid possibly allocating a new path in transform if we can 11208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 11218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // transform the path into device space 11238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pathPtr->transform(*matrix, devPathPtr); 11248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 112582595b6fa4733e1525f357bdcac22db058790550reed this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill); 11268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 11278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 112882595b6fa4733e1525f357bdcac22db058790550reedvoid SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { 1129900ecf2f1579d42c9d2959831787af0346320f86reed@google.com SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); 11308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1131c7e211acd0c9201688de7ff0c9a2271c67440adffmalita if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { 1132e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); 1133e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); 11348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11354edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 11364edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1137a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com return; 1138a641f3f18e5319773989812a888f3fad49e4f2adreed@google.com } 11398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 114092fc2ae58331662ec411a048686cb4801e0a909areed mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height()); 11418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fFormat = SkMask::kA8_Format; 114292fc2ae58331662ec411a048686cb4801e0a909areed mask.fRowBytes = SkToU32(pmap.rowBytes()); 114392fc2ae58331662ec411a048686cb4801e0a909areed // fImage is typed as writable, but in this case it is used read-only 114492fc2ae58331662ec411a048686cb4801e0a909areed mask.fImage = (uint8_t*)pmap.addr8(0, 0); 1145a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawDevMask(mask, paint); 11478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { // need to xform the bitmap first 11488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 11498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMask mask; 1150a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(0, 0, 11528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMatrix->mapRect(&r); 11548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.round(&mask.fBounds); 1155a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // set the mask's bounds to the transformed bitmap-bounds, 11578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // clipped to the actual device 11588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 11598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect devBounds; 116041e010cb901c0da9066c4df562030808c9ccd7f8reed devBounds.set(0, 0, fDst.width(), fDst.height()); 11618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need intersect(l, t, r, b) on irect 11628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!mask.fBounds.intersect(devBounds)) { 11638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 11648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1166543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com 11678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fFormat = SkMask::kA8_Format; 11688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask.fRowBytes = SkAlign4(mask.fBounds.width()); 1169543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com size_t size = mask.computeImageSize(); 1170543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com if (0 == size) { 1171543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com // the mask is too big to allocated, draw nothing 1172543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com return; 1173543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com } 11748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // allocate (and clear) our temp buffer to hold the transformed bitmap 1176565901db954c231840750ea955ed31b820b9ade8scroggo SkAutoTMalloc<uint8_t> storage(size); 1177565901db954c231840750ea955ed31b820b9ade8scroggo mask.fImage = storage.get(); 11788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(mask.fImage, 0, size); 1179a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now draw our bitmap(src) into mask(dst), transformed by the matrix 11818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 11828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkBitmap device; 1183a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()), 1184a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org mask.fImage, mask.fRowBytes); 1185a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 11868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkCanvas c(device); 11878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need the unclipped top/left for the translate 11888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com c.translate(-SkIntToScalar(mask.fBounds.fLeft), 11898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com -SkIntToScalar(mask.fBounds.fTop)); 11908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com c.concat(*fMatrix); 11913469c76c40790b409621fd7eff34f56240718549reed@android.com 11923469c76c40790b409621fd7eff34f56240718549reed@android.com // We can't call drawBitmap, or we'll infinitely recurse. Instead 1193fb12c3e6ba84f95dc15fbaddc239dede0ba1d60ereed@android.com // we manually build a shader and draw that into our new mask 11943469c76c40790b409621fd7eff34f56240718549reed@android.com SkPaint tmpPaint; 11953469c76c40790b409621fd7eff34f56240718549reed@android.com tmpPaint.setFlags(paint.getFlags()); 119666a96d07d5583cc018cb70127bd5483799b69d0ebrianosman tmpPaint.setFilterQuality(paint.getFilterQuality()); 11974bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap); 11983469c76c40790b409621fd7eff34f56240718549reed@android.com SkRect rr; 11993469c76c40790b409621fd7eff34f56240718549reed@android.com rr.set(0, 0, SkIntToScalar(bitmap.width()), 12003469c76c40790b409621fd7eff34f56240718549reed@android.com SkIntToScalar(bitmap.height())); 12014bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby c.drawRect(rr, paintWithShader); 12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawDevMask(mask, paint); 12048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1207045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comstatic bool clipped_out(const SkMatrix& m, const SkRasterClip& c, 12088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkRect& srcR) { 12098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect dstR; 12108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com m.mapRect(&dstR, srcR); 1211b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed return c.quickReject(dstR.roundOut()); 12128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1214045e62d715f5ee9b03deb5af3c750f8318096179reed@google.comstatic bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip, 12158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int width, int height) { 12168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 12178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height)); 12188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return clipped_out(matrix, clip, r); 12198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1221c240e719b2bebd3711ade4e6fe056921aa7b0521reedstatic bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) { 1222c240e719b2bebd3711ade4e6fe056921aa7b0521reed return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height()); 1223045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com} 1224045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com 12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, 12260393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkRect* dstBounds, const SkPaint& origPaint) const { 1227f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 12288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1230045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty() || 12318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bitmap.width() == 0 || bitmap.height() == 0 || 1232900ecf2f1579d42c9d2959831787af0346320f86reed@google.com bitmap.colorType() == kUnknown_SkColorType) { 12338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1235a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 1236f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita SkTCopyOnFirstWrite<SkPaint> paint(origPaint); 1237f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita if (origPaint.getStyle() != SkPaint::kFill_Style) { 1238f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita paint.writable()->setStyle(SkPaint::kFill_Style); 1239f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita } 1240a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 124292362383a4de7b0d819c88fa8b74242bb2507602commit-bot@chromium.org matrix.setConcat(*fMatrix, prematrix); 12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1244045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) { 12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1248c7e211acd0c9201688de7ff0c9a2271c67440adffmalita if (bitmap.colorType() != kAlpha_8_SkColorType 1249f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) { 1250f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // 1251f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // It is safe to call lock pixels now, since we know the matrix is 1252f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // (more or less) identity. 1253f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com // 12544edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 12554edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1256f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com return; 1257f7ef56d9104fc651769760df9d5f861ef36de658reed@google.com } 1258e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int ix = SkScalarRoundToInt(matrix.getTranslateX()); 1259e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com int iy = SkScalarRoundToInt(matrix.getTranslateY()); 1260c240e719b2bebd3711ade4e6fe056921aa7b0521reed if (clipHandlesSprite(*fRC, ix, iy, pmap)) { 126157bfa0209e3379385b7ef6217cafb22ca83836c8Herb Derby char storage[kSkBlitterContextSize]; 126257bfa0209e3379385b7ef6217cafb22ca83836c8Herb Derby SkArenaAlloc allocator{storage}; 1263a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org // blitter will be owned by the allocator. 1264f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator); 1265045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (blitter) { 1266c240e719b2bebd3711ade4e6fe056921aa7b0521reed SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()), 1267c240e719b2bebd3711ade4e6fe056921aa7b0521reed *fRC, blitter); 1268045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com return; 12698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1270c240e719b2bebd3711ade4e6fe056921aa7b0521reed // if !blitter, then we fall-through to the slower case 12718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1273a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // now make a temp draw on the stack, and use it 12758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // 12768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDraw draw(*this); 12778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 1278a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 127970ac8a9d091d385bf5244125159c4d8509a0c470Matt Sarett if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) { 1280f85d2a4fa1b71e6ee28518431e2a34df5683bc81fmalita draw.drawBitmapAsMask(bitmap, *paint); 12818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 12824bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(*paint, bitmap); 12830393912de72bc3d8b3640c122c53470dd0da1e6dreed const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 12840393912de72bc3d8b3640c122c53470dd0da1e6dreed if (dstBounds) { 12850393912de72bc3d8b3640c122c53470dd0da1e6dreed this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds); 12860393912de72bc3d8b3640c122c53470dd0da1e6dreed } else { 12870393912de72bc3d8b3640c122c53470dd0da1e6dreed draw.drawRect(srcBounds, paintWithShader); 12880393912de72bc3d8b3640c122c53470dd0da1e6dreed } 12898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1292c240e719b2bebd3711ade4e6fe056921aa7b0521reedvoid SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const { 1293f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 1294a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 12958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 1296045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->isEmpty() || 12978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bitmap.width() == 0 || bitmap.height() == 0 || 1298900ecf2f1579d42c9d2959831787af0346320f86reed@google.com bitmap.colorType() == kUnknown_SkColorType) { 12998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1302c240e719b2bebd3711ade4e6fe056921aa7b0521reed const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1304045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com if (fRC->quickReject(bounds)) { 13058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; // nothing to draw 13068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 130840c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com SkPaint paint(origPaint); 130940c2ba27b6e5c6a4b6c073264f8c0a7c86355abereed@google.com paint.setStyle(SkPaint::kFill_Style); 13108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13114edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed SkPixmap pmap; 13124edb5d219eb99aa1e8fbe5e37260d3b34314e54bMike Reed if (!bitmap.peekPixels(&pmap)) { 1313c240e719b2bebd3711ade4e6fe056921aa7b0521reed return; 1314c240e719b2bebd3711ade4e6fe056921aa7b0521reed } 1315c240e719b2bebd3711ade4e6fe056921aa7b0521reed 131696fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) { 1317a5572e5bb2a2bbeeb59de0741c2527869d365a0ccommit-bot@chromium.org // blitter will be owned by the allocator. 131857bfa0209e3379385b7ef6217cafb22ca83836c8Herb Derby char storage[kSkBlitterContextSize]; 131957bfa0209e3379385b7ef6217cafb22ca83836c8Herb Derby SkArenaAlloc allocator{storage}; 132041e010cb901c0da9066c4df562030808c9ccd7f8reed SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator); 13218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (blitter) { 1322045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkScan::FillIRect(bounds, *fRC, blitter); 13238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 13248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRect r; 13298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // get a scalar version of our rect 13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com r.set(bounds); 13328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13339c9005a347e9996f357bd79591bd34f74f8bbc66commit-bot@chromium.org // create shader with offset 13348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(r.fLeft, r.fTop); 13354bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix); 13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDraw draw(*this); 13378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.reset(); 13388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 13398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // call ourself with a rect 1340a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com // is this OK if paint has a rasterizer? 13414bf560a056d7ba5b3051ebc87e687d4997928ff6Herb Derby draw.drawRect(r, paintWithShader); 13428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 13438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 13458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13467120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed#include "SkPaintPriv.h" 13478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalerContext.h" 13488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkGlyphCache.h" 1349e69137620ab0b5b40d230318c8e11b822f63cb9dreed@google.com#include "SkTextToPathIter.h" 13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkUtils.h" 13518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13528128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.orgbool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm) { 13538128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org // hairline glyphs are fast enough so we don't need to cache them 13548128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) { 13558128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org return true; 13568128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org } 13578128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 13588128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org // we don't cache perspective 13598128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org if (ctm.hasPerspective()) { 13608128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org return true; 13618128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org } 13628128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 13638128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org SkMatrix textM; 13647120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed SkPaintPriv::MakeTextMatrix(&textM, paint); 13657120b2d577d3aab1f51c5af1530a68c57ca51696Mike Reed return SkPaint::TooBigToUseCache(ctm, textM); 13668128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org} 13678128d8c119382279918b90ad8d80ccb3aaebb8a0commit-bot@chromium.org 136899330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y, 13698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPaint& paint) const { 1370f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 13718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1372166e653f67f3fffc3846184a25ce45ab083f07a2djsollen@google.com SkTextToPathIter iter(text, byteLength, paint, true); 13738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 13758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setScale(iter.getPathScale(), iter.getPathScale()); 13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.postTranslate(x, y); 13778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkPath* iterPath; 13798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar xpos, prevXPos = 0; 13808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13817b4531f64cbd85d32a77ceab1bdec8335c5a7864reed@google.com while (iter.next(&iterPath, &xpos)) { 13828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.postTranslate(xpos - prevXPos, 0); 13837b4531f64cbd85d32a77ceab1bdec8335c5a7864reed@google.com if (iterPath) { 1384a1361364e64138adda3dc5f71d50d7503838bb6dMike Reed this->drawPath(*iterPath, iter.getPaint(), &matrix, false); 1385f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com } 13868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com prevXPos = xpos; 13878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 13888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 13898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 13908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// disable warning : local variable used without having been initialized 1391d7dc76f7e99309cbd09a5420c22e55b951067debbungeman#if defined _WIN32 13928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( push ) 13938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( disable : 4701 ) 13948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 13958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1396f553e4e09cd2baf15fc041daab8a08bd46e352f0herb//////////////////////////////////////////////////////////////////////////////////////////////////// 13972e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1398d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbclass DrawOneGlyph { 1399d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbpublic: 1400d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) 1401d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) 1402d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fGlyphCache(cache) 1403d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fBlitter(blitter) 1404d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) 1405d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fDraw(draw) 1406d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fPaint(paint) 1407d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb , fClipBounds(PickClipBounds(draw)) { } 1408d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1409d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1410d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb position += rounding; 1411d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // Prevent glyphs from being drawn outside of or straddling the edge of device space. 1412875e13ca0990e32da9db639743a913efe77f7e89mtklein // Comparisons written a little weirdly so that NaN coordinates are treated safely. 1413875e13ca0990e32da9db639743a913efe77f7e89mtklein auto gt = [](float a, int b) { return !(a <= (float)b); }; 1414875e13ca0990e32da9db639743a913efe77f7e89mtklein auto lt = [](float a, int b) { return !(a >= (float)b); }; 1415875e13ca0990e32da9db639743a913efe77f7e89mtklein if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1416875e13ca0990e32da9db639743a913efe77f7e89mtklein lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) || 1417875e13ca0990e32da9db639743a913efe77f7e89mtklein gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) || 1418875e13ca0990e32da9db639743a913efe77f7e89mtklein lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) { 1419d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return; 1420d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1421d095f2bf06ca810844233bea9fb06de585643b32bungeman 142277a9cc1dead147fc547895d3725d9ee2150cda73benjaminwagner int left = SkScalarFloorToInt(position.fX); 142377a9cc1dead147fc547895d3725d9ee2150cda73benjaminwagner int top = SkScalarFloorToInt(position.fY); 1424d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 14258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1426d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb left += glyph.fLeft; 1427d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb top += glyph.fTop; 14288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1429d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb int right = left + glyph.fWidth; 1430d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb int bottom = top + glyph.fHeight; 14318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1432d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkMask mask; 1433d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask.fBounds.set(left, top, right, bottom); 1434875e13ca0990e32da9db639743a913efe77f7e89mtklein SkASSERT(!mask.fBounds.isEmpty()); 143583a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1436d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (fUseRegionToDraw) { 1437d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkRegion::Cliperator clipper(*fClip, mask.fBounds); 143883a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1439d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!clipper.done() && this->getImageData(glyph, &mask)) { 1440d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkIRect& cr = clipper.rect(); 1441d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb do { 1442d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb this->blitMask(mask, cr); 1443d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb clipper.next(); 1444d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } while (!clipper.done()); 1445d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1446d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } else { 1447d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkIRect storage; 1448d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkIRect* bounds = &mask.fBounds; 1449d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1450d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // this extra test is worth it, assuming that most of the time it succeeds 1451d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb // since we can avoid writing to storage 1452d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { 1453d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) 1454d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return; 1455d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bounds = &storage; 1456d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 145783a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com 1458d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (this->getImageData(glyph, &mask)) { 1459d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb this->blitMask(mask, *bounds); 1460d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1461cd7f03597475ea423aa819bdae03996b26874dd5herb } 146283a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com } 14638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1464d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herbprivate: 1465d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb static bool UsingRegionToDraw(const SkRasterClip* rClip) { 1466d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rClip->isBW() && !rClip->isRect(); 1467d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 14682e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1469d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb static SkIRect PickClipBounds(const SkDraw& draw) { 1470d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkRasterClip& rasterClip = *draw.fRC; 14712e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1472d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (rasterClip.isBW()) { 1473d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rasterClip.bwRgn().getBounds(); 1474d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } else { 1475d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return rasterClip.aaRgn().getBounds(); 1476001e74426672e00f3f2783ccf728031662d4a358herb } 14779447103029273a9f8dd7f5997e8af7a1e3ee7488bungeman@google.com } 1478001e74426672e00f3f2783ccf728031662d4a358herb 1479d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bool getImageData(const SkGlyph& glyph, SkMask* mask) { 1480d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); 1481d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (nullptr == bits) { 1482d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return false; // can't rasterize glyph 1483d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb } 1484d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fImage = bits; 1485d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fRowBytes = glyph.rowBytes(); 1486d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); 1487d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb return true; 14882e8fec79658baef06f4a9fca5e91a4e116b47b3dherb } 14892e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1490d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb void blitMask(const SkMask& mask, const SkIRect& clip) const { 1491d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb if (SkMask::kARGB32_Format == mask.fFormat) { 1492d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkBitmap bm; 1493d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb bm.installPixels( 1494d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), 1495d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb (SkPMColor*)mask.fImage, mask.fRowBytes); 1496d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 1497d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); 1498045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } else { 1499d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb fBlitter->blitMask(mask, clip); 1500045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com } 15018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15025bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com 1503d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const bool fUseRegionToDraw; 1504d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkGlyphCache * const fGlyphCache; 1505d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkBlitter * const fBlitter; 1506d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkRegion* const fClip; 1507d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkDraw& fDraw; 1508d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkPaint& fPaint; 1509d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb const SkIRect fClipBounds; 1510d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb}; 15112e8fec79658baef06f4a9fca5e91a4e116b47b3dherb 1512d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb//////////////////////////////////////////////////////////////////////////////////////////////////// 15138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1514a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosmanuint32_t SkDraw::scalerContextFlags() const { 1515a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman uint32_t flags = SkPaint::kBoostContrast_ScalerContextFlag; 151699330ba6227137866a0dbd63478d36f335203ebdMike Reed if (!fDst.colorSpace()) { 1517a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman flags |= SkPaint::kFakeGamma_ScalerContextFlag; 1518a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman } 1519a1e8f8d8f1a0b7141136d7d49df1cc2fec0528dfbrianosman return flags; 1520f6d1e605317917146362706ed460b5ed6624fcc5bungeman} 1521f6d1e605317917146362706ed460b5ed6624fcc5bungeman 152299330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y, 152399330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkPaint& paint, const SkSurfaceProps* props) const { 152496fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(byteLength == 0 || text != nullptr); 15258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1526f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 15278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 152996fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 15308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 15318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 153336d6edac9f3e63d9a5f499d0076550d08b80eacabsalomon@google.com // SkScalarRec doesn't currently have a way of representing hairline stroke and 153436d6edac9f3e63d9a5f499d0076550d08b80eacabsalomon@google.com // will fill if its frame-width is 0. 1535ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 15368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->drawText_asPaths(text, byteLength, x, y, paint); 15378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 15388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 154099330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); 154111a7f7f5998cb3d5605741e37a7f12f7477d480cherb 154211a7f7f5998cb3d5605741e37a7f12f7477d480cherb // The Blitter Choose needs to be live while using the blitter below. 154311a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 154411a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1545f6d1e605317917146362706ed460b5ed6624fcc5bungeman DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 15468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1547e59124ed1a62f1fec79679c38cabed622a756f75herb SkFindAndPlaceGlyph::ProcessText( 15484c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb paint.getTextEncoding(), text, byteLength, 1549f6d1e605317917146362706ed460b5ed6624fcc5bungeman {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph); 15508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 15518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////// 15538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 155499330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[], 155599330ba6227137866a0dbd63478d36f335203ebdMike Reed int scalarsPerPosition, const SkPoint& offset, 155699330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkPaint& origPaint, const SkSurfaceProps* props) const { 1557ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com // setup our std paint, in hopes of getting hits in the cache 1558ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com SkPaint paint(origPaint); 1559ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com SkScalar matrixScale = paint.setupForAsPaths(); 1560ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 15615a64902ee92847f53dfc5b211da19d074179be64reed@google.com SkMatrix matrix; 15625a64902ee92847f53dfc5b211da19d074179be64reed@google.com matrix.setScale(matrixScale, matrixScale); 15638f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 15644e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. 15654e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org paint.setStyle(SkPaint::kFill_Style); 156696fcdcc219d2a0d3579719b84b28bede76efba64halcanary paint.setPathEffect(nullptr); 15674e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org 1568e34f17d23699abfc672289f51319b37294b3c257robertphillips SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(), 1569e34f17d23699abfc672289f51319b37294b3c257robertphillips paint.isDevKernText(), 1570e34f17d23699abfc672289f51319b37294b3c257robertphillips true); 157199330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), nullptr); 1572ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 1573ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com const char* stop = text + byteLength; 157479738cc7bf12d212bef4ff80591d1bf6f383663dbungeman SkTextAlignProc alignProc(paint.getTextAlign()); 157505c4a4322e7d4f3417b7df33825bab8603d52051fmalita SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); 15768f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 15774e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org // Now restore the original settings, so we "draw" with whatever style/stroking. 15784e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org paint.setStyle(origPaint.getStyle()); 1579693fdbd6b81a860657612e7604430dd55d6e721bMike Reed paint.setPathEffect(origPaint.refPathEffect()); 15804e82cdb90abb34a2ab60fcdb26e7bfc17e8e4da9commit-bot@chromium.org 1581ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com while (text < stop) { 1582d936f63c35fb7dfb2b6c20802206adbfc3cc48d0benjaminwagner const SkGlyph& glyph = glyphCacheProc(cache.get(), &text); 1583ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (glyph.fWidth) { 1584ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com const SkPath* path = cache->findPath(glyph); 1585ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (path) { 1586cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen SkPoint tmsLoc; 1587cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen tmsProc(pos, &tmsLoc); 1588cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com SkPoint loc; 1589cb9a2c8934f009b6ee1ca73d662ac18b285085d9kkinnunen alignProc(tmsLoc, glyph, &loc); 15908f6ef4010f6835c5ce9ede180e50a6a58512a81eskia.committer@gmail.com 1591cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com matrix[SkMatrix::kMTransX] = loc.fX; 1592cfd90d6073baef9841dcb6e7b25d244f06ceeeaabungeman@google.com matrix[SkMatrix::kMTransY] = loc.fY; 159399330ba6227137866a0dbd63478d36f335203ebdMike Reed this->drawPath(*path, paint, &matrix, false); 1594ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1595ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1596ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com pos += scalarsPerPosition; 1597ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com } 1598ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com} 1599ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com 160099330ba6227137866a0dbd63478d36f335203ebdMike Reedvoid SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar pos[], 160199330ba6227137866a0dbd63478d36f335203ebdMike Reed int scalarsPerPosition, const SkPoint& offset, const SkPaint& paint, 160299330ba6227137866a0dbd63478d36f335203ebdMike Reed const SkSurfaceProps* props) const { 160396fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(byteLength == 0 || text != nullptr); 16048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 16058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1606f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com SkDEBUGCODE(this->validate();) 16078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // nothing to draw 160996fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 16108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 16118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1613ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 161499330ba6227137866a0dbd63478d36f335203ebdMike Reed this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint, props); 16158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 16168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 161899330ba6227137866a0dbd63478d36f335203ebdMike Reed SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix); 1619d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb 16209be5ff6f9871ef22740094e7c25dd67329a73d20herb // The Blitter Choose needs to be live while using the blitter below. 162111a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 162211a7f7f5998cb3d5605741e37a7f12f7477d480cherb SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1623f6d1e605317917146362706ed460b5ed6624fcc5bungeman DrawOneGlyph drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter()); 1624d4c24f67496ff2e5e83bc7ce7945cbb85484bfa6herb SkPaint::Align textAlignment = paint.getTextAlign(); 16258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16269be5ff6f9871ef22740094e7c25dd67329a73d20herb SkFindAndPlaceGlyph::ProcessPosText( 16274c11b3f8a2d9919a21110dbdd29e67e5cbaa41fbherb paint.getTextEncoding(), text, byteLength, 1628f6d1e605317917146362706ed460b5ed6624fcc5bungeman offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph); 16298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1631d7dc76f7e99309cbd09a5420c22e55b951067debbungeman#if defined _WIN32 16328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#pragma warning ( pop ) 16338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 16348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1635787a16dd9e03f3971898131dd778206c8cb9a0dfMike Reed//////////////////////////////////////////////////////////////////////////////////////////////// 16368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 16388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1639f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comvoid SkDraw::validate() const { 164096fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(fMatrix != nullptr); 164196fcdcc219d2a0d3579719b84b28bede76efba64halcanary SkASSERT(fRC != nullptr); 16428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1643045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com const SkIRect& cr = fRC->getBounds(); 16448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect br; 16458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 164641e010cb901c0da9066c4df562030808c9ccd7f8reed br.set(0, 0, fDst.width(), fDst.height()); 16478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(cr.isEmpty() || br.contains(cr)); 16488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 16518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////////////////////////// 16538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h" 16558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDraw.h" 16568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h" 16578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h" 16588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds, 1660b07a94f1cba3976596ae1a7f23d8c2043ba353f3reed const SkMaskFilter* filter, const SkMatrix* filterMatrix, 16618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkIRect* bounds) { 16628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (devPath.isEmpty()) { 16638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 16648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // init our bounds from the path 166711fa2247b747eb75e2f158dc7571d458ed6c0115reed *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut(); 1668a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16696db75fc2c393ba86a3f533597a8bcd348477e79ctomhudson@google.com SkIPoint margin = SkIPoint::Make(0, 0); 16708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (filter) { 16718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(filterMatrix); 1672a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16735af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com SkMask srcM, dstM; 1674a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcM.fBounds = *bounds; 16768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcM.fFormat = SkMask::kA8_Format; 16778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) { 16788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 16798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1681a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 16825af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com // (possibly) trim the bounds to reflect the clip 16838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // (plus whatever slop the filter needs) 16845af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com if (clipBounds) { 16853555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // Ugh. Guard against gigantic margins from wacky filters. Without this 16863555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // check we can request arbitrary amounts of slop beyond our visible 16873555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // clip, and bring down the renderer (at least on finite RAM machines 16883555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // like handsets, etc.). Need to balance this invented value between 16893555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // quality of large filters like blurs, and the corresponding memory 16903555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com // requests. 16913555591c158c242b071c7ec92ad75b6e4cb74af2reed@android.com static const int MAX_MARGIN = 128; 169211fa2247b747eb75e2f158dc7571d458ed6c0115reed if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN), 169311fa2247b747eb75e2f158dc7571d458ed6c0115reed SkMin32(margin.fY, MAX_MARGIN)))) { 16945af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com return false; 16955af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com } 16968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 16998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1701055e192adc0072ae2548ef5431ceee652945f9c2bsalomonstatic void draw_into_mask(const SkMask& mask, const SkPath& devPath, 1702055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkStrokeRec::InitStyle style) { 170341e010cb901c0da9066c4df562030808c9ccd7f8reed SkDraw draw; 170441e010cb901c0da9066c4df562030808c9ccd7f8reed if (!draw.fDst.reset(mask)) { 170541e010cb901c0da9066c4df562030808c9ccd7f8reed return; 170641e010cb901c0da9066c4df562030808c9ccd7f8reed } 170741e010cb901c0da9066c4df562030808c9ccd7f8reed 1708045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkRasterClip clip; 1709045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkMatrix matrix; 1710045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com SkPaint paint; 17118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1712045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height())); 17138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 17148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com -SkIntToScalar(mask.fBounds.fTop)); 17158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1716045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com draw.fRC = &clip; 17178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.fMatrix = &matrix; 17188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com paint.setAntiAlias(true); 1719055e192adc0072ae2548ef5431ceee652945f9c2bsalomon switch (style) { 1720055e192adc0072ae2548ef5431ceee652945f9c2bsalomon case SkStrokeRec::kHairline_InitStyle: 1721055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkASSERT(!paint.getStrokeWidth()); 1722055e192adc0072ae2548ef5431ceee652945f9c2bsalomon paint.setStyle(SkPaint::kStroke_Style); 1723055e192adc0072ae2548ef5431ceee652945f9c2bsalomon break; 1724055e192adc0072ae2548ef5431ceee652945f9c2bsalomon case SkStrokeRec::kFill_InitStyle: 1725055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkASSERT(paint.getStyle() == SkPaint::kFill_Style); 1726055e192adc0072ae2548ef5431ceee652945f9c2bsalomon break; 1727055e192adc0072ae2548ef5431ceee652945f9c2bsalomon 1728055e192adc0072ae2548ef5431ceee652945f9c2bsalomon } 17298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com draw.drawPath(devPath, paint); 17308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds, 173330711b764be6bbb58caa30a0ac5d1474c894efe7reed@google.com const SkMaskFilter* filter, const SkMatrix* filterMatrix, 17342ac4ef5e6e0c9c95c9200408ba25a95ca758eac2junov@chromium.org SkMask* mask, SkMask::CreateMode mode, 1735055e192adc0072ae2548ef5431ceee652945f9c2bsalomon SkStrokeRec::InitStyle style) { 17368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kJustRenderImage_CreateMode != mode) { 17378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds)) 17388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 17398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1740a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 17418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) { 17428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fFormat = SkMask::kA8_Format; 17438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com mask->fRowBytes = mask->fBounds.width(); 1744543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com size_t size = mask->computeImageSize(); 1745543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com if (0 == size) { 1746543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com // we're too big to allocate the mask, abort 1747543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com return false; 1748543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com } 1749543ed9352c7dfd93071c08b14930cca2e82a08d4reed@android.com mask->fImage = SkMask::AllocImage(size); 17508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com memset(mask->fImage, 0, mask->computeImageSize()); 17518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkMask::kJustComputeBounds_CreateMode != mode) { 17542ac4ef5e6e0c9c95c9200408ba25a95ca758eac2junov@chromium.org draw_into_mask(*mask, devPath, style); 17558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1756a76de3d1a92134c3e95ad7fce99234f92fa48268reed@google.com 17578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 17588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1759