blob: 624b796f7ec12ff9a1aa4eb7e7e164207fd6257a [file] [log] [blame]
robertphillips@google.com58b20212012-06-27 20:44:52 +00001/*
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"
robertphillips@google.com9528bdb2013-09-18 22:33:57 +000010#include "GrDrawTargetCaps.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000011#include "GrGpu.h"
12
sugoi@google.com5f74cf82012-12-17 21:16:45 +000013#include "SkStrokeRec.h"
sugoi@google.com12b4e272012-12-06 20:13:11 +000014
robertphillips@google.com58b20212012-06-27 20:44:52 +000015// TODO: try to remove this #include
16#include "GrContext.h"
17
18namespace {
19/*
20 * Convert a boolean operation into a transfer mode code
21 */
22SkXfermode::Mode op_to_mode(SkRegion::Op op) {
23
24 static const SkXfermode::Mode modeMap[] = {
25 SkXfermode::kDstOut_Mode, // kDifference_Op
reed@google.com8d3cd7a2013-01-30 21:36:11 +000026 SkXfermode::kModulate_Mode, // kIntersect_Op
robertphillips@google.com58b20212012-06-27 20:44:52 +000027 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
robertphillips@google.com58b20212012-06-27 20:44:52 +000036}
37
38/**
39 * Draw a single rect element of the clip stack into the accumulation bitmap
40 */
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000041void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
robertphillips@google.com366f1c62012-06-29 21:38:47 +000042 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000043 SkPaint paint;
44
45 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
46
47 paint.setXfermode(mode);
48 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000049 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000050
robertphillips@google.com366f1c62012-06-29 21:38:47 +000051 fDraw.drawRect(rect, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000052
53 SkSafeUnref(mode);
54}
55
56/**
57 * Draw a single path element of the clip stack into the accumulation bitmap
58 */
sugoi@google.com5f74cf82012-12-17 21:16:45 +000059void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
sugoi@google.com12b4e272012-12-06 20:13:11 +000060 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000061
62 SkPaint paint;
sugoi@google.com5f74cf82012-12-17 21:16:45 +000063 if (stroke.isHairlineStyle()) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000064 paint.setStyle(SkPaint::kStroke_Style);
65 paint.setStrokeWidth(SK_Scalar1);
66 } else {
sugoi@google.com5f74cf82012-12-17 21:16:45 +000067 if (stroke.isFillStyle()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +000068 paint.setStyle(SkPaint::kFill_Style);
69 } else {
70 paint.setStyle(SkPaint::kStroke_Style);
71 paint.setStrokeJoin(stroke.getJoin());
72 paint.setStrokeCap(stroke.getCap());
sugoi@google.com5f74cf82012-12-17 21:16:45 +000073 paint.setStrokeWidth(stroke.getWidth());
robertphillips@google.com58b20212012-06-27 20:44:52 +000074 }
75 }
sugoi@google.com5f74cf82012-12-17 21:16:45 +000076
robertphillips@google.com58b20212012-06-27 20:44:52 +000077 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
78
79 paint.setXfermode(mode);
80 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000081 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000082
sugoi@google.com12b4e272012-12-06 20:13:11 +000083 fDraw.drawPath(path, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000084
85 SkSafeUnref(mode);
86}
87
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000088bool GrSWMaskHelper::init(const SkIRect& resultBounds,
bsalomon@google.comb9086a02012-11-01 18:02:54 +000089 const SkMatrix* matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +000090 if (NULL != matrix) {
91 fMatrix = *matrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +000092 } else {
93 fMatrix.setIdentity();
94 }
95
robertphillips@google.com366f1c62012-06-29 21:38:47 +000096 // Now translate so the bound's UL corner is at the origin
97 fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
98 -resultBounds.fTop * SK_Scalar1);
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000099 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000100 resultBounds.height());
robertphillips@google.com58b20212012-06-27 20:44:52 +0000101
102 fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
103 if (!fBM.allocPixels()) {
104 return false;
105 }
106 sk_bzero(fBM.getPixels(), fBM.getSafeSize());
107
108 sk_bzero(&fDraw, sizeof(fDraw));
109 fRasterClip.setRect(bounds);
110 fDraw.fRC = &fRasterClip;
111 fDraw.fClip = &fRasterClip.bwRgn();
112 fDraw.fMatrix = &fMatrix;
113 fDraw.fBitmap = &fBM;
114 return true;
115}
116
117/**
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000118 * Get a texture (from the texture cache) of the correct size & format.
119 * Return true on success; false on failure.
robertphillips@google.com58b20212012-06-27 20:44:52 +0000120 */
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000121bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000122 GrTextureDesc desc;
123 desc.fWidth = fBM.width();
124 desc.fHeight = fBM.height();
125 desc.fConfig = kAlpha_8_GrPixelConfig;
126
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000127 texture->set(fContext, desc);
128 return NULL != texture->texture();
robertphillips@google.com58b20212012-06-27 20:44:52 +0000129}
130
131/**
132 * Move the result of the software mask generation back to the gpu
133 */
robertphillips@google.comd92cf2e2013-07-19 18:13:02 +0000134void GrSWMaskHelper::toTexture(GrTexture *texture) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000135 SkAutoLockPixels alp(fBM);
136
robertphillips@google.com9528bdb2013-09-18 22:33:57 +0000137 // If we aren't reusing scratch textures we don't need to flush before
138 // writing since no one else will be using 'texture'
139 bool reuseScratch = fContext->getGpu()->caps()->reuseScratchTextures();
140
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141 texture->writePixels(0, 0, fBM.width(), fBM.height(),
robertphillips@google.com58b20212012-06-27 20:44:52 +0000142 kAlpha_8_GrPixelConfig,
robertphillips@google.com9528bdb2013-09-18 22:33:57 +0000143 fBM.getPixels(), fBM.rowBytes(),
144 reuseScratch ? 0 : GrContext::kDontFlush_PixelOpsFlag);
robertphillips@google.com58b20212012-06-27 20:44:52 +0000145}
146
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000147////////////////////////////////////////////////////////////////////////////////
148/**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149 * Software rasterizes path to A8 mask (possibly using the context's matrix)
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000150 * and uploads the result to a scratch texture. Returns the resulting
151 * texture on success; NULL on failure.
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000152 */
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000153GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
154 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000155 const SkStrokeRec& stroke,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000156 const SkIRect& resultBounds,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000157 bool antiAlias,
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000158 SkMatrix* matrix) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000159 GrAutoScratchTexture ast;
160
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000161 GrSWMaskHelper helper(context);
162
163 if (!helper.init(resultBounds, matrix)) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000164 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000165 }
166
sugoi@google.com12b4e272012-12-06 20:13:11 +0000167 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000168
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000169 if (!helper.getTexture(&ast)) {
170 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000171 }
172
robertphillips@google.comd92cf2e2013-07-19 18:13:02 +0000173 helper.toTexture(ast.texture());
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000174
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000175 return ast.detach();
176}
177
178void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
179 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000180 const SkIRect& rect) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000181 GrDrawState* drawState = target->drawState();
182
bsalomon@google.com137f1342013-05-29 21:27:53 +0000183 GrDrawState::AutoViewMatrixRestore avmr;
184 if (!avmr.setIdentity(drawState)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000185 return;
186 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000187 GrDrawState::AutoRestoreEffects are(drawState);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000188
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000189 SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
190 SK_Scalar1 * rect.fTop,
191 SK_Scalar1 * rect.fRight,
192 SK_Scalar1 * rect.fBottom);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000193
194 // We want to use device coords to compute the texture coordinates. We set our matrix to be
195 // equal to the view matrix followed by a translation so that the top-left of the device bounds
196 // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
197 // vertex positions rather than local coords.
198 SkMatrix maskMatrix;
199 maskMatrix.setIDiv(texture->width(), texture->height());
200 maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
201 maskMatrix.preConcat(drawState->getViewMatrix());
202
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000203 drawState->addCoverageEffect(
bsalomon@google.comc7818882013-03-20 19:19:53 +0000204 GrSimpleTextureEffect::Create(texture,
205 maskMatrix,
humper@google.comb86add12013-07-25 18:49:07 +0000206 GrTextureParams::kNone_FilterMode,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000207 kPosition_GrCoordSet))->unref();
bsalomon@google.comc7818882013-03-20 19:19:53 +0000208
209 target->drawSimpleRect(dstRect);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000210}