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#include "batches/GrRectBatchFactory.h"
14
15////////////////////////////////////////////////////////////////////////////////
16bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
17    if (nullptr == fContext) {
18        return false;
19    }
20    if (args.fStroke->isDashed()) {
21        return false;
22    }
23    return true;
24}
25
26namespace {
27
28////////////////////////////////////////////////////////////////////////////////
29// gets device coord bounds of path (not considering the fill) and clip. The
30// path bounds will be a subset of the clip bounds. returns false if
31// path bounds would be empty.
32bool get_path_and_clip_bounds(const GrPipelineBuilder* pipelineBuilder,
33                              const SkPath& path,
34                              const SkMatrix& matrix,
35                              SkIRect* devPathBounds,
36                              SkIRect* devClipBounds) {
37    // compute bounds as intersection of rt size, clip, and path
38    const GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
39    if (nullptr == rt) {
40        return false;
41    }
42
43    pipelineBuilder->clip().getConservativeBounds(rt->width(), rt->height(), devClipBounds);
44
45    if (devClipBounds->isEmpty()) {
46        *devPathBounds = SkIRect::MakeWH(rt->width(), rt->height());
47        return false;
48    }
49
50    if (!path.getBounds().isEmpty()) {
51        SkRect pathSBounds;
52        matrix.mapRect(&pathSBounds, path.getBounds());
53        SkIRect pathIBounds;
54        pathSBounds.roundOut(&pathIBounds);
55        *devPathBounds = *devClipBounds;
56        if (!devPathBounds->intersect(pathIBounds)) {
57            // set the correct path bounds, as this would be used later.
58            *devPathBounds = pathIBounds;
59            return false;
60        }
61    } else {
62        *devPathBounds = SkIRect::EmptyIRect();
63        return false;
64    }
65    return true;
66}
67
68////////////////////////////////////////////////////////////////////////////////
69static void draw_non_aa_rect(GrDrawTarget* drawTarget,
70                             const GrPipelineBuilder& pipelineBuilder,
71                             GrColor color,
72                             const SkMatrix& viewMatrix,
73                             const SkRect& rect,
74                             const SkMatrix& localMatrix) {
75    SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect,
76                                                                        nullptr, &localMatrix));
77    drawTarget->drawBatch(pipelineBuilder, batch);
78}
79
80void draw_around_inv_path(GrDrawTarget* target,
81                          GrPipelineBuilder* pipelineBuilder,
82                          GrColor color,
83                          const SkMatrix& viewMatrix,
84                          const SkIRect& devClipBounds,
85                          const SkIRect& devPathBounds) {
86    SkMatrix invert;
87    if (!viewMatrix.invert(&invert)) {
88        return;
89    }
90
91    SkRect rect;
92    if (devClipBounds.fTop < devPathBounds.fTop) {
93        rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
94                  devClipBounds.fRight, devPathBounds.fTop);
95        draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert);
96    }
97    if (devClipBounds.fLeft < devPathBounds.fLeft) {
98        rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
99                  devPathBounds.fLeft, devPathBounds.fBottom);
100        draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert);
101    }
102    if (devClipBounds.fRight > devPathBounds.fRight) {
103        rect.iset(devPathBounds.fRight, devPathBounds.fTop,
104                  devClipBounds.fRight, devPathBounds.fBottom);
105        draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert);
106    }
107    if (devClipBounds.fBottom > devPathBounds.fBottom) {
108        rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
109                  devClipBounds.fRight, devClipBounds.fBottom);
110        draw_non_aa_rect(target, *pipelineBuilder, color, SkMatrix::I(), rect, invert);
111    }
112}
113
114}
115
116////////////////////////////////////////////////////////////////////////////////
117// return true on success; false on failure
118bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) {
119    GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), "GrSoftwarePathRenderer::onDrawPath");
120    if (nullptr == fContext) {
121        return false;
122    }
123
124    SkIRect devPathBounds, devClipBounds;
125    if (!get_path_and_clip_bounds(args.fPipelineBuilder, *args.fPath,
126                                  *args.fViewMatrix, &devPathBounds, &devClipBounds)) {
127        if (args.fPath->isInverseFillType()) {
128            draw_around_inv_path(args.fTarget, args.fPipelineBuilder, args.fColor,
129                                 *args.fViewMatrix, devClipBounds, devPathBounds);
130        }
131        return true;
132    }
133
134    SkAutoTUnref<GrTexture> texture(
135            GrSWMaskHelper::DrawPathMaskToTexture(fContext, *args.fPath, *args.fStroke,
136                                                  devPathBounds,
137                                                  args.fAntiAlias, args.fViewMatrix));
138    if (nullptr == texture) {
139        return false;
140    }
141
142    GrSWMaskHelper::DrawToTargetWithPathMask(texture, args.fTarget, args.fPipelineBuilder,
143                                             args.fColor, *args.fViewMatrix, devPathBounds);
144
145    if (args.fPath->isInverseFillType()) {
146        draw_around_inv_path(args.fTarget, args.fPipelineBuilder, args.fColor, *args.fViewMatrix,
147                             devClipBounds, devPathBounds);
148    }
149
150    return true;
151}
152