158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/* 258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Copyright 2012 Google Inc. 358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * 458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Use of this source code is governed by a BSD-style license that can be 558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * found in the LICENSE file. 658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */ 758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com#include "GrSWMaskHelper.h" 9eb1cb5c5b50febad115d859faca91d2d6af3fff2bsalomon#include "GrCaps.h" 10976f5f0dc5e907d1ca50685fad117bd15d7fc87brobertphillips#include "GrContext.h" 11e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips#include "GrContextPriv.h" 12895274391db8df7357334aec260edca2e1735626Brian Salomon#include "GrRenderTargetContext.h" 138acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon#include "GrShape.h" 14e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips#include "GrSurfaceContext.h" 15e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips#include "GrTextureProxy.h" 16a0485d94529905e76320b7aa941a0d94b5578ac2Brian Salomon#include "SkDistanceFieldGen.h" 17baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon#include "ops/GrDrawOp.h" 18baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon#include "ops/GrRectOpFactory.h" 1958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 2058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/* 2158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Convert a boolean operation into a transfer mode code 2258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */ 23374772bd61951f01bf84fe17bf53d8867681c9aereedstatic SkBlendMode op_to_mode(SkRegion::Op op) { 2458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 25374772bd61951f01bf84fe17bf53d8867681c9aereed static const SkBlendMode modeMap[] = { 26374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kDstOut, // kDifference_Op 27374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kModulate, // kIntersect_Op 28374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kSrcOver, // kUnion_Op 29374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kXor, // kXOR_Op 30374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kClear, // kReverseDifference_Op 31374772bd61951f01bf84fe17bf53d8867681c9aereed SkBlendMode::kSrc, // kReplace_Op 3258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com }; 3358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 3458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com return modeMap[op]; 3558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com} 3658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 3758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/** 3858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Draw a single rect element of the clip stack into the accumulation bitmap 3958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */ 400e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomonvoid GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, GrAA aa, uint8_t alpha) { 4158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com SkPaint paint; 4258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 43374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setBlendMode(op_to_mode(op)); 440e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomon paint.setAntiAlias(GrAA::kYes == aa); 45366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); 4658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 47366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com fDraw.drawRect(rect, paint); 4858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com} 4958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 5058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com/** 5158b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com * Draw a single path element of the clip stack into the accumulation bitmap 5258b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com */ 530e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomonvoid GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, GrAA aa, uint8_t alpha) { 5458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com SkPaint paint; 55f809c1ec98854b6d0e604744a1fc5f9a4ff493beRobert Phillips paint.setPathEffect(shape.style().refPathEffect()); 568acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon shape.style().strokeRec().applyToPaint(&paint); 570e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomon paint.setAntiAlias(GrAA::kYes == aa); 5858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 598acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon SkPath path; 608acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon shape.asPath(&path); 61126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com if (SkRegion::kReplace_Op == op && 0xFF == alpha) { 62126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com SkASSERT(0xFF == paint.getAlpha()); 639837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips fDraw.drawPathCoverage(path, paint); 64126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com } else { 65374772bd61951f01bf84fe17bf53d8867681c9aereed paint.setBlendMode(op_to_mode(op)); 66126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); 679837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips fDraw.drawPath(path, paint); 68126f7f5244502c0cbf1e5fec1d2ad7a0f2eb6c34reed@google.com } 6958b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com} 7058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 719837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillipsbool GrSWMaskHelper::init(const SkIRect& resultBounds, const SkMatrix* matrix) { 7249f085dddff10473b6ebf832a974288300224e60bsalomon if (matrix) { 73366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com fMatrix = *matrix; 7458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com } else { 7558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com fMatrix.setIdentity(); 7658b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com } 7758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 78366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com // Now translate so the bound's UL corner is at the origin 799837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips fMatrix.postTranslate(-SkIntToScalar(resultBounds.fLeft), -SkIntToScalar(resultBounds.fTop)); 809837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips SkIRect bounds = SkIRect::MakeWH(resultBounds.width(), resultBounds.height()); 8125a67bcb7ac70d3077e91126c4b8924a53557a38krajcevski 829837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(bounds.width(), bounds.height()); 839837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips if (!fPixels.tryAlloc(bmImageInfo)) { 849837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips return false; 859d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary } 869837740dd59fa2461e5d6e6cd36cdc93567b5717robertphillips fPixels.erase(0); 87b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski 8841e010cb901c0da9066c4df562030808c9ccd7f8reed sk_bzero(&fDraw, sizeof(fDraw)); 8941e010cb901c0da9066c4df562030808c9ccd7f8reed fDraw.fDst = fPixels; 9058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com fRasterClip.setRect(bounds); 9141e010cb901c0da9066c4df562030808c9ccd7f8reed fDraw.fRC = &fRasterClip; 9241e010cb901c0da9066c4df562030808c9ccd7f8reed fDraw.fMatrix = &fMatrix; 9358b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com return true; 9458b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com} 9558b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 96d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillipssk_sp<GrTextureProxy> GrSWMaskHelper::toTextureProxy(GrContext* context, SkBackingFit fit) { 97f2703d83da3ab2ae18b45231fd4f11e16cce3184bsalomon GrSurfaceDesc desc; 98d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips desc.fOrigin = kTopLeft_GrSurfaceOrigin; 9941e010cb901c0da9066c4df562030808c9ccd7f8reed desc.fWidth = fPixels.width(); 10041e010cb901c0da9066c4df562030808c9ccd7f8reed desc.fHeight = fPixels.height(); 101b3abe90145b988883c9882de1ac42da963adbf67krajcevski desc.fConfig = kAlpha_8_GrPixelConfig; 102fb4f5cb39e31b8544b526074683a65bb716b7acfkrajcevski 103e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext( 104e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips desc, 105e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips fit, 106e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips SkBudgeted::kYes); 107f200a90f3e58ce20753420cadced850d7d00dca1Robert Phillips if (!sContext || !sContext->asTextureProxy()) { 108e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips return nullptr; 10939ef7fb885d7be648b9f0ecd027bc400d1213cecbsalomon } 11058b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 111c949ce9d808dbf7c2db7dc0b85271969ba46b69aRobert Phillips SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight); 112c949ce9d808dbf7c2db7dc0b85271969ba46b69aRobert Phillips if (!sContext->writePixels(ii, fPixels.addr(), fPixels.rowBytes(), 0, 0)) { 113e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips return nullptr; 114e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips } 115b8ccc2f6d258a8466f79fc418e9e0a55aeaf58cekrajcevski 116f200a90f3e58ce20753420cadced850d7d00dca1Robert Phillips return sContext->asTextureProxyRef(); 11758b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com} 11858b20215f6d88b7e1cacae0b76226fced5109293robertphillips@google.com 119fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth/** 120fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth * Convert mask generation results to a signed distance field 121fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth */ 122fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverthvoid GrSWMaskHelper::toSDF(unsigned char* sdf) { 12341e010cb901c0da9066c4df562030808c9ccd7f8reed SkGenerateDistanceFieldFromA8Image(sdf, (const unsigned char*)fPixels.addr(), 12441e010cb901c0da9066c4df562030808c9ccd7f8reed fPixels.width(), fPixels.height(), fPixels.rowBytes()); 125fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth} 126fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth 127366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com//////////////////////////////////////////////////////////////////////////////// 128366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com/** 1298acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon * Software rasterizes shape to A8 mask and uploads the result to a scratch texture. Returns the 1308acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon * resulting texture on success; nullptr on failure. 131366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com */ 132d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillipssk_sp<GrTextureProxy> GrSWMaskHelper::DrawShapeMaskToTexture(GrContext* context, 133d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips const GrShape& shape, 134d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips const SkIRect& resultBounds, 135d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips GrAA aa, 136d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips SkBackingFit fit, 137d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips const SkMatrix* matrix) { 138e305cc1f2a44e47d6a0dcc0ff34e2692349aed5dRobert Phillips GrSWMaskHelper helper; 139366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 14084e922bfb3e7a03f6e35beb2f1e4f2657e7cd3e9reed@google.com if (!helper.init(resultBounds, matrix)) { 14196fcdcc219d2a0d3579719b84b28bede76efba64halcanary return nullptr; 142366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com } 143366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 1440e8fc8b9e6a138cf4a66b421fb824679df717329Brian Salomon helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0xFF); 145366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com 146d3749485db2de966a80e39669a49192fc7c0bd9dRobert Phillips return helper.toTextureProxy(context, fit); 1475dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com} 1485dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com 149296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillipsvoid GrSWMaskHelper::DrawToTargetWithShapeMask(sk_sp<GrTextureProxy> proxy, 1501105224f9701e57ec5ce0354d6a380b664f5c638Brian Osman GrRenderTargetContext* renderTargetContext, 15182f44319159bb98dcacdbbec7ea643dde5ed024bBrian Salomon GrPaint&& paint, 152d2b6d6486ed9d00df779f6b337d756c9a818006frobertphillips const GrUserStencilSettings& userStencilSettings, 1538acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon const GrClip& clip, 1548acedde5970ce70de6d9791ffeda87a65af4ed07bsalomon const SkMatrix& viewMatrix, 15539ef7fb885d7be648b9f0ecd027bc400d1213cecbsalomon const SkIPoint& textureOriginInDeviceSpace, 15639ef7fb885d7be648b9f0ecd027bc400d1213cecbsalomon const SkIRect& deviceSpaceRectToDraw) { 157d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt SkMatrix invert; 1588059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt if (!viewMatrix.invert(&invert)) { 159e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com return; 160e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com } 1615dfb67219a308edecafbe09eebb35c5e149db6e6robertphillips@google.com 16239ef7fb885d7be648b9f0ecd027bc400d1213cecbsalomon SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw); 163c78188896e28a4ae49e406a7422b345ae177dafebsalomon@google.com 164309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon // We use device coords to compute the texture coordinates. We take the device coords and apply 165309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling 166309d4d590964fbf7443c5bc892c132faa61a9abbbsalomon // matrix to normalized coords. 16767c18d6b5188a0497f6912a73d964c763d2f8f84Robert Phillips SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX), 16867c18d6b5188a0497f6912a73d964c763d2f8f84Robert Phillips SkIntToScalar(-textureOriginInDeviceSpace.fY)); 1692ebd0c80a2a9d90a2c2c653f40a2a7205bd2d31bBrian Salomon maskMatrix.preConcat(viewMatrix); 170d4652ca1b7989af5ef4e81b0de4eba529f804618Brian Salomon paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make( 171fbcef6eb8abad142daf45418516550f7635b4a52Robert Phillips std::move(proxy), nullptr, maskMatrix, 172296b1ccf9b8e9c8b945645efcbaa9c71c7135f58Robert Phillips GrSamplerParams::kNone_FilterMode)); 173baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon renderTargetContext->addDrawOp(clip, 174baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon GrRectOpFactory::MakeNonAAFillWithLocalMatrix( 175baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon std::move(paint), SkMatrix::I(), invert, dstRect, 176baaf439eb5d08097d794f13800e5bf7ce8885f95Brian Salomon GrAAType::kNone, &userStencilSettings)); 177366f1c6a09f63c76e78145cb08028f66062f31fdrobertphillips@google.com} 178