gfx/skia/trunk/src/gpu/GrSWMaskHelper.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:f2943f65b3e9
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 "GrDrawState.h"
10 #include "GrDrawTargetCaps.h"
11 #include "GrGpu.h"
12
13 #include "SkStrokeRec.h"
14
15 // TODO: try to remove this #include
16 #include "GrContext.h"
17
18 namespace {
19 /*
20 * Convert a boolean operation into a transfer mode code
21 */
22 SkXfermode::Mode op_to_mode(SkRegion::Op op) {
23
24 static const SkXfermode::Mode modeMap[] = {
25 SkXfermode::kDstOut_Mode, // kDifference_Op
26 SkXfermode::kModulate_Mode, // kIntersect_Op
27 SkXfermode::kSrcOver_Mode, // kUnion_Op
28 SkXfermode::kXor_Mode, // kXOR_Op
29 SkXfermode::kClear_Mode, // kReverseDifference_Op
30 SkXfermode::kSrc_Mode, // kReplace_Op
31 };
32
33 return modeMap[op];
34 }
35
36 }
37
38 /**
39 * Draw a single rect element of the clip stack into the accumulation bitmap
40 */
41 void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
42 bool antiAlias, uint8_t alpha) {
43 SkPaint paint;
44
45 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
46
47 paint.setXfermode(mode);
48 paint.setAntiAlias(antiAlias);
49 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
50
51 fDraw.drawRect(rect, paint);
52
53 SkSafeUnref(mode);
54 }
55
56 /**
57 * Draw a single path element of the clip stack into the accumulation bitmap
58 */
59 void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
60 bool antiAlias, uint8_t alpha) {
61
62 SkPaint paint;
63 if (stroke.isHairlineStyle()) {
64 paint.setStyle(SkPaint::kStroke_Style);
65 paint.setStrokeWidth(SK_Scalar1);
66 } else {
67 if (stroke.isFillStyle()) {
68 paint.setStyle(SkPaint::kFill_Style);
69 } else {
70 paint.setStyle(SkPaint::kStroke_Style);
71 paint.setStrokeJoin(stroke.getJoin());
72 paint.setStrokeCap(stroke.getCap());
73 paint.setStrokeWidth(stroke.getWidth());
74 }
75 }
76 paint.setAntiAlias(antiAlias);
77
78 if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
79 SkASSERT(0xFF == paint.getAlpha());
80 fDraw.drawPathCoverage(path, paint);
81 } else {
82 paint.setXfermodeMode(op_to_mode(op));
83 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
84 fDraw.drawPath(path, paint);
85 }
86 }
87
88 bool GrSWMaskHelper::init(const SkIRect& resultBounds,
89 const SkMatrix* matrix) {
90 if (NULL != matrix) {
91 fMatrix = *matrix;
92 } else {
93 fMatrix.setIdentity();
94 }
95
96 // Now translate so the bound's UL corner is at the origin
97 fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
98 -resultBounds.fTop * SK_Scalar1);
99 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
100 resultBounds.height());
101
102 if (!fBM.allocPixels(SkImageInfo::MakeA8(bounds.fRight, bounds.fBottom))) {
103 return false;
104 }
105 sk_bzero(fBM.getPixels(), fBM.getSafeSize());
106
107 sk_bzero(&fDraw, sizeof(fDraw));
108 fRasterClip.setRect(bounds);
109 fDraw.fRC = &fRasterClip;
110 fDraw.fClip = &fRasterClip.bwRgn();
111 fDraw.fMatrix = &fMatrix;
112 fDraw.fBitmap = &fBM;
113 return true;
114 }
115
116 /**
117 * Get a texture (from the texture cache) of the correct size & format.
118 * Return true on success; false on failure.
119 */
120 bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
121 GrTextureDesc desc;
122 desc.fWidth = fBM.width();
123 desc.fHeight = fBM.height();
124 desc.fConfig = kAlpha_8_GrPixelConfig;
125
126 texture->set(fContext, desc);
127 return NULL != texture->texture();
128 }
129
130 /**
131 * Move the result of the software mask generation back to the gpu
132 */
133 void GrSWMaskHelper::toTexture(GrTexture *texture) {
134 SkAutoLockPixels alp(fBM);
135
136 // If we aren't reusing scratch textures we don't need to flush before
137 // writing since no one else will be using 'texture'
138 bool reuseScratch = fContext->getGpu()->caps()->reuseScratchTextures();
139
140 // Since we're uploading to it, 'texture' shouldn't have a render target.
141 SkASSERT(NULL == texture->asRenderTarget());
142
143 texture->writePixels(0, 0, fBM.width(), fBM.height(),
144 kAlpha_8_GrPixelConfig,
145 fBM.getPixels(), fBM.rowBytes(),
146 reuseScratch ? 0 : GrContext::kDontFlush_PixelOpsFlag);
147 }
148
149 ////////////////////////////////////////////////////////////////////////////////
150 /**
151 * Software rasterizes path to A8 mask (possibly using the context's matrix)
152 * and uploads the result to a scratch texture. Returns the resulting
153 * texture on success; NULL on failure.
154 */
155 GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
156 const SkPath& path,
157 const SkStrokeRec& stroke,
158 const SkIRect& resultBounds,
159 bool antiAlias,
160 SkMatrix* matrix) {
161 GrAutoScratchTexture ast;
162
163 GrSWMaskHelper helper(context);
164
165 if (!helper.init(resultBounds, matrix)) {
166 return NULL;
167 }
168
169 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
170
171 if (!helper.getTexture(&ast)) {
172 return NULL;
173 }
174
175 helper.toTexture(ast.texture());
176
177 return ast.detach();
178 }
179
180 void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
181 GrDrawTarget* target,
182 const SkIRect& rect) {
183 GrDrawState* drawState = target->drawState();
184
185 GrDrawState::AutoViewMatrixRestore avmr;
186 if (!avmr.setIdentity(drawState)) {
187 return;
188 }
189 GrDrawState::AutoRestoreEffects are(drawState);
190
191 SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
192 SK_Scalar1 * rect.fTop,
193 SK_Scalar1 * rect.fRight,
194 SK_Scalar1 * rect.fBottom);
195
196 // We want to use device coords to compute the texture coordinates. We set our matrix to be
197 // equal to the view matrix followed by a translation so that the top-left of the device bounds
198 // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
199 // vertex positions rather than local coords.
200 SkMatrix maskMatrix;
201 maskMatrix.setIDiv(texture->width(), texture->height());
202 maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
203 maskMatrix.preConcat(drawState->getViewMatrix());
204
205 drawState->addCoverageEffect(
206 GrSimpleTextureEffect::Create(texture,
207 maskMatrix,
208 GrTextureParams::kNone_FilterMode,
209 kPosition_GrCoordSet))->unref();
210
211 target->drawSimpleRect(dstRect);
212 }

mercurial