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 (NULL == fContext) { 19 return false; 20 } 21 22 return true; 23} 24 25GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport( 26 const SkPath&, 27 const SkStrokeRec&, 28 const GrDrawTarget*) const { 29 return GrPathRenderer::kNoSupport_StencilSupport; 30} 31 32namespace { 33 34//////////////////////////////////////////////////////////////////////////////// 35// gets device coord bounds of path (not considering the fill) and clip. The 36// path bounds will be a subset of the clip bounds. returns false if 37// path bounds would be empty. 38bool get_path_and_clip_bounds(const GrDrawTarget* target, 39 const SkPath& path, 40 const SkMatrix& matrix, 41 SkIRect* devPathBounds, 42 SkIRect* devClipBounds) { 43 // compute bounds as intersection of rt size, clip, and path 44 const GrRenderTarget* rt = target->getDrawState().getRenderTarget(); 45 if (NULL == rt) { 46 return false; 47 } 48 *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height()); 49 50 target->getClip()->getConservativeBounds(rt, devClipBounds); 51 52 // TODO: getConservativeBounds already intersects with the 53 // render target's bounding box. Remove this next line 54 if (!devPathBounds->intersect(*devClipBounds)) { 55 return false; 56 } 57 58 if (!path.getBounds().isEmpty()) { 59 SkRect pathSBounds; 60 matrix.mapRect(&pathSBounds, path.getBounds()); 61 SkIRect pathIBounds; 62 pathSBounds.roundOut(&pathIBounds); 63 if (!devPathBounds->intersect(pathIBounds)) { 64 // set the correct path bounds, as this would be used later. 65 *devPathBounds = pathIBounds; 66 return false; 67 } 68 } else { 69 *devPathBounds = SkIRect::EmptyIRect(); 70 return false; 71 } 72 return true; 73} 74 75//////////////////////////////////////////////////////////////////////////////// 76void draw_around_inv_path(GrDrawTarget* target, 77 const SkIRect& devClipBounds, 78 const SkIRect& devPathBounds) { 79 GrDrawState::AutoViewMatrixRestore avmr; 80 if (!avmr.setIdentity(target->drawState())) { 81 return; 82 } 83 SkRect rect; 84 if (devClipBounds.fTop < devPathBounds.fTop) { 85 rect.iset(devClipBounds.fLeft, devClipBounds.fTop, 86 devClipBounds.fRight, devPathBounds.fTop); 87 target->drawSimpleRect(rect); 88 } 89 if (devClipBounds.fLeft < devPathBounds.fLeft) { 90 rect.iset(devClipBounds.fLeft, devPathBounds.fTop, 91 devPathBounds.fLeft, devPathBounds.fBottom); 92 target->drawSimpleRect(rect); 93 } 94 if (devClipBounds.fRight > devPathBounds.fRight) { 95 rect.iset(devPathBounds.fRight, devPathBounds.fTop, 96 devClipBounds.fRight, devPathBounds.fBottom); 97 target->drawSimpleRect(rect); 98 } 99 if (devClipBounds.fBottom > devPathBounds.fBottom) { 100 rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, 101 devClipBounds.fRight, devClipBounds.fBottom); 102 target->drawSimpleRect(rect); 103 } 104} 105 106} 107 108//////////////////////////////////////////////////////////////////////////////// 109// return true on success; false on failure 110bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path, 111 const SkStrokeRec& stroke, 112 GrDrawTarget* target, 113 bool antiAlias) { 114 115 if (NULL == fContext) { 116 return false; 117 } 118 119 GrDrawState* drawState = target->drawState(); 120 121 SkMatrix vm = drawState->getViewMatrix(); 122 123 SkIRect devPathBounds, devClipBounds; 124 if (!get_path_and_clip_bounds(target, path, vm, 125 &devPathBounds, &devClipBounds)) { 126 if (path.isInverseFillType()) { 127 draw_around_inv_path(target, devClipBounds, devPathBounds); 128 } 129 return true; 130 } 131 132 SkAutoTUnref<GrTexture> texture( 133 GrSWMaskHelper::DrawPathMaskToTexture(fContext, path, stroke, 134 devPathBounds, 135 antiAlias, &vm)); 136 if (NULL == texture) { 137 return false; 138 } 139 140 GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, devPathBounds); 141 142 if (path.isInverseFillType()) { 143 draw_around_inv_path(target, devClipBounds, devPathBounds); 144 } 145 146 return true; 147} 148