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