blob: f67336fe6cb64b6c044642c5d6de4c0f2d2704eb [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
12// TODO: try to remove this #include
13#include "GrContext.h"
14
15namespace {
16/*
17 * Convert a boolean operation into a transfer mode code
18 */
19SkXfermode::Mode op_to_mode(SkRegion::Op op) {
20
21 static const SkXfermode::Mode modeMap[] = {
22 SkXfermode::kDstOut_Mode, // kDifference_Op
23 SkXfermode::kMultiply_Mode, // kIntersect_Op
24 SkXfermode::kSrcOver_Mode, // kUnion_Op
25 SkXfermode::kXor_Mode, // kXOR_Op
26 SkXfermode::kClear_Mode, // kReverseDifference_Op
27 SkXfermode::kSrc_Mode, // kReplace_Op
28 };
29
30 return modeMap[op];
31}
32
33////////////////////////////////////////////////////////////////////////////////
34SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) {
35 switch (fill) {
36 case kWinding_GrPathFill:
37 return SkPath::kWinding_FillType;
38 case kEvenOdd_GrPathFill:
39 return SkPath::kEvenOdd_FillType;
40 case kInverseWinding_GrPathFill:
41 return SkPath::kInverseWinding_FillType;
42 case kInverseEvenOdd_GrPathFill:
43 return SkPath::kInverseEvenOdd_FillType;
44 default:
45 GrCrash("Unexpected fill.");
46 return SkPath::kWinding_FillType;
47 }
48}
49
50}
51
52/**
53 * Draw a single rect element of the clip stack into the accumulation bitmap
54 */
55void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op,
56 bool antiAlias, GrColor color) {
57 SkPaint paint;
58
59 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
60
61 paint.setXfermode(mode);
62 paint.setAntiAlias(antiAlias);
63 paint.setColor(color);
64
65 fDraw.drawRect(clientRect, paint);
66
67 SkSafeUnref(mode);
68}
69
70/**
71 * Draw a single path element of the clip stack into the accumulation bitmap
72 */
73void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op,
74 GrPathFill fill, bool antiAlias, GrColor color) {
75
76 SkPaint paint;
77 SkPath tmpPath;
78 const SkPath* pathToDraw = &clientPath;
79 if (kHairLine_GrPathFill == fill) {
80 paint.setStyle(SkPaint::kStroke_Style);
81 paint.setStrokeWidth(SK_Scalar1);
82 } else {
83 paint.setStyle(SkPaint::kFill_Style);
84 SkPath::FillType skfill = gr_fill_to_sk_fill(fill);
85 if (skfill != pathToDraw->getFillType()) {
86 tmpPath = *pathToDraw;
87 tmpPath.setFillType(skfill);
88 pathToDraw = &tmpPath;
89 }
90 }
91 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
92
93 paint.setXfermode(mode);
94 paint.setAntiAlias(antiAlias);
95 paint.setColor(color);
96
97 fDraw.drawPath(*pathToDraw, paint);
98
99 SkSafeUnref(mode);
100}
101
102bool GrSWMaskHelper::init(const GrIRect& pathDevBounds,
103 const GrPoint* translate,
104 bool useMatrix) {
105 if (useMatrix) {
106 fMatrix = fContext->getMatrix();
107 } else {
108 fMatrix.setIdentity();
109 }
110
111 if (NULL != translate) {
112 fMatrix.postTranslate(translate->fX, translate->fY);
113 }
114
115 fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1,
116 -pathDevBounds.fTop * SK_Scalar1);
117 GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(),
118 pathDevBounds.height());
119
120 fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
121 if (!fBM.allocPixels()) {
122 return false;
123 }
124 sk_bzero(fBM.getPixels(), fBM.getSafeSize());
125
126 sk_bzero(&fDraw, sizeof(fDraw));
127 fRasterClip.setRect(bounds);
128 fDraw.fRC = &fRasterClip;
129 fDraw.fClip = &fRasterClip.bwRgn();
130 fDraw.fMatrix = &fMatrix;
131 fDraw.fBitmap = &fBM;
132 return true;
133}
134
135/**
136 * Get a texture (from the texture cache) of the correct size & format
137 */
138bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) {
139 GrTextureDesc desc;
140 desc.fWidth = fBM.width();
141 desc.fHeight = fBM.height();
142 desc.fConfig = kAlpha_8_GrPixelConfig;
143
144 tex->set(fContext, desc);
145 GrTexture* texture = tex->texture();
146
147 if (NULL == texture) {
148 return false;
149 }
150
151 return true;
152}
153
154/**
155 * Move the result of the software mask generation back to the gpu
156 */
157void GrSWMaskHelper::toTexture(GrTexture *texture, bool clearToWhite) {
158 SkAutoLockPixels alp(fBM);
159
160 // The destination texture is almost always larger than "fBM". Clear
161 // it appropriately so we don't get mask artifacts outside of the path's
162 // bounding box
163
164 // "texture" needs to be installed as the render target for the clear
165 // and the texture upload but cannot remain the render target upon
166 // returned. Callers typically use it as a texture and it would then
167 // be both source and dest.
168 GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(),
169 texture->asRenderTarget());
170
171 if (clearToWhite) {
172 fContext->getGpu()->clear(NULL, SK_ColorWHITE);
173 } else {
174 fContext->getGpu()->clear(NULL, 0x00000000);
175 }
176
177 texture->writePixels(0, 0, fBM.width(), fBM.height(),
178 kAlpha_8_GrPixelConfig,
179 fBM.getPixels(), fBM.rowBytes());
180}
181