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 "GrGpu.h" 11 12 #include "SkStrokeRec.h" 13 14 // TODO: try to remove this #include 15 #include "GrContext.h" 16 17 namespace { 18 /* 19 * Convert a boolean operation into a transfer mode code 20 */ 21 SkXfermode::Mode op_to_mode(SkRegion::Op op) { 22 23 static const SkXfermode::Mode modeMap[] = { 24 SkXfermode::kDstOut_Mode, // kDifference_Op 25 SkXfermode::kModulate_Mode, // kIntersect_Op 26 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 35 } 36 37 /** 38 * Draw a single rect element of the clip stack into the accumulation bitmap 39 */ 40 void GrSWMaskHelper::draw(const GrRect& rect, SkRegion::Op op, 41 bool antiAlias, uint8_t alpha) { 42 SkPaint paint; 43 44 SkXfermode* mode = SkXfermode::Create(op_to_mode(op)); 45 46 paint.setXfermode(mode); 47 paint.setAntiAlias(antiAlias); 48 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); 49 50 fDraw.drawRect(rect, paint); 51 52 SkSafeUnref(mode); 53 } 54 55 /** 56 * Draw a single path element of the clip stack into the accumulation bitmap 57 */ 58 void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op, 59 bool antiAlias, uint8_t alpha) { 60 61 SkPaint paint; 62 if (stroke.isHairlineStyle()) { 63 paint.setStyle(SkPaint::kStroke_Style); 64 paint.setStrokeWidth(SK_Scalar1); 65 } else { 66 if (stroke.isFillStyle()) { 67 paint.setStyle(SkPaint::kFill_Style); 68 } else { 69 paint.setStyle(SkPaint::kStroke_Style); 70 paint.setStrokeJoin(stroke.getJoin()); 71 paint.setStrokeCap(stroke.getCap()); 72 paint.setStrokeWidth(stroke.getWidth()); 73 } 74 } 75 76 SkXfermode* mode = SkXfermode::Create(op_to_mode(op)); 77 78 paint.setXfermode(mode); 79 paint.setAntiAlias(antiAlias); 80 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); 81 82 fDraw.drawPath(path, paint); 83 84 SkSafeUnref(mode); 85 } 86 87 bool GrSWMaskHelper::init(const GrIRect& resultBounds, 88 const SkMatrix* matrix) { 89 if (NULL != matrix) { 90 fMatrix = *matrix; 91 } else { 92 fMatrix.setIdentity(); 93 } 94 95 // Now translate so the bound's UL corner is at the origin 96 fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1, 97 -resultBounds.fTop * SK_Scalar1); 98 GrIRect bounds = GrIRect::MakeWH(resultBounds.width(), 99 resultBounds.height()); 100 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 /** 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, uint8_t alpha) { 134 SkAutoLockPixels alp(fBM); 135 136 // The destination texture is almost always larger than "fBM". Clear 137 // it appropriately so we don't get mask artifacts outside of the path's 138 // bounding box 139 140 // "texture" needs to be installed as the render target for the clear 141 // and the texture upload but cannot remain the render target upon 142 // return. Callers typically use it as a texture and it would then 143 // be both source and dest. 144 GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(), 145 texture->asRenderTarget()); 146 147 fContext->getGpu()->clear(NULL, GrColorPackRGBA(alpha, alpha, alpha, alpha)); 148 149 texture->writePixels(0, 0, fBM.width(), fBM.height(), 150 kAlpha_8_GrPixelConfig, 151 fBM.getPixels(), fBM.rowBytes()); 152 } 153 154 //////////////////////////////////////////////////////////////////////////////// 155 /** 156 * Software rasterizes path to A8 mask (possibly using the context's matrix) 157 * and uploads the result to a scratch texture. Returns the resulting 158 * texture on success; NULL on failure. 159 */ 160 GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context, 161 const SkPath& path, 162 const SkStrokeRec& stroke, 163 const GrIRect& resultBounds, 164 bool antiAlias, 165 SkMatrix* matrix) { 166 GrAutoScratchTexture ast; 167 168 GrSWMaskHelper helper(context); 169 170 if (!helper.init(resultBounds, matrix)) { 171 return NULL; 172 } 173 174 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); 175 176 if (!helper.getTexture(&ast)) { 177 return NULL; 178 } 179 180 helper.toTexture(ast.texture(), 0x00); 181 182 return ast.detach(); 183 } 184 185 void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, 186 GrDrawTarget* target, 187 const GrIRect& rect) { 188 GrDrawState* drawState = target->drawState(); 189 190 GrDrawState::AutoDeviceCoordDraw adcd(drawState); 191 if (!adcd.succeeded()) { 192 return; 193 } 194 enum { 195 // the SW path renderer shares this stage with glyph 196 // rendering (kGlyphMaskStage in GrBatchedTextContext) 197 kPathMaskStage = GrPaint::kTotalStages, 198 }; 199 GrAssert(!drawState->isStageEnabled(kPathMaskStage)); 200 drawState->createTextureEffect(kPathMaskStage, texture, SkMatrix::I()); 201 SkScalar w = SkIntToScalar(rect.width()); 202 SkScalar h = SkIntToScalar(rect.height()); 203 GrRect maskRect = GrRect::MakeWH(w / texture->width(), 204 h / texture->height()); 205 206 const GrRect* srcRects[GrDrawState::kNumStages] = { NULL }; 207 srcRects[kPathMaskStage] = &maskRect; 208 GrRect dstRect = GrRect::MakeLTRB( 209 SK_Scalar1 * rect.fLeft, 210 SK_Scalar1 * rect.fTop, 211 SK_Scalar1 * rect.fRight, 212 SK_Scalar1 * rect.fBottom); 213 target->drawRect(dstRect, NULL, srcRects, NULL); 214 drawState->disableStage(kPathMaskStage); 215 } 216