|
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 //////////////////////////////////////////////////////////////////////////////// |
|
14 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 |
|
31 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. |
|
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 //////////////////////////////////////////////////////////////////////////////// |
|
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 |
|
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 } |