• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ////////////////////////////////////////////////////////////////////////////////
canDrawPath(const SkPath &,const SkStrokeRec &,const GrDrawTarget *,bool antiAlias) const14 bool 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 
onGetStencilSupport(const SkPath &,const SkStrokeRec &,const GrDrawTarget *) const31 GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport(
32     const SkPath&,
33     const SkStrokeRec&,
34     const GrDrawTarget*) 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 SkPath & path,const SkMatrix & matrix,SkIRect * devPathBounds,SkIRect * devClipBounds)44 bool 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 ////////////////////////////////////////////////////////////////////////////////
draw_around_inv_path(GrDrawTarget * target,const SkIRect & devClipBounds,const SkIRect & devPathBounds)82 void 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
onDrawPath(const SkPath & path,const SkStrokeRec & stroke,GrDrawTarget * target,bool antiAlias)116 bool 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