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////////////////////////////////////////////////////////////////////////////////
15bool 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
30GrPathRenderer::StencilSupport
31GrSoftwarePathRenderer::onGetStencilSupport(const GrDrawTarget*,
32                                            const GrPipelineBuilder*,
33                                            const SkPath&,
34                                            const GrStrokeInfo&) const {
35    return GrPathRenderer::kNoSupport_StencilSupport;
36}
37
38namespace {
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.
44bool 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////////////////////////////////////////////////////////////////////////////////
82void 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
120bool 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