• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrSWMaskHelper.h"
9 #include "GrCaps.h"
10 #include "GrContext.h"
11 #include "GrContextPriv.h"
12 #include "GrRenderTargetContext.h"
13 #include "GrShape.h"
14 #include "GrSurfaceContext.h"
15 #include "GrTextureProxy.h"
16 #include "SkDistanceFieldGen.h"
17 #include "ops/GrDrawOp.h"
18 #include "ops/GrRectOpFactory.h"
19 
20 /*
21  * Convert a boolean operation into a transfer mode code
22  */
op_to_mode(SkRegion::Op op)23 static SkBlendMode op_to_mode(SkRegion::Op op) {
24 
25     static const SkBlendMode modeMap[] = {
26         SkBlendMode::kDstOut,   // kDifference_Op
27         SkBlendMode::kModulate, // kIntersect_Op
28         SkBlendMode::kSrcOver,  // kUnion_Op
29         SkBlendMode::kXor,      // kXOR_Op
30         SkBlendMode::kClear,    // kReverseDifference_Op
31         SkBlendMode::kSrc,      // kReplace_Op
32     };
33 
34     return modeMap[op];
35 }
36 
37 /**
38  * Draw a single rect element of the clip stack into the accumulation bitmap
39  */
drawRect(const SkRect & rect,SkRegion::Op op,GrAA aa,uint8_t alpha)40 void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, GrAA aa, uint8_t alpha) {
41     SkPaint paint;
42 
43     paint.setBlendMode(op_to_mode(op));
44     paint.setAntiAlias(GrAA::kYes == aa);
45     paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
46 
47     fDraw.drawRect(rect, paint);
48 }
49 
50 /**
51  * Draw a single path element of the clip stack into the accumulation bitmap
52  */
drawShape(const GrShape & shape,SkRegion::Op op,GrAA aa,uint8_t alpha)53 void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, GrAA aa, uint8_t alpha) {
54     SkPaint paint;
55     paint.setPathEffect(shape.style().refPathEffect());
56     shape.style().strokeRec().applyToPaint(&paint);
57     paint.setAntiAlias(GrAA::kYes == aa);
58 
59     SkPath path;
60     shape.asPath(&path);
61     if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
62         SkASSERT(0xFF == paint.getAlpha());
63         fDraw.drawPathCoverage(path, paint);
64     } else {
65         paint.setBlendMode(op_to_mode(op));
66         paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
67         fDraw.drawPath(path, paint);
68     }
69 }
70 
init(const SkIRect & resultBounds,const SkMatrix * matrix)71 bool GrSWMaskHelper::init(const SkIRect& resultBounds, const SkMatrix* matrix) {
72     if (matrix) {
73         fMatrix = *matrix;
74     } else {
75         fMatrix.setIdentity();
76     }
77 
78     // Now translate so the bound's UL corner is at the origin
79     fMatrix.postTranslate(-SkIntToScalar(resultBounds.fLeft), -SkIntToScalar(resultBounds.fTop));
80     SkIRect bounds = SkIRect::MakeWH(resultBounds.width(), resultBounds.height());
81 
82     const SkImageInfo bmImageInfo = SkImageInfo::MakeA8(bounds.width(), bounds.height());
83     if (!fPixels.tryAlloc(bmImageInfo)) {
84         return false;
85     }
86     fPixels.erase(0);
87 
88     sk_bzero(&fDraw, sizeof(fDraw));
89     fDraw.fDst      = fPixels;
90     fRasterClip.setRect(bounds);
91     fDraw.fRC       = &fRasterClip;
92     fDraw.fMatrix   = &fMatrix;
93     return true;
94 }
95 
toTextureProxy(GrContext * context,SkBackingFit fit)96 sk_sp<GrTextureProxy> GrSWMaskHelper::toTextureProxy(GrContext* context, SkBackingFit fit) {
97     GrSurfaceDesc desc;
98     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
99     desc.fWidth = fPixels.width();
100     desc.fHeight = fPixels.height();
101     desc.fConfig = kAlpha_8_GrPixelConfig;
102 
103     sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeDeferredSurfaceContext(
104                                                                                 desc,
105                                                                                 fit,
106                                                                                 SkBudgeted::kYes);
107     if (!sContext || !sContext->asTextureProxy()) {
108         return nullptr;
109     }
110 
111     SkImageInfo ii = SkImageInfo::MakeA8(desc.fWidth, desc.fHeight);
112     if (!sContext->writePixels(ii, fPixels.addr(), fPixels.rowBytes(), 0, 0)) {
113         return nullptr;
114     }
115 
116     return sContext->asTextureProxyRef();
117 }
118 
119 /**
120  * Convert mask generation results to a signed distance field
121  */
toSDF(unsigned char * sdf)122 void GrSWMaskHelper::toSDF(unsigned char* sdf) {
123     SkGenerateDistanceFieldFromA8Image(sdf, (const unsigned char*)fPixels.addr(),
124                                        fPixels.width(), fPixels.height(), fPixels.rowBytes());
125 }
126 
127 ////////////////////////////////////////////////////////////////////////////////
128 /**
129  * Software rasterizes shape to A8 mask and uploads the result to a scratch texture. Returns the
130  * resulting texture on success; nullptr on failure.
131  */
DrawShapeMaskToTexture(GrContext * context,const GrShape & shape,const SkIRect & resultBounds,GrAA aa,SkBackingFit fit,const SkMatrix * matrix)132 sk_sp<GrTextureProxy> GrSWMaskHelper::DrawShapeMaskToTexture(GrContext* context,
133                                                              const GrShape& shape,
134                                                              const SkIRect& resultBounds,
135                                                              GrAA aa,
136                                                              SkBackingFit fit,
137                                                              const SkMatrix* matrix) {
138     GrSWMaskHelper helper;
139 
140     if (!helper.init(resultBounds, matrix)) {
141         return nullptr;
142     }
143 
144     helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0xFF);
145 
146     return helper.toTextureProxy(context, fit);
147 }
148 
DrawToTargetWithShapeMask(sk_sp<GrTextureProxy> proxy,GrRenderTargetContext * renderTargetContext,GrPaint && paint,const GrUserStencilSettings & userStencilSettings,const GrClip & clip,const SkMatrix & viewMatrix,const SkIPoint & textureOriginInDeviceSpace,const SkIRect & deviceSpaceRectToDraw)149 void GrSWMaskHelper::DrawToTargetWithShapeMask(sk_sp<GrTextureProxy> proxy,
150                                                GrRenderTargetContext* renderTargetContext,
151                                                GrPaint&& paint,
152                                                const GrUserStencilSettings& userStencilSettings,
153                                                const GrClip& clip,
154                                                const SkMatrix& viewMatrix,
155                                                const SkIPoint& textureOriginInDeviceSpace,
156                                                const SkIRect& deviceSpaceRectToDraw) {
157     SkMatrix invert;
158     if (!viewMatrix.invert(&invert)) {
159         return;
160     }
161 
162     SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw);
163 
164     // We use device coords to compute the texture coordinates. We take the device coords and apply
165     // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling
166     // matrix to normalized coords.
167     SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX),
168                                               SkIntToScalar(-textureOriginInDeviceSpace.fY));
169     maskMatrix.preConcat(viewMatrix);
170     paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
171             std::move(proxy), nullptr, maskMatrix,
172             GrSamplerParams::kNone_FilterMode));
173     renderTargetContext->addDrawOp(clip,
174                                    GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
175                                            std::move(paint), SkMatrix::I(), invert, dstRect,
176                                            GrAAType::kNone, &userStencilSettings));
177 }
178