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 13//////////////////////////////////////////////////////////////////////////////// 14bool GrSoftwarePathRenderer::canDrawPath(const SkPath&, 15 const SkStrokeRec&, 16 const GrDrawTarget*, 17 bool antiAlias) const { 18 if (!antiAlias || NULL == fContext) { 19 // TODO: We could allow the SW path to also handle non-AA paths but 20 // this would mean that GrDefaultPathRenderer would never be called 21 // (since it appears after the SW renderer in the path renderer 22 // chain). Some testing would need to be done r.e. performance 23 // and consistency of the resulting images before removing 24 // the "!antiAlias" clause from the above test 25 return false; 26 } 27 28 return true; 29} 30 31GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport( 32 const SkPath&, 33 const SkStrokeRec&, 34 const GrDrawTarget*) 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 SkPath& path, 46 const SkMatrix& matrix, 47 SkIRect* devPathBounds, 48 SkIRect* devClipBounds) { 49 // compute bounds as intersection of rt size, clip, and path 50 const GrRenderTarget* rt = target->getDrawState().getRenderTarget(); 51 if (NULL == rt) { 52 return false; 53 } 54 *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height()); 55 56 target->getClip()->getConservativeBounds(rt, devClipBounds); 57 58 // TODO: getConservativeBounds already intersects with the 59 // render target's bounding box. Remove this next line 60 if (!devPathBounds->intersect(*devClipBounds)) { 61 return false; 62 } 63 64 if (!path.getBounds().isEmpty()) { 65 SkRect pathSBounds; 66 matrix.mapRect(&pathSBounds, path.getBounds()); 67 SkIRect pathIBounds; 68 pathSBounds.roundOut(&pathIBounds); 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 const SkIRect& devClipBounds, 84 const SkIRect& devPathBounds) { 85 GrDrawState::AutoViewMatrixRestore avmr; 86 if (!avmr.setIdentity(target->drawState())) { 87 return; 88 } 89 SkRect rect; 90 if (devClipBounds.fTop < devPathBounds.fTop) { 91 rect.iset(devClipBounds.fLeft, devClipBounds.fTop, 92 devClipBounds.fRight, devPathBounds.fTop); 93 target->drawSimpleRect(rect, NULL); 94 } 95 if (devClipBounds.fLeft < devPathBounds.fLeft) { 96 rect.iset(devClipBounds.fLeft, devPathBounds.fTop, 97 devPathBounds.fLeft, devPathBounds.fBottom); 98 target->drawSimpleRect(rect, NULL); 99 } 100 if (devClipBounds.fRight > devPathBounds.fRight) { 101 rect.iset(devPathBounds.fRight, devPathBounds.fTop, 102 devClipBounds.fRight, devPathBounds.fBottom); 103 target->drawSimpleRect(rect, NULL); 104 } 105 if (devClipBounds.fBottom > devPathBounds.fBottom) { 106 rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, 107 devClipBounds.fRight, devClipBounds.fBottom); 108 target->drawSimpleRect(rect, NULL); 109 } 110} 111 112} 113 114//////////////////////////////////////////////////////////////////////////////// 115// return true on success; false on failure 116bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path, 117 const SkStrokeRec& stroke, 118 GrDrawTarget* target, 119 bool antiAlias) { 120 121 if (NULL == fContext) { 122 return false; 123 } 124 125 GrDrawState* drawState = target->drawState(); 126 127 SkMatrix vm = drawState->getViewMatrix(); 128 129 SkIRect devPathBounds, devClipBounds; 130 if (!get_path_and_clip_bounds(target, path, vm, 131 &devPathBounds, &devClipBounds)) { 132 if (path.isInverseFillType()) { 133 draw_around_inv_path(target, devClipBounds, devPathBounds); 134 } 135 return true; 136 } 137 138 SkAutoTUnref<GrTexture> texture( 139 GrSWMaskHelper::DrawPathMaskToTexture(fContext, path, stroke, 140 devPathBounds, 141 antiAlias, &vm)); 142 if (NULL == texture) { 143 return false; 144 } 145 146 GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, devPathBounds); 147 148 if (path.isInverseFillType()) { 149 draw_around_inv_path(target, devClipBounds, devPathBounds); 150 } 151 152 return true; 153} 154