1 2/* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "GrSoftwarePathRenderer.h" 10#include "GrContext.h" 11#include "GrSWMaskHelper.h" 12#include "GrVertexBuffer.h" 13 14//////////////////////////////////////////////////////////////////////////////// 15bool GrSoftwarePathRenderer::canDrawPath(const GrDrawTarget*, 16 const GrPipelineBuilder*, 17 const SkMatrix& viewMatrix, 18 const SkPath&, 19 const GrStrokeInfo& stroke, 20 bool antiAlias) const { 21 if (NULL == fContext) { 22 return false; 23 } 24 if (stroke.isDashed()) { 25 return false; 26 } 27 return true; 28} 29 30GrPathRenderer::StencilSupport 31GrSoftwarePathRenderer::onGetStencilSupport(const GrDrawTarget*, 32 const GrPipelineBuilder*, 33 const SkPath&, 34 const GrStrokeInfo&) const { 35 return GrPathRenderer::kNoSupport_StencilSupport; 36} 37 38namespace { 39 40//////////////////////////////////////////////////////////////////////////////// 41// gets device coord bounds of path (not considering the fill) and clip. The 42// path bounds will be a subset of the clip bounds. returns false if 43// path bounds would be empty. 44bool get_path_and_clip_bounds(const GrDrawTarget* target, 45 const GrPipelineBuilder* pipelineBuilder, 46 const SkPath& path, 47 const SkMatrix& matrix, 48 SkIRect* devPathBounds, 49 SkIRect* devClipBounds) { 50 // compute bounds as intersection of rt size, clip, and path 51 const GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); 52 if (NULL == rt) { 53 return false; 54 } 55 56 pipelineBuilder->clip().getConservativeBounds(rt, devClipBounds); 57 58 if (devClipBounds->isEmpty()) { 59 *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height()); 60 return false; 61 } 62 63 if (!path.getBounds().isEmpty()) { 64 SkRect pathSBounds; 65 matrix.mapRect(&pathSBounds, path.getBounds()); 66 SkIRect pathIBounds; 67 pathSBounds.roundOut(&pathIBounds); 68 *devPathBounds = *devClipBounds; 69 if (!devPathBounds->intersect(pathIBounds)) { 70 // set the correct path bounds, as this would be used later. 71 *devPathBounds = pathIBounds; 72 return false; 73 } 74 } else { 75 *devPathBounds = SkIRect::EmptyIRect(); 76 return false; 77 } 78 return true; 79} 80 81//////////////////////////////////////////////////////////////////////////////// 82void draw_around_inv_path(GrDrawTarget* target, 83 GrPipelineBuilder* pipelineBuilder, 84 GrColor color, 85 const SkMatrix& viewMatrix, 86 const SkIRect& devClipBounds, 87 const SkIRect& devPathBounds) { 88 SkMatrix invert; 89 if (!viewMatrix.invert(&invert)) { 90 return; 91 } 92 93 SkRect rect; 94 if (devClipBounds.fTop < devPathBounds.fTop) { 95 rect.iset(devClipBounds.fLeft, devClipBounds.fTop, 96 devClipBounds.fRight, devPathBounds.fTop); 97 target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert); 98 } 99 if (devClipBounds.fLeft < devPathBounds.fLeft) { 100 rect.iset(devClipBounds.fLeft, devPathBounds.fTop, 101 devPathBounds.fLeft, devPathBounds.fBottom); 102 target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert); 103 } 104 if (devClipBounds.fRight > devPathBounds.fRight) { 105 rect.iset(devPathBounds.fRight, devPathBounds.fTop, 106 devClipBounds.fRight, devPathBounds.fBottom); 107 target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert); 108 } 109 if (devClipBounds.fBottom > devPathBounds.fBottom) { 110 rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, 111 devClipBounds.fRight, devClipBounds.fBottom); 112 target->drawRect(pipelineBuilder, color, SkMatrix::I(), rect, NULL, &invert); 113 } 114} 115 116} 117 118//////////////////////////////////////////////////////////////////////////////// 119// return true on success; false on failure 120bool GrSoftwarePathRenderer::onDrawPath(GrDrawTarget* target, 121 GrPipelineBuilder* pipelineBuilder, 122 GrColor color, 123 const SkMatrix& viewMatrix, 124 const SkPath& path, 125 const GrStrokeInfo& stroke, 126 bool antiAlias) { 127 if (NULL == fContext) { 128 return false; 129 } 130 131 SkIRect devPathBounds, devClipBounds; 132 if (!get_path_and_clip_bounds(target, pipelineBuilder, path, viewMatrix, &devPathBounds, 133 &devClipBounds)) { 134 if (path.isInverseFillType()) { 135 draw_around_inv_path(target, pipelineBuilder, color, viewMatrix, devClipBounds, 136 devPathBounds); 137 } 138 return true; 139 } 140 141 SkAutoTUnref<GrTexture> texture( 142 GrSWMaskHelper::DrawPathMaskToTexture(fContext, path, stroke.getStrokeRec(), 143 devPathBounds, 144 antiAlias, &viewMatrix)); 145 if (NULL == texture) { 146 return false; 147 } 148 149 GrPipelineBuilder copy = *pipelineBuilder; 150 GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, ©, color, viewMatrix, 151 devPathBounds); 152 153 if (path.isInverseFillType()) { 154 draw_around_inv_path(target, pipelineBuilder, color, viewMatrix, devClipBounds, 155 devPathBounds); 156 } 157 158 return true; 159} 160