/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrSWMaskHelper.h" #include "GrDrawState.h" #include "GrGpu.h" // TODO: try to remove this #include #include "GrContext.h" namespace { /* * Convert a boolean operation into a transfer mode code */ SkXfermode::Mode op_to_mode(SkRegion::Op op) { static const SkXfermode::Mode modeMap[] = { SkXfermode::kDstOut_Mode, // kDifference_Op SkXfermode::kMultiply_Mode, // kIntersect_Op SkXfermode::kSrcOver_Mode, // kUnion_Op SkXfermode::kXor_Mode, // kXOR_Op SkXfermode::kClear_Mode, // kReverseDifference_Op SkXfermode::kSrc_Mode, // kReplace_Op }; return modeMap[op]; } //////////////////////////////////////////////////////////////////////////////// SkPath::FillType gr_fill_to_sk_fill(GrPathFill fill) { switch (fill) { case kWinding_GrPathFill: return SkPath::kWinding_FillType; case kEvenOdd_GrPathFill: return SkPath::kEvenOdd_FillType; case kInverseWinding_GrPathFill: return SkPath::kInverseWinding_FillType; case kInverseEvenOdd_GrPathFill: return SkPath::kInverseEvenOdd_FillType; default: GrCrash("Unexpected fill."); return SkPath::kWinding_FillType; } } } /** * Draw a single rect element of the clip stack into the accumulation bitmap */ void GrSWMaskHelper::draw(const GrRect& clientRect, SkRegion::Op op, bool antiAlias, GrColor color) { SkPaint paint; SkXfermode* mode = SkXfermode::Create(op_to_mode(op)); paint.setXfermode(mode); paint.setAntiAlias(antiAlias); paint.setColor(color); fDraw.drawRect(clientRect, paint); SkSafeUnref(mode); } /** * Draw a single path element of the clip stack into the accumulation bitmap */ void GrSWMaskHelper::draw(const SkPath& clientPath, SkRegion::Op op, GrPathFill fill, bool antiAlias, GrColor color) { SkPaint paint; SkPath tmpPath; const SkPath* pathToDraw = &clientPath; if (kHairLine_GrPathFill == fill) { paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SK_Scalar1); } else { paint.setStyle(SkPaint::kFill_Style); SkPath::FillType skfill = gr_fill_to_sk_fill(fill); if (skfill != pathToDraw->getFillType()) { tmpPath = *pathToDraw; tmpPath.setFillType(skfill); pathToDraw = &tmpPath; } } SkXfermode* mode = SkXfermode::Create(op_to_mode(op)); paint.setXfermode(mode); paint.setAntiAlias(antiAlias); paint.setColor(color); fDraw.drawPath(*pathToDraw, paint); SkSafeUnref(mode); } bool GrSWMaskHelper::init(const GrIRect& pathDevBounds, const GrPoint* translate, bool useMatrix) { if (useMatrix) { fMatrix = fContext->getMatrix(); } else { fMatrix.setIdentity(); } if (NULL != translate) { fMatrix.postTranslate(translate->fX, translate->fY); } fMatrix.postTranslate(-pathDevBounds.fLeft * SK_Scalar1, -pathDevBounds.fTop * SK_Scalar1); GrIRect bounds = GrIRect::MakeWH(pathDevBounds.width(), pathDevBounds.height()); fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom); if (!fBM.allocPixels()) { return false; } sk_bzero(fBM.getPixels(), fBM.getSafeSize()); sk_bzero(&fDraw, sizeof(fDraw)); fRasterClip.setRect(bounds); fDraw.fRC = &fRasterClip; fDraw.fClip = &fRasterClip.bwRgn(); fDraw.fMatrix = &fMatrix; fDraw.fBitmap = &fBM; return true; } /** * Get a texture (from the texture cache) of the correct size & format */ bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* tex) { GrTextureDesc desc; desc.fWidth = fBM.width(); desc.fHeight = fBM.height(); desc.fConfig = kAlpha_8_GrPixelConfig; tex->set(fContext, desc); GrTexture* texture = tex->texture(); if (NULL == texture) { return false; } return true; } /** * Move the result of the software mask generation back to the gpu */ void GrSWMaskHelper::toTexture(GrTexture *texture, bool clearToWhite) { SkAutoLockPixels alp(fBM); // The destination texture is almost always larger than "fBM". Clear // it appropriately so we don't get mask artifacts outside of the path's // bounding box // "texture" needs to be installed as the render target for the clear // and the texture upload but cannot remain the render target upon // returned. Callers typically use it as a texture and it would then // be both source and dest. GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(), texture->asRenderTarget()); if (clearToWhite) { fContext->getGpu()->clear(NULL, SK_ColorWHITE); } else { fContext->getGpu()->clear(NULL, 0x00000000); } texture->writePixels(0, 0, fBM.width(), fBM.height(), kAlpha_8_GrPixelConfig, fBM.getPixels(), fBM.rowBytes()); }