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, &copy, 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