blob: 5b570b4b74a13d6b5897a4ad10cdf5b7cc452936 [file] [log] [blame]
robertphillips@google.comf4c2c522012-04-27 12:08:47 +00001
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"
robertphillips@google.comed4155d2012-05-01 14:30:24 +000010#include "GrContext.h"
robertphillips@google.com58b20212012-06-27 20:44:52 +000011#include "GrSWMaskHelper.h"
robertphillips@google.comf4c2c522012-04-27 12:08:47 +000012
robertphillips@google.comed4155d2012-05-01 14:30:24 +000013////////////////////////////////////////////////////////////////////////////////
robertphillips@google.comf4c2c522012-04-27 12:08:47 +000014bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
15 GrPathFill fill,
16 const GrDrawTarget* target,
17 bool antiAlias) const {
robertphillips@google.comed4155d2012-05-01 14:30:24 +000018 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
robertphillips@google.comf4c2c522012-04-27 12:08:47 +000025 return false;
26 }
27
robertphillips@google.comed4155d2012-05-01 14:30:24 +000028 return true;
robertphillips@google.comf4c2c522012-04-27 12:08:47 +000029}
30
robertphillips@google.comed4155d2012-05-01 14:30:24 +000031namespace {
32
33////////////////////////////////////////////////////////////////////////////////
robertphillips@google.comed4155d2012-05-01 14:30:24 +000034// gets device coord bounds of path (not considering the fill) and clip. The
35// path bounds will be a subset of the clip bounds. returns false if
36// path bounds would be empty.
37bool get_path_and_clip_bounds(const GrDrawTarget* target,
38 const SkPath& path,
robertphillips@google.com366f1c62012-06-29 21:38:47 +000039 const GrMatrix& matrix,
robertphillips@google.comed4155d2012-05-01 14:30:24 +000040 GrIRect* pathBounds,
41 GrIRect* clipBounds) {
42 // compute bounds as intersection of rt size, clip, and path
43 const GrRenderTarget* rt = target->getDrawState().getRenderTarget();
44 if (NULL == rt) {
45 return false;
46 }
47 *pathBounds = GrIRect::MakeWH(rt->width(), rt->height());
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000048
robertphillips@google.come4d69c02012-07-26 21:37:40 +000049 target->getClip()->getConservativeBounds(rt, clipBounds);
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000050 if (!pathBounds->intersect(*clipBounds)) {
51 return false;
robertphillips@google.comed4155d2012-05-01 14:30:24 +000052 }
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000053
robertphillips@google.com366f1c62012-06-29 21:38:47 +000054 if (!path.getBounds().isEmpty()) {
55 GrRect pathSBounds;
56 matrix.mapRect(&pathSBounds, path.getBounds());
robertphillips@google.comed4155d2012-05-01 14:30:24 +000057 GrIRect pathIBounds;
58 pathSBounds.roundOut(&pathIBounds);
59 if (!pathBounds->intersect(pathIBounds)) {
bsalomon@google.com276c1fa2012-06-19 13:22:45 +000060 // set the correct path bounds, as this would be used later.
61 *pathBounds = pathIBounds;
robertphillips@google.comed4155d2012-05-01 14:30:24 +000062 return false;
63 }
64 } else {
bsalomon@google.com276c1fa2012-06-19 13:22:45 +000065 *pathBounds = GrIRect::EmptyIRect();
robertphillips@google.comed4155d2012-05-01 14:30:24 +000066 return false;
67 }
68 return true;
69}
70
71////////////////////////////////////////////////////////////////////////////////
robertphillips@google.comed4155d2012-05-01 14:30:24 +000072void draw_around_inv_path(GrDrawTarget* target,
robertphillips@google.comed4155d2012-05-01 14:30:24 +000073 const GrIRect& clipBounds,
74 const GrIRect& pathBounds) {
bsalomon@google.come3d32162012-07-20 13:37:06 +000075 GrDrawTarget::AutoDeviceCoordDraw adcd(target);
76 if (!adcd.succeeded()) {
77 return;
78 }
robertphillips@google.comed4155d2012-05-01 14:30:24 +000079 GrRect rect;
80 if (clipBounds.fTop < pathBounds.fTop) {
81 rect.iset(clipBounds.fLeft, clipBounds.fTop,
82 clipBounds.fRight, pathBounds.fTop);
bsalomon@google.come3d32162012-07-20 13:37:06 +000083 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000084 }
85 if (clipBounds.fLeft < pathBounds.fLeft) {
86 rect.iset(clipBounds.fLeft, pathBounds.fTop,
87 pathBounds.fLeft, pathBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +000088 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000089 }
90 if (clipBounds.fRight > pathBounds.fRight) {
91 rect.iset(pathBounds.fRight, pathBounds.fTop,
92 clipBounds.fRight, pathBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +000093 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000094 }
95 if (clipBounds.fBottom > pathBounds.fBottom) {
96 rect.iset(clipBounds.fLeft, pathBounds.fBottom,
97 clipBounds.fRight, clipBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +000098 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000099 }
100}
101
102}
103
104////////////////////////////////////////////////////////////////////////////////
105// return true on success; false on failure
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000106bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
107 GrPathFill fill,
108 const GrVec* translate,
109 GrDrawTarget* target,
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000110 bool antiAlias) {
111
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000112 if (NULL == fContext) {
113 return false;
114 }
115
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000116 GrDrawState* drawState = target->drawState();
117
118 GrMatrix vm = drawState->getViewMatrix();
119 if (NULL != translate) {
120 vm.postTranslate(translate->fX, translate->fY);
121 }
122
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000123 GrIRect pathBounds, clipBounds;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000124 if (!get_path_and_clip_bounds(target, path, vm,
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000125 &pathBounds, &clipBounds)) {
bsalomon@google.com276c1fa2012-06-19 13:22:45 +0000126 if (GrIsFillInverted(fill)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000127 draw_around_inv_path(target, clipBounds, pathBounds);
bsalomon@google.com276c1fa2012-06-19 13:22:45 +0000128 }
129 return true;
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000130 }
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000131
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000132 SkAutoTUnref<GrTexture> texture(
133 GrSWMaskHelper::DrawPathMaskToTexture(fContext, path,
134 pathBounds, fill,
135 antiAlias, &vm));
136 if (NULL == texture) {
137 return false;
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000138 }
139
bsalomon@google.come3d32162012-07-20 13:37:06 +0000140 GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, pathBounds);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000141
142 if (GrIsFillInverted(fill)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000143 draw_around_inv_path(target, clipBounds, pathBounds);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000144 }
145
146 return true;
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000147}