OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrAAStrokeRectBatch.h" | 8 #include "GrAAStrokeRectBatch.h" |
9 | 9 |
10 #include "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
11 #include "GrDefaultGeoProcFactory.h" | 11 #include "GrDefaultGeoProcFactory.h" |
12 #include "GrResourceKey.h" | 12 #include "GrResourceKey.h" |
13 #include "GrResourceProvider.h" | 13 #include "GrResourceProvider.h" |
14 | 14 |
15 GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey); | 15 GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey); |
16 GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey); | 16 GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey); |
17 | 17 |
18 static void set_inset_fan(SkPoint* pts, size_t stride, | 18 static void set_inset_fan(SkPoint* pts, size_t stride, |
19 const SkRect& r, SkScalar dx, SkScalar dy) { | 19 const SkRect& r, SkScalar dx, SkScalar dy) { |
20 pts->setRectFan(r.fLeft + dx, r.fTop + dy, | 20 pts->setRectFan(r.fLeft + dx, r.fTop + dy, |
21 r.fRight - dx, r.fBottom - dy, stride); | 21 r.fRight - dx, r.fBottom - dy, stride); |
22 } | 22 } |
23 | 23 |
| 24 // We support all hairlines, bevels, and miters, but not round joins. Also, chec
k whether the miter |
| 25 // limit makes a miter join effectively beveled. |
| 26 inline static bool allowed_stroke(const SkStrokeRec& stroke, bool* isMiter) { |
| 27 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || |
| 28 stroke.getStyle() == SkStrokeRec::kHairline_Style); |
| 29 // For hairlines, make bevel and round joins appear the same as mitered ones
. |
| 30 if (!stroke.getWidth()) { |
| 31 *isMiter = true; |
| 32 return true; |
| 33 } |
| 34 if (stroke.getJoin() == SkPaint::kBevel_Join) { |
| 35 *isMiter = false; |
| 36 return true; |
| 37 } |
| 38 if (stroke.getJoin() == SkPaint::kMiter_Join) { |
| 39 *isMiter = stroke.getMiter() >= SK_ScalarSqrt2; |
| 40 return true; |
| 41 } |
| 42 return false; |
| 43 } |
| 44 |
| 45 static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect*
devInside, |
| 46 bool* isDegenerate, const SkMatrix& viewMatrix, const
SkRect& rect, |
| 47 SkScalar strokeWidth, bool miterStroke) { |
| 48 SkRect devRect; |
| 49 viewMatrix.mapRect(&devRect, rect); |
| 50 |
| 51 SkVector devStrokeSize; |
| 52 if (strokeWidth > 0) { |
| 53 devStrokeSize.set(strokeWidth, strokeWidth); |
| 54 viewMatrix.mapVectors(&devStrokeSize, 1); |
| 55 devStrokeSize.setAbs(devStrokeSize); |
| 56 } else { |
| 57 devStrokeSize.set(SK_Scalar1, SK_Scalar1); |
| 58 } |
| 59 |
| 60 const SkScalar dx = devStrokeSize.fX; |
| 61 const SkScalar dy = devStrokeSize.fY; |
| 62 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); |
| 63 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); |
| 64 |
| 65 *devOutside = devRect; |
| 66 *devOutsideAssist = devRect; |
| 67 *devInside = devRect; |
| 68 |
| 69 devOutside->outset(rx, ry); |
| 70 devInside->inset(rx, ry); |
| 71 |
| 72 // If we have a degenerate stroking rect(ie the stroke is larger than inner
rect) then we |
| 73 // make a degenerate inside rect to avoid double hitting. We will also jam
all of the points |
| 74 // together when we render these rects. |
| 75 SkScalar spare; |
| 76 { |
| 77 SkScalar w = devRect.width() - dx; |
| 78 SkScalar h = devRect.height() - dy; |
| 79 spare = SkTMin(w, h); |
| 80 } |
| 81 |
| 82 *isDegenerate = spare <= 0; |
| 83 if (*isDegenerate) { |
| 84 devInside->fLeft = devInside->fRight = devRect.centerX(); |
| 85 devInside->fTop = devInside->fBottom = devRect.centerY(); |
| 86 } |
| 87 |
| 88 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) |
| 89 // to draw the outside of the octagon. Because there are 8 vertices on the o
uter |
| 90 // edge, while vertex number of inner edge is 4, the same as miter-stroke. |
| 91 if (!miterStroke) { |
| 92 devOutside->inset(0, ry); |
| 93 devOutsideAssist->outset(0, ry); |
| 94 } |
| 95 } |
| 96 |
24 static sk_sp<GrGeometryProcessor> create_stroke_rect_gp(bool tweakAlphaForCovera
ge, | 97 static sk_sp<GrGeometryProcessor> create_stroke_rect_gp(bool tweakAlphaForCovera
ge, |
25 const SkMatrix& viewMatr
ix, | 98 const SkMatrix& viewMatr
ix, |
26 bool usesLocalCoords, | 99 bool usesLocalCoords, |
27 bool coverageIgnored) { | 100 bool coverageIgnored) { |
28 using namespace GrDefaultGeoProcFactory; | 101 using namespace GrDefaultGeoProcFactory; |
29 | 102 |
30 Color color(Color::kAttribute_Type); | 103 Color color(Color::kAttribute_Type); |
31 Coverage::Type coverageType; | 104 Coverage::Type coverageType; |
32 // TODO remove coverage if coverage is ignored | 105 // TODO remove coverage if coverage is ignored |
33 /*if (coverageIgnored) { | 106 /*if (coverageIgnored) { |
34 coverageType = Coverage::kNone_Type; | 107 coverageType = Coverage::kNone_Type; |
35 } else*/ if (tweakAlphaForCoverage) { | 108 } else*/ if (tweakAlphaForCoverage) { |
36 coverageType = Coverage::kSolid_Type; | 109 coverageType = Coverage::kSolid_Type; |
37 } else { | 110 } else { |
38 coverageType = Coverage::kAttribute_Type; | 111 coverageType = Coverage::kAttribute_Type; |
39 } | 112 } |
40 Coverage coverage(coverageType); | 113 Coverage coverage(coverageType); |
41 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : | 114 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type : |
42 LocalCoords::kUnused_Type); | 115 LocalCoords::kUnused_Type); |
43 return MakeForDeviceSpace(color, coverage, localCoords, viewMatrix); | 116 return MakeForDeviceSpace(color, coverage, localCoords, viewMatrix); |
44 } | 117 } |
45 | 118 |
46 class AAStrokeRectBatch : public GrVertexBatch { | 119 class AAStrokeRectBatch : public GrVertexBatch { |
47 public: | 120 public: |
48 DEFINE_BATCH_CLASS_ID | 121 DEFINE_BATCH_CLASS_ID |
49 | 122 |
50 // TODO support AA rotated stroke rects by copying around view matrices | 123 AAStrokeRectBatch(GrColor color, const SkMatrix& viewMatrix, |
51 struct Geometry { | 124 const SkRect& devOutside, const SkRect& devInside) |
52 SkRect fDevOutside; | 125 : INHERITED(ClassID()) |
53 SkRect fDevOutsideAssist; | 126 , fViewMatrix(viewMatrix) { |
54 SkRect fDevInside; | 127 SkASSERT(!devOutside.isEmpty()) |
55 GrColor fColor; | 128 SkASSERT(!devInside.isEmpty()) |
56 bool fDegenerate; | |
57 }; | |
58 | 129 |
59 static AAStrokeRectBatch* Create(const SkMatrix& viewMatrix, bool miterStrok
e) { | 130 fGeoData.emplace_back(Geometry{color, devOutside, devOutside, devInside,
false}); |
60 return new AAStrokeRectBatch(viewMatrix, miterStroke); | 131 fBounds = devOutside; |
| 132 fMiterStroke = true; |
| 133 } |
| 134 |
| 135 |
| 136 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const
SkRect& rect, |
| 137 const SkStrokeRec& stroke) { |
| 138 bool isMiter; |
| 139 if (!allowed_stroke(stroke, &isMiter)) { |
| 140 return nullptr; |
| 141 } |
| 142 |
| 143 AAStrokeRectBatch* batch = new AAStrokeRectBatch(); |
| 144 batch->fMiterStroke = isMiter; |
| 145 Geometry& geo = batch->fGeoData.push_back(); |
| 146 compute_rects(&geo.fDevOutside, &geo.fDevOutsideAssist, &geo.fDevInside,
&geo.fDegenerate, |
| 147 viewMatrix, rect, stroke.getWidth(), isMiter); |
| 148 geo.fColor = color; |
| 149 batch->fBounds = geo.fDevOutside; |
| 150 batch->fBounds.join(geo.fDevOutsideAssist); |
| 151 batch->fViewMatrix = viewMatrix; |
| 152 return batch; |
61 } | 153 } |
62 | 154 |
63 const char* name() const override { return "AAStrokeRect"; } | 155 const char* name() const override { return "AAStrokeRect"; } |
64 | 156 |
65 void computePipelineOptimizations(GrInitInvariantOutput* color, | 157 void computePipelineOptimizations(GrInitInvariantOutput* color, |
66 GrInitInvariantOutput* coverage, | 158 GrInitInvariantOutput* coverage, |
67 GrBatchToXPOverrides* overrides) const ove
rride { | 159 GrBatchToXPOverrides* overrides) const ove
rride { |
68 // When this is called on a batch, there is only one geometry bundle | 160 // When this is called on a batch, there is only one geometry bundle |
69 color->setKnownFourComponents(fGeoData[0].fColor); | 161 color->setKnownFourComponents(fGeoData[0].fColor); |
70 coverage->setUnknownSingleComponent(); | 162 coverage->setUnknownSingleComponent(); |
71 } | 163 } |
72 | 164 |
73 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
74 | |
75 bool canAppend(const SkMatrix& viewMatrix, bool miterStroke) { | |
76 return fViewMatrix.cheapEqualTo(viewMatrix) && fMiterStroke == miterStro
ke; | |
77 } | |
78 | |
79 void append(GrColor color, const SkRect& devOutside, const SkRect& devOutsid
eAssist, | |
80 const SkRect& devInside, bool degenerate) { | |
81 Geometry& geometry = fGeoData.push_back(); | |
82 geometry.fColor = color; | |
83 geometry.fDevOutside = devOutside; | |
84 geometry.fDevOutsideAssist = devOutsideAssist; | |
85 geometry.fDevInside = devInside; | |
86 geometry.fDegenerate = degenerate; | |
87 } | |
88 | |
89 void appendAndUpdateBounds(GrColor color, const SkRect& devOutside, | |
90 const SkRect& devOutsideAssist, const SkRect& dev
Inside, | |
91 bool degenerate) { | |
92 this->append(color, devOutside, devOutsideAssist, devInside, degenerate)
; | |
93 | |
94 SkRect bounds; | |
95 this->updateBounds(&bounds, fGeoData.back()); | |
96 this->joinBounds(bounds); | |
97 } | |
98 | |
99 void init() { this->updateBounds(&fBounds, fGeoData[0]); } | |
100 | |
101 private: | 165 private: |
102 void updateBounds(SkRect* bounds, const Geometry& geo) { | 166 AAStrokeRectBatch() : INHERITED(ClassID()) {} |
103 // If we have miterstroke then we inset devOutside and outset devOutside
Assist, so we need | |
104 // the join for proper bounds | |
105 *bounds = geo.fDevOutside; | |
106 bounds->join(geo.fDevOutsideAssist); | |
107 } | |
108 | 167 |
109 void onPrepareDraws(Target*) const override; | 168 void onPrepareDraws(Target*) const override; |
110 void initBatchTracker(const GrXPOverridesForBatch&) override; | 169 void initBatchTracker(const GrXPOverridesForBatch&) override; |
111 | 170 |
112 AAStrokeRectBatch(const SkMatrix& viewMatrix,bool miterStroke) | |
113 : INHERITED(ClassID()) { | |
114 fViewMatrix = viewMatrix; | |
115 fMiterStroke = miterStroke; | |
116 } | |
117 | |
118 static const int kMiterIndexCnt = 3 * 24; | 171 static const int kMiterIndexCnt = 3 * 24; |
119 static const int kMiterVertexCnt = 16; | 172 static const int kMiterVertexCnt = 16; |
120 static const int kNumMiterRectsInIndexBuffer = 256; | 173 static const int kNumMiterRectsInIndexBuffer = 256; |
121 | 174 |
122 static const int kBevelIndexCnt = 48 + 36 + 24; | 175 static const int kBevelIndexCnt = 48 + 36 + 24; |
123 static const int kBevelVertexCnt = 24; | 176 static const int kBevelVertexCnt = 24; |
124 static const int kNumBevelRectsInIndexBuffer = 256; | 177 static const int kNumBevelRectsInIndexBuffer = 256; |
125 | 178 |
126 static const GrBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider,
bool miterStroke); | 179 static const GrBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider,
bool miterStroke); |
127 | 180 |
128 GrColor color() const { return fBatch.fColor; } | 181 GrColor color() const { return fBatch.fColor; } |
129 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | 182 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
130 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } | 183 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } |
131 bool colorIgnored() const { return fBatch.fColorIgnored; } | 184 bool colorIgnored() const { return fBatch.fColorIgnored; } |
132 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | 185 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } |
133 const Geometry& geometry() const { return fGeoData[0]; } | |
134 const SkMatrix& viewMatrix() const { return fViewMatrix; } | 186 const SkMatrix& viewMatrix() const { return fViewMatrix; } |
135 bool miterStroke() const { return fMiterStroke; } | 187 bool miterStroke() const { return fMiterStroke; } |
136 | 188 |
137 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override; | 189 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override; |
138 | 190 |
139 void generateAAStrokeRectGeometry(void* vertices, | 191 void generateAAStrokeRectGeometry(void* vertices, |
140 size_t offset, | 192 size_t offset, |
141 size_t vertexStride, | 193 size_t vertexStride, |
142 int outerVertexNum, | 194 int outerVertexNum, |
143 int innerVertexNum, | 195 int innerVertexNum, |
144 GrColor color, | 196 GrColor color, |
145 const SkRect& devOutside, | 197 const SkRect& devOutside, |
146 const SkRect& devOutsideAssist, | 198 const SkRect& devOutsideAssist, |
147 const SkRect& devInside, | 199 const SkRect& devInside, |
148 bool miterStroke, | 200 bool miterStroke, |
149 bool degenerate, | 201 bool degenerate, |
150 bool tweakAlphaForCoverage) const; | 202 bool tweakAlphaForCoverage) const; |
151 | 203 |
152 struct BatchTracker { | 204 struct BatchTracker { |
153 GrColor fColor; | 205 GrColor fColor; |
154 bool fUsesLocalCoords; | 206 bool fUsesLocalCoords; |
155 bool fColorIgnored; | 207 bool fColorIgnored; |
156 bool fCoverageIgnored; | 208 bool fCoverageIgnored; |
157 bool fCanTweakAlphaForCoverage; | 209 bool fCanTweakAlphaForCoverage; |
158 }; | 210 }; |
159 | 211 |
| 212 // TODO support AA rotated stroke rects by copying around view matrices |
| 213 struct Geometry { |
| 214 GrColor fColor; |
| 215 SkRect fDevOutside; |
| 216 SkRect fDevOutsideAssist; |
| 217 SkRect fDevInside; |
| 218 bool fDegenerate; |
| 219 }; |
| 220 |
160 BatchTracker fBatch; | 221 BatchTracker fBatch; |
161 SkSTArray<1, Geometry, true> fGeoData; | 222 SkSTArray<1, Geometry, true> fGeoData; |
162 SkMatrix fViewMatrix; | 223 SkMatrix fViewMatrix; |
163 bool fMiterStroke; | 224 bool fMiterStroke; |
164 | 225 |
165 typedef GrVertexBatch INHERITED; | 226 typedef GrVertexBatch INHERITED; |
166 }; | 227 }; |
167 | 228 |
168 void AAStrokeRectBatch::initBatchTracker(const GrXPOverridesForBatch& overrides)
{ | 229 void AAStrokeRectBatch::initBatchTracker(const GrXPOverridesForBatch& overrides)
{ |
169 // Handle any color overrides | 230 // Handle any color overrides |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 | 406 |
346 // In the event of two batches, one who can tweak, one who cannot, we just f
all back to | 407 // In the event of two batches, one who can tweak, one who cannot, we just f
all back to |
347 // not tweaking | 408 // not tweaking |
348 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) { | 409 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) { |
349 fBatch.fCanTweakAlphaForCoverage = false; | 410 fBatch.fCanTweakAlphaForCoverage = false; |
350 } | 411 } |
351 | 412 |
352 if (this->color() != that->color()) { | 413 if (this->color() != that->color()) { |
353 fBatch.fColor = GrColor_ILLEGAL; | 414 fBatch.fColor = GrColor_ILLEGAL; |
354 } | 415 } |
355 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()); | 416 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
356 this->joinBounds(that->bounds()); | 417 this->joinBounds(that->bounds()); |
357 return true; | 418 return true; |
358 } | 419 } |
359 | 420 |
360 static void setup_scale(int* scale, SkScalar inset) { | 421 static void setup_scale(int* scale, SkScalar inset) { |
361 if (inset < SK_ScalarHalf) { | 422 if (inset < SK_ScalarHalf) { |
362 *scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); | 423 *scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); |
363 SkASSERT(*scale >= 0 && *scale <= 255); | 424 SkASSERT(*scale >= 0 && *scale <= 255); |
364 } else { | 425 } else { |
365 *scale = 0xff; | 426 *scale = 0xff; |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 for (int i = 0; i < innerVertexNum; ++i) { | 570 for (int i = 0; i < innerVertexNum; ++i) { |
510 if (tweakAlphaForCoverage) { | 571 if (tweakAlphaForCoverage) { |
511 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; | 572 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor; |
512 } else { | 573 } else { |
513 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; | 574 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
514 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)
) = innerCoverage; | 575 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)
) = innerCoverage; |
515 } | 576 } |
516 } | 577 } |
517 } | 578 } |
518 | 579 |
519 // We support all hairlines, bevels, and miters, but not round joins. Also, chec
k whether the miter | |
520 // limit makes a miter join effectively beveled. | |
521 inline static bool allowed_stroke(const SkStrokeRec& stroke, bool* isMiter) { | |
522 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || | |
523 stroke.getStyle() == SkStrokeRec::kHairline_Style); | |
524 // For hairlines, make bevel and round joins appear the same as mitered ones
. | |
525 if (!stroke.getWidth()) { | |
526 *isMiter = true; | |
527 return true; | |
528 } | |
529 if (stroke.getJoin() == SkPaint::kBevel_Join) { | |
530 *isMiter = false; | |
531 return true; | |
532 } | |
533 if (stroke.getJoin() == SkPaint::kMiter_Join) { | |
534 *isMiter = stroke.getMiter() >= SK_ScalarSqrt2; | |
535 return true; | |
536 } | |
537 return false; | |
538 } | |
539 | |
540 static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect*
devInside, | |
541 bool* isDegenerate, const SkMatrix& viewMatrix, const
SkRect& rect, | |
542 SkScalar strokeWidth, bool miterStroke) { | |
543 SkRect devRect; | |
544 viewMatrix.mapRect(&devRect, rect); | |
545 | |
546 SkVector devStrokeSize; | |
547 if (strokeWidth > 0) { | |
548 devStrokeSize.set(strokeWidth, strokeWidth); | |
549 viewMatrix.mapVectors(&devStrokeSize, 1); | |
550 devStrokeSize.setAbs(devStrokeSize); | |
551 } else { | |
552 devStrokeSize.set(SK_Scalar1, SK_Scalar1); | |
553 } | |
554 | |
555 const SkScalar dx = devStrokeSize.fX; | |
556 const SkScalar dy = devStrokeSize.fY; | |
557 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); | |
558 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); | |
559 | |
560 *devOutside = devRect; | |
561 *devOutsideAssist = devRect; | |
562 *devInside = devRect; | |
563 | |
564 devOutside->outset(rx, ry); | |
565 devInside->inset(rx, ry); | |
566 | |
567 // If we have a degenerate stroking rect(ie the stroke is larger than inner
rect) then we | |
568 // make a degenerate inside rect to avoid double hitting. We will also jam
all of the points | |
569 // together when we render these rects. | |
570 SkScalar spare; | |
571 { | |
572 SkScalar w = devRect.width() - dx; | |
573 SkScalar h = devRect.height() - dy; | |
574 spare = SkTMin(w, h); | |
575 } | |
576 | |
577 *isDegenerate = spare <= 0; | |
578 if (*isDegenerate) { | |
579 devInside->fLeft = devInside->fRight = devRect.centerX(); | |
580 devInside->fTop = devInside->fBottom = devRect.centerY(); | |
581 } | |
582 | |
583 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) | |
584 // to draw the outside of the octagon. Because there are 8 vertices on the o
uter | |
585 // edge, while vertex number of inner edge is 4, the same as miter-stroke. | |
586 if (!miterStroke) { | |
587 devOutside->inset(0, ry); | |
588 devOutsideAssist->outset(0, ry); | |
589 } | |
590 } | |
591 | |
592 namespace GrAAStrokeRectBatch { | 580 namespace GrAAStrokeRectBatch { |
593 | 581 |
594 GrDrawBatch* CreateFillBetweenRects(GrColor color, | 582 GrDrawBatch* CreateFillBetweenRects(GrColor color, |
595 const SkMatrix& viewMatrix, | 583 const SkMatrix& viewMatrix, |
596 const SkRect& devOutside, | 584 const SkRect& devOutside, |
597 const SkRect& devInside) { | 585 const SkRect& devInside) { |
598 SkASSERT(!devOutside.isEmpty()) | 586 return new AAStrokeRectBatch(color, viewMatrix, devOutside, devInside); |
599 SkASSERT(!devInside.isEmpty()) | |
600 AAStrokeRectBatch* batch = AAStrokeRectBatch::Create(viewMatrix, true); | |
601 batch->append(color, devOutside, devOutside, devInside, false); | |
602 batch->init(); | |
603 return batch; | |
604 } | 587 } |
605 | 588 |
606 GrDrawBatch* Create(GrColor color, | 589 GrDrawBatch* Create(GrColor color, |
607 const SkMatrix& viewMatrix, | 590 const SkMatrix& viewMatrix, |
608 const SkRect& rect, | 591 const SkRect& rect, |
609 const SkStrokeRec& stroke) { | 592 const SkStrokeRec& stroke) { |
610 bool isMiterStroke; | 593 return AAStrokeRectBatch::Create(color, viewMatrix, rect, stroke); |
611 if (!allowed_stroke(stroke, &isMiterStroke)) { | |
612 return nullptr; | |
613 } | |
614 AAStrokeRectBatch* batch = AAStrokeRectBatch::Create(viewMatrix, isMiterStro
ke); | |
615 | |
616 SkRect devOutside, devOutsideAssist, devInside; | |
617 bool isDegenerate; | |
618 compute_rects(&devOutside, &devOutsideAssist, &devInside, &isDegenerate, vie
wMatrix, | |
619 rect, stroke.getWidth(), isMiterStroke); | |
620 | |
621 batch->append(color, devOutside, devOutsideAssist, devInside, isDegenerate); | |
622 batch->init(); | |
623 return batch; | |
624 } | 594 } |
625 | 595 |
626 }; | 596 } |
627 | 597 |
628 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 598 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
629 | 599 |
630 #ifdef GR_TEST_UTILS | 600 #ifdef GR_TEST_UTILS |
631 | 601 |
632 #include "GrBatchTest.h" | 602 #include "GrBatchTest.h" |
633 | 603 |
634 DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) { | 604 DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) { |
635 bool miterStroke = random->nextBool(); | 605 bool miterStroke = random->nextBool(); |
636 | 606 |
637 // Create either a empty rect or a non-empty rect. | 607 // Create either a empty rect or a non-empty rect. |
638 SkRect rect = random->nextBool() ? SkRect::MakeXYWH(10, 10, 50, 40) : | 608 SkRect rect = random->nextBool() ? SkRect::MakeXYWH(10, 10, 50, 40) : |
639 SkRect::MakeXYWH(6, 7, 0, 0); | 609 SkRect::MakeXYWH(6, 7, 0, 0); |
640 SkScalar minDim = SkMinScalar(rect.width(), rect.height()); | 610 SkScalar minDim = SkMinScalar(rect.width(), rect.height()); |
641 SkScalar strokeWidth = random->nextUScalar1() * minDim; | 611 SkScalar strokeWidth = random->nextUScalar1() * minDim; |
642 | 612 |
643 GrColor color = GrRandomColor(random); | 613 GrColor color = GrRandomColor(random); |
644 | 614 |
645 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); | 615 SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); |
646 rec.setStrokeStyle(strokeWidth); | 616 rec.setStrokeStyle(strokeWidth); |
647 rec.setStrokeParams(SkPaint::kButt_Cap, | 617 rec.setStrokeParams(SkPaint::kButt_Cap, |
648 miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Joi
n, | 618 miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Joi
n, |
649 1.f); | 619 1.f); |
650 SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random); | 620 SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random); |
651 return GrAAStrokeRectBatch::Create(color, matrix, rect, rec); | 621 return GrAAStrokeRectBatch::Create(color, matrix, rect, rec); |
652 } | 622 } |
653 | 623 |
654 #endif | 624 #endif |
OLD | NEW |