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