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 ////////////////////////////////////////////////////////////////////////////////
canDrawPath(const GrDrawTarget *,const GrPipelineBuilder *,const SkMatrix & viewMatrix,const SkPath &,const GrStrokeInfo & stroke,bool antiAlias) const15 bool 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
30 GrPathRenderer::StencilSupport
onGetStencilSupport(const GrDrawTarget *,const GrPipelineBuilder *,const SkPath &,const GrStrokeInfo &) const31 GrSoftwarePathRenderer::onGetStencilSupport(const GrDrawTarget*,
32 const GrPipelineBuilder*,
33 const SkPath&,
34 const GrStrokeInfo&) const {
35 return GrPathRenderer::kNoSupport_StencilSupport;
36 }
37
38 namespace {
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.
get_path_and_clip_bounds(const GrDrawTarget * target,const GrPipelineBuilder * pipelineBuilder,const SkPath & path,const SkMatrix & matrix,SkIRect * devPathBounds,SkIRect * devClipBounds)44 bool 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 ////////////////////////////////////////////////////////////////////////////////
draw_around_inv_path(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,GrColor color,const SkMatrix & viewMatrix,const SkIRect & devClipBounds,const SkIRect & devPathBounds)82 void 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
onDrawPath(GrDrawTarget * target,GrPipelineBuilder * pipelineBuilder,GrColor color,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & stroke,bool antiAlias)120 bool 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