blob: eb5c555a1fee6772cd1a1446ae3a3c13aebd5537 [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"
10#include "GrGpu.h"
11
sugoi@google.com5f74cf82012-12-17 21:16:45 +000012#include "SkStrokeRec.h"
sugoi@google.com12b4e272012-12-06 20:13:11 +000013
robertphillips@google.com58b20212012-06-27 20:44:52 +000014// TODO: try to remove this #include
15#include "GrContext.h"
16
17namespace {
18/*
19 * Convert a boolean operation into a transfer mode code
20 */
21SkXfermode::Mode op_to_mode(SkRegion::Op op) {
22
23 static const SkXfermode::Mode modeMap[] = {
24 SkXfermode::kDstOut_Mode, // kDifference_Op
reed@google.com8d3cd7a2013-01-30 21:36:11 +000025 SkXfermode::kModulate_Mode, // kIntersect_Op
robertphillips@google.com58b20212012-06-27 20:44:52 +000026 SkXfermode::kSrcOver_Mode, // kUnion_Op
27 SkXfermode::kXor_Mode, // kXOR_Op
28 SkXfermode::kClear_Mode, // kReverseDifference_Op
29 SkXfermode::kSrc_Mode, // kReplace_Op
30 };
31
32 return modeMap[op];
33}
34
robertphillips@google.com58b20212012-06-27 20:44:52 +000035}
36
37/**
38 * Draw a single rect element of the clip stack into the accumulation bitmap
39 */
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000040void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
robertphillips@google.com366f1c62012-06-29 21:38:47 +000041 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000042 SkPaint paint;
43
44 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
45
46 paint.setXfermode(mode);
47 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000048 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000049
robertphillips@google.com366f1c62012-06-29 21:38:47 +000050 fDraw.drawRect(rect, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000051
52 SkSafeUnref(mode);
53}
54
55/**
56 * Draw a single path element of the clip stack into the accumulation bitmap
57 */
sugoi@google.com5f74cf82012-12-17 21:16:45 +000058void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
sugoi@google.com12b4e272012-12-06 20:13:11 +000059 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000060
61 SkPaint paint;
sugoi@google.com5f74cf82012-12-17 21:16:45 +000062 if (stroke.isHairlineStyle()) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000063 paint.setStyle(SkPaint::kStroke_Style);
64 paint.setStrokeWidth(SK_Scalar1);
65 } else {
sugoi@google.com5f74cf82012-12-17 21:16:45 +000066 if (stroke.isFillStyle()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +000067 paint.setStyle(SkPaint::kFill_Style);
68 } else {
69 paint.setStyle(SkPaint::kStroke_Style);
70 paint.setStrokeJoin(stroke.getJoin());
71 paint.setStrokeCap(stroke.getCap());
sugoi@google.com5f74cf82012-12-17 21:16:45 +000072 paint.setStrokeWidth(stroke.getWidth());
robertphillips@google.com58b20212012-06-27 20:44:52 +000073 }
74 }
sugoi@google.com5f74cf82012-12-17 21:16:45 +000075
robertphillips@google.com58b20212012-06-27 20:44:52 +000076 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
77
78 paint.setXfermode(mode);
79 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000080 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000081
sugoi@google.com12b4e272012-12-06 20:13:11 +000082 fDraw.drawPath(path, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000083
84 SkSafeUnref(mode);
85}
86
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000087bool GrSWMaskHelper::init(const SkIRect& resultBounds,
bsalomon@google.comb9086a02012-11-01 18:02:54 +000088 const SkMatrix* matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +000089 if (NULL != matrix) {
90 fMatrix = *matrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +000091 } else {
92 fMatrix.setIdentity();
93 }
94
robertphillips@google.com366f1c62012-06-29 21:38:47 +000095 // Now translate so the bound's UL corner is at the origin
96 fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
97 -resultBounds.fTop * SK_Scalar1);
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000098 SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
robertphillips@google.com366f1c62012-06-29 21:38:47 +000099 resultBounds.height());
robertphillips@google.com58b20212012-06-27 20:44:52 +0000100
101 fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
102 if (!fBM.allocPixels()) {
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/**
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000117 * Get a texture (from the texture cache) of the correct size & format.
118 * Return true on success; false on failure.
robertphillips@google.com58b20212012-06-27 20:44:52 +0000119 */
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000120bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000121 GrTextureDesc desc;
122 desc.fWidth = fBM.width();
123 desc.fHeight = fBM.height();
124 desc.fConfig = kAlpha_8_GrPixelConfig;
125
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000126 texture->set(fContext, desc);
127 return NULL != texture->texture();
robertphillips@google.com58b20212012-06-27 20:44:52 +0000128}
129
130/**
131 * Move the result of the software mask generation back to the gpu
132 */
robertphillips@google.comd92cf2e2013-07-19 18:13:02 +0000133void GrSWMaskHelper::toTexture(GrTexture *texture) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000134 SkAutoLockPixels alp(fBM);
135
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000136 texture->writePixels(0, 0, fBM.width(), fBM.height(),
robertphillips@google.com58b20212012-06-27 20:44:52 +0000137 kAlpha_8_GrPixelConfig,
138 fBM.getPixels(), fBM.rowBytes());
139}
140
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000141////////////////////////////////////////////////////////////////////////////////
142/**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000143 * Software rasterizes path to A8 mask (possibly using the context's matrix)
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000144 * and uploads the result to a scratch texture. Returns the resulting
145 * texture on success; NULL on failure.
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000146 */
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000147GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
148 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +0000149 const SkStrokeRec& stroke,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000150 const SkIRect& resultBounds,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000151 bool antiAlias,
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000152 SkMatrix* matrix) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000153 GrAutoScratchTexture ast;
154
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000155 GrSWMaskHelper helper(context);
156
157 if (!helper.init(resultBounds, matrix)) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000158 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000159 }
160
sugoi@google.com12b4e272012-12-06 20:13:11 +0000161 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000162
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000163 if (!helper.getTexture(&ast)) {
164 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000165 }
166
robertphillips@google.comd92cf2e2013-07-19 18:13:02 +0000167 helper.toTexture(ast.texture());
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000168
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000169 return ast.detach();
170}
171
172void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
173 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000174 const SkIRect& rect) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000175 GrDrawState* drawState = target->drawState();
176
bsalomon@google.com137f1342013-05-29 21:27:53 +0000177 GrDrawState::AutoViewMatrixRestore avmr;
178 if (!avmr.setIdentity(drawState)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000179 return;
180 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000181 GrDrawState::AutoRestoreEffects are(drawState);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000182
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000183 SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
184 SK_Scalar1 * rect.fTop,
185 SK_Scalar1 * rect.fRight,
186 SK_Scalar1 * rect.fBottom);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000187
188 // We want to use device coords to compute the texture coordinates. We set our matrix to be
189 // equal to the view matrix followed by a translation so that the top-left of the device bounds
190 // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
191 // vertex positions rather than local coords.
192 SkMatrix maskMatrix;
193 maskMatrix.setIDiv(texture->width(), texture->height());
194 maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
195 maskMatrix.preConcat(drawState->getViewMatrix());
196
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000197 drawState->addCoverageEffect(
bsalomon@google.comc7818882013-03-20 19:19:53 +0000198 GrSimpleTextureEffect::Create(texture,
199 maskMatrix,
200 false,
201 GrEffect::kPosition_CoordsType))->unref();
202
203 target->drawSimpleRect(dstRect);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000204}