blob: 6d91ef90d1ba18b1ae519b573e92bbd6fc675632 [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
rmistry@google.comd6176b02012-08-23 18:14:13 +000022 // chain). Some testing would need to be done r.e. performance
robertphillips@google.comed4155d2012-05-01 14:30:24 +000023 // 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
rmistry@google.comd6176b02012-08-23 18:14:13 +000035// path bounds will be a subset of the clip bounds. returns false if
robertphillips@google.comed4155d2012-05-01 14:30:24 +000036// path bounds would be empty.
37bool get_path_and_clip_bounds(const GrDrawTarget* target,
38 const SkPath& path,
bsalomon@google.comb9086a02012-11-01 18:02:54 +000039 const SkMatrix& matrix,
robertphillips@google.com7b112892012-07-31 15:18:21 +000040 GrIRect* devPathBounds,
41 GrIRect* devClipBounds) {
robertphillips@google.comed4155d2012-05-01 14:30:24 +000042 // 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 }
robertphillips@google.com7b112892012-07-31 15:18:21 +000047 *devPathBounds = GrIRect::MakeWH(rt->width(), rt->height());
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000048
robertphillips@google.com7b112892012-07-31 15:18:21 +000049 target->getClip()->getConservativeBounds(rt, devClipBounds);
50
rmistry@google.comd6176b02012-08-23 18:14:13 +000051 // TODO: getConservativeBounds already intersects with the
robertphillips@google.com7b112892012-07-31 15:18:21 +000052 // render target's bounding box. Remove this next line
53 if (!devPathBounds->intersect(*devClipBounds)) {
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000054 return false;
robertphillips@google.comed4155d2012-05-01 14:30:24 +000055 }
robertphillips@google.com3e11c0b2012-07-11 18:20:35 +000056
robertphillips@google.com366f1c62012-06-29 21:38:47 +000057 if (!path.getBounds().isEmpty()) {
58 GrRect pathSBounds;
59 matrix.mapRect(&pathSBounds, path.getBounds());
robertphillips@google.comed4155d2012-05-01 14:30:24 +000060 GrIRect pathIBounds;
61 pathSBounds.roundOut(&pathIBounds);
robertphillips@google.com7b112892012-07-31 15:18:21 +000062 if (!devPathBounds->intersect(pathIBounds)) {
bsalomon@google.com276c1fa2012-06-19 13:22:45 +000063 // set the correct path bounds, as this would be used later.
robertphillips@google.com7b112892012-07-31 15:18:21 +000064 *devPathBounds = pathIBounds;
robertphillips@google.comed4155d2012-05-01 14:30:24 +000065 return false;
66 }
67 } else {
robertphillips@google.com7b112892012-07-31 15:18:21 +000068 *devPathBounds = GrIRect::EmptyIRect();
robertphillips@google.comed4155d2012-05-01 14:30:24 +000069 return false;
70 }
71 return true;
72}
73
74////////////////////////////////////////////////////////////////////////////////
robertphillips@google.comed4155d2012-05-01 14:30:24 +000075void draw_around_inv_path(GrDrawTarget* target,
robertphillips@google.com7b112892012-07-31 15:18:21 +000076 const GrIRect& devClipBounds,
77 const GrIRect& devPathBounds) {
bsalomon@google.com5b3e8902012-10-05 20:13:28 +000078 GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
bsalomon@google.come3d32162012-07-20 13:37:06 +000079 if (!adcd.succeeded()) {
80 return;
81 }
robertphillips@google.comed4155d2012-05-01 14:30:24 +000082 GrRect rect;
robertphillips@google.com7b112892012-07-31 15:18:21 +000083 if (devClipBounds.fTop < devPathBounds.fTop) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000084 rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
robertphillips@google.com7b112892012-07-31 15:18:21 +000085 devClipBounds.fRight, devPathBounds.fTop);
bsalomon@google.come3d32162012-07-20 13:37:06 +000086 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000087 }
robertphillips@google.com7b112892012-07-31 15:18:21 +000088 if (devClipBounds.fLeft < devPathBounds.fLeft) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000089 rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
robertphillips@google.com7b112892012-07-31 15:18:21 +000090 devPathBounds.fLeft, devPathBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +000091 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000092 }
robertphillips@google.com7b112892012-07-31 15:18:21 +000093 if (devClipBounds.fRight > devPathBounds.fRight) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000094 rect.iset(devPathBounds.fRight, devPathBounds.fTop,
robertphillips@google.com7b112892012-07-31 15:18:21 +000095 devClipBounds.fRight, devPathBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +000096 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +000097 }
robertphillips@google.com7b112892012-07-31 15:18:21 +000098 if (devClipBounds.fBottom > devPathBounds.fBottom) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000099 rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000100 devClipBounds.fRight, devClipBounds.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000101 target->drawSimpleRect(rect, NULL);
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000102 }
103}
104
105}
106
107////////////////////////////////////////////////////////////////////////////////
108// return true on success; false on failure
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000109bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
110 GrPathFill fill,
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000111 GrDrawTarget* target,
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000112 bool antiAlias) {
113
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000114 if (NULL == fContext) {
115 return false;
116 }
117
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000118 GrDrawState* drawState = target->drawState();
119
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000120 SkMatrix vm = drawState->getViewMatrix();
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000121
robertphillips@google.com7b112892012-07-31 15:18:21 +0000122 GrIRect devPathBounds, devClipBounds;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000123 if (!get_path_and_clip_bounds(target, path, vm,
robertphillips@google.com7b112892012-07-31 15:18:21 +0000124 &devPathBounds, &devClipBounds)) {
bsalomon@google.com276c1fa2012-06-19 13:22:45 +0000125 if (GrIsFillInverted(fill)) {
robertphillips@google.com7b112892012-07-31 15:18:21 +0000126 draw_around_inv_path(target, devClipBounds, devPathBounds);
bsalomon@google.com276c1fa2012-06-19 13:22:45 +0000127 }
128 return true;
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000129 }
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000130
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000131 SkAutoTUnref<GrTexture> texture(
rmistry@google.comd6176b02012-08-23 18:14:13 +0000132 GrSWMaskHelper::DrawPathMaskToTexture(fContext, path,
133 devPathBounds, fill,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000134 antiAlias, &vm));
135 if (NULL == texture) {
136 return false;
robertphillips@google.comed4155d2012-05-01 14:30:24 +0000137 }
138
robertphillips@google.com7b112892012-07-31 15:18:21 +0000139 GrSWMaskHelper::DrawToTargetWithPathMask(texture, target, devPathBounds);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000140
141 if (GrIsFillInverted(fill)) {
robertphillips@google.com7b112892012-07-31 15:18:21 +0000142 draw_around_inv_path(target, devClipBounds, devPathBounds);
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000143 }
144
145 return true;
robertphillips@google.comf4c2c522012-04-27 12:08:47 +0000146}