blob: 14f8ae601678ca30ed3d87625a0aa7d025ce704d [file] [log] [blame]
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
bungemand3ebb482015-08-05 13:57:49 -07007
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00008#include "gm.h"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000010#include "SkCanvas.h"
11#include "SkPaint.h"
bungemand3ebb482015-08-05 13:57:49 -070012#include "SkPath.h"
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000013#include "SkRandom.h"
14
halcanary6950de62015-11-07 05:29:00 -080015// https://bug.skia.org/1316 shows that this cubic, when slightly clipped, creates big
reed@google.com22999c62013-05-23 19:30:48 +000016// (incorrect) changes to its control points.
17class ClippedCubicGM : public skiagm::GM {
18public:
19 ClippedCubicGM() {}
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000020
reed@google.com22999c62013-05-23 19:30:48 +000021protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000022
reed@google.com22999c62013-05-23 19:30:48 +000023 SkString onShortName() {
reed@google.com03ca64b2013-05-23 19:39:15 +000024 return SkString("clippedcubic");
reed@google.com22999c62013-05-23 19:30:48 +000025 }
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000026
reed@google.com22999c62013-05-23 19:30:48 +000027 SkISize onISize() { return SkISize::Make(1240, 390); }
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000028
reed@google.com22999c62013-05-23 19:30:48 +000029 virtual void onDraw(SkCanvas* canvas) {
30 SkPath path;
31 path.moveTo(0, 0);
32 path.cubicTo(140, 150, 40, 10, 170, 150);
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000033
reed@google.com22999c62013-05-23 19:30:48 +000034 SkPaint paint;
35 SkRect bounds = path.getBounds();
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000036
reed@google.com0f8990c2013-05-23 19:47:05 +000037 for (SkScalar dy = -1; dy <= 1; dy += 1) {
reed@google.com22999c62013-05-23 19:30:48 +000038 canvas->save();
reed@google.com0f8990c2013-05-23 19:47:05 +000039 for (SkScalar dx = -1; dx <= 1; dx += 1) {
reed@google.com22999c62013-05-23 19:30:48 +000040 canvas->save();
41 canvas->clipRect(bounds);
42 canvas->translate(dx, dy);
43 canvas->drawPath(path, paint);
44 canvas->restore();
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000045
reed@google.com22999c62013-05-23 19:30:48 +000046 canvas->translate(bounds.width(), 0);
47 }
48 canvas->restore();
49 canvas->translate(0, bounds.height());
50 }
51 }
skia.committer@gmail.com3e2345a2013-05-24 07:01:26 +000052
reed@google.com22999c62013-05-23 19:30:48 +000053private:
54 typedef skiagm::GM INHERITED;
55};
56
caryclark7d173402015-08-20 08:23:52 -070057
58class ClippedCubic2GM : public skiagm::GM {
59public:
60 ClippedCubic2GM() {}
61
62protected:
63
caryclark02833bf2015-08-20 10:53:13 -070064 SkString onShortName() override {
caryclark7d173402015-08-20 08:23:52 -070065 return SkString("clippedcubic2");
66 }
67
caryclark02833bf2015-08-20 10:53:13 -070068 SkISize onISize() override { return SkISize::Make(1240, 390); }
caryclark7d173402015-08-20 08:23:52 -070069
70 void onDraw(SkCanvas* canvas) override {
71 canvas->save();
caryclark05424f72015-08-20 10:35:43 -070072 canvas->translate(-2, 120);
caryclark7d173402015-08-20 08:23:52 -070073 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
74 canvas->translate(0, 170);
75 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
76 canvas->translate(0, 170);
77 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
78 canvas->translate(0, 170);
79 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
80 canvas->restore();
caryclark05424f72015-08-20 10:35:43 -070081 canvas->save();
82 canvas->translate(20, -2);
83 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 80));
84 canvas->translate(170, 0);
85 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 100, 80));
86 canvas->translate(170, 0);
87 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 30));
88 canvas->translate(170, 0);
89 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 10));
90 canvas->restore();
caryclark7d173402015-08-20 08:23:52 -070091 }
92
93 void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
94 SkPaint framePaint, fillPaint;
95 framePaint.setStyle(SkPaint::kStroke_Style);
96 canvas->drawRect(clip, framePaint);
97 canvas->drawPath(path, framePaint);
98 canvas->save();
99 canvas->clipRect(clip);
100 canvas->drawPath(path, fillPaint);
101 canvas->restore();
102 }
103
104 void onOnceBeforeDraw() override {
105 fPath.moveTo(69.7030518991886f, 0);
106 fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
107 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
108 fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
109 -0.013089005235602302f, 131);
110 fPath.close();
caryclark05424f72015-08-20 10:35:43 -0700111 fFlipped = fPath;
112 SkMatrix matrix;
113 matrix.reset();
114 matrix.setScaleX(0);
115 matrix.setScaleY(0);
116 matrix.setSkewX(1);
117 matrix.setSkewY(1);
118 fFlipped.transform(matrix);
caryclark7d173402015-08-20 08:23:52 -0700119 }
120
121 SkPath fPath;
caryclark05424f72015-08-20 10:35:43 -0700122 SkPath fFlipped;
caryclark7d173402015-08-20 08:23:52 -0700123private:
124 typedef skiagm::GM INHERITED;
125};
126
127
reed@google.com27b90fa2013-03-08 18:44:01 +0000128class CubicPathGM : public skiagm::GM {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000129public:
130 CubicPathGM() {}
131
132protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000133
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000134 SkString onShortName() {
135 return SkString("cubicpath");
136 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000137
reed@google.com27b90fa2013-03-08 18:44:01 +0000138 SkISize onISize() { return SkISize::Make(1240, 390); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000139
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000140 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
141 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
142 SkPaint::Style style, SkPath::FillType fill,
143 SkScalar strokeWidth) {
144 path.setFillType(fill);
145 SkPaint paint;
146 paint.setStrokeCap(cap);
147 paint.setStrokeWidth(strokeWidth);
148 paint.setStrokeJoin(join);
149 paint.setColor(color);
150 paint.setStyle(style);
151 canvas->save();
152 canvas->clipRect(clip);
153 canvas->drawPath(path, paint);
154 canvas->restore();
155 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000156
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000157 virtual void onDraw(SkCanvas* canvas) {
158 struct FillAndName {
159 SkPath::FillType fFill;
160 const char* fName;
161 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700162 constexpr FillAndName gFills[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000163 {SkPath::kWinding_FillType, "Winding"},
164 {SkPath::kEvenOdd_FillType, "Even / Odd"},
165 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
166 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
167 };
168 struct StyleAndName {
169 SkPaint::Style fStyle;
170 const char* fName;
171 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700172 constexpr StyleAndName gStyles[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000173 {SkPaint::kFill_Style, "Fill"},
174 {SkPaint::kStroke_Style, "Stroke"},
175 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
176 };
177 struct CapAndName {
178 SkPaint::Cap fCap;
179 SkPaint::Join fJoin;
180 const char* fName;
181 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700182 constexpr CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000183 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
184 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
185 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
186 };
187 struct PathAndName {
188 SkPath fPath;
189 const char* fName;
190 };
191 PathAndName path;
192 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
193 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
194 60*SK_Scalar1, 20*SK_Scalar1,
195 75*SK_Scalar1, 10*SK_Scalar1);
196 path.fName = "moveTo-cubic";
197
198 SkPaint titlePaint;
199 titlePaint.setColor(SK_ColorBLACK);
200 titlePaint.setAntiAlias(true);
Mike Reed1af9b482019-01-07 11:01:57 -0500201 SkFont font(sk_tool_utils::create_portable_typeface(), 15);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000202 const char title[] = "Cubic Drawn Into Rectangle Clips With "
203 "Indicated Style, Fill and Linecaps, with stroke width 10";
Mike Reed1af9b482019-01-07 11:01:57 -0500204 canvas->drawString(title, 20, 20, font, titlePaint);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000205
scroggof9d61012014-12-15 12:54:51 -0800206 SkRandom rand;
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000207 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
208 canvas->save();
209 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
210 canvas->save();
211 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
212 if (0 < cap) {
213 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
214 }
215 canvas->save();
216 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
217 if (0 < fill) {
218 canvas->translate(0, rect.height() + 40 * SK_Scalar1);
219 }
220 canvas->save();
221 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
222 if (0 < style) {
223 canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
224 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000225
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000226 SkColor color = 0xff007000;
227 this->drawPath(path.fPath, canvas, color, rect,
228 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
229 gFills[fill].fFill, SK_Scalar1*10);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000230
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000231 SkPaint rectPaint;
232 rectPaint.setColor(SK_ColorBLACK);
233 rectPaint.setStyle(SkPaint::kStroke_Style);
234 rectPaint.setStrokeWidth(-1);
235 rectPaint.setAntiAlias(true);
236 canvas->drawRect(rect, rectPaint);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000237
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000238 SkPaint labelPaint;
239 labelPaint.setColor(color);
Mike Reed1af9b482019-01-07 11:01:57 -0500240 font.setSize(10);
241 canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint);
242 canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint);
243 canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000244 }
245 canvas->restore();
246 }
247 canvas->restore();
248 }
249 canvas->restore();
250 canvas->restore();
251 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000252
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000253private:
reed@google.com27b90fa2013-03-08 18:44:01 +0000254 typedef skiagm::GM INHERITED;
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000255};
256
reed@google.com27b90fa2013-03-08 18:44:01 +0000257class CubicClosePathGM : public skiagm::GM {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000258public:
259 CubicClosePathGM() {}
260
261protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000262
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000263 SkString onShortName() {
264 return SkString("cubicclosepath");
265 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000266
reed@google.com27b90fa2013-03-08 18:44:01 +0000267 SkISize onISize() { return SkISize::Make(1240, 390); }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000268
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000269 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
270 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
271 SkPaint::Style style, SkPath::FillType fill,
272 SkScalar strokeWidth) {
273 path.setFillType(fill);
274 SkPaint paint;
275 paint.setStrokeCap(cap);
276 paint.setStrokeWidth(strokeWidth);
277 paint.setStrokeJoin(join);
278 paint.setColor(color);
279 paint.setStyle(style);
280 canvas->save();
281 canvas->clipRect(clip);
282 canvas->drawPath(path, paint);
283 canvas->restore();
284 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000285
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000286 virtual void onDraw(SkCanvas* canvas) {
287 struct FillAndName {
288 SkPath::FillType fFill;
289 const char* fName;
290 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700291 constexpr FillAndName gFills[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000292 {SkPath::kWinding_FillType, "Winding"},
293 {SkPath::kEvenOdd_FillType, "Even / Odd"},
294 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
295 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
296 };
297 struct StyleAndName {
298 SkPaint::Style fStyle;
299 const char* fName;
300 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700301 constexpr StyleAndName gStyles[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000302 {SkPaint::kFill_Style, "Fill"},
303 {SkPaint::kStroke_Style, "Stroke"},
304 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
305 };
306 struct CapAndName {
307 SkPaint::Cap fCap;
308 SkPaint::Join fJoin;
309 const char* fName;
310 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700311 constexpr CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000312 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
313 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
314 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
315 };
316 struct PathAndName {
317 SkPath fPath;
318 const char* fName;
319 };
320 PathAndName path;
321 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
322 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
323 60*SK_Scalar1, 20*SK_Scalar1,
324 75*SK_Scalar1, 10*SK_Scalar1);
325 path.fPath.close();
326 path.fName = "moveTo-cubic-close";
327
328 SkPaint titlePaint;
329 titlePaint.setColor(SK_ColorBLACK);
330 titlePaint.setAntiAlias(true);
Mike Reed1af9b482019-01-07 11:01:57 -0500331 SkFont font(sk_tool_utils::create_portable_typeface(), 15);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000332 const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
333 "Indicated Style, Fill and Linecaps, with stroke width 10";
Mike Reed1af9b482019-01-07 11:01:57 -0500334 canvas->drawString(title, 20, 20, font, titlePaint);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000335
scroggof9d61012014-12-15 12:54:51 -0800336 SkRandom rand;
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000337 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
338 canvas->save();
339 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
340 canvas->save();
341 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
342 if (0 < cap) {
343 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
344 }
345 canvas->save();
346 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
347 if (0 < fill) {
348 canvas->translate(0, rect.height() + 40 * SK_Scalar1);
349 }
350 canvas->save();
351 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
352 if (0 < style) {
353 canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
354 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000355
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000356 SkColor color = 0xff007000;
357 this->drawPath(path.fPath, canvas, color, rect,
358 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
359 gFills[fill].fFill, SK_Scalar1*10);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000360
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000361 SkPaint rectPaint;
362 rectPaint.setColor(SK_ColorBLACK);
363 rectPaint.setStyle(SkPaint::kStroke_Style);
364 rectPaint.setStrokeWidth(-1);
365 rectPaint.setAntiAlias(true);
366 canvas->drawRect(rect, rectPaint);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000367
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000368 SkPaint labelPaint;
369 labelPaint.setColor(color);
370 labelPaint.setAntiAlias(true);
Mike Reed1af9b482019-01-07 11:01:57 -0500371 font.setSize(10);
372 canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint);
373 canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint);
374 canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000375 }
376 canvas->restore();
377 }
378 canvas->restore();
379 }
380 canvas->restore();
381 canvas->restore();
382 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000383
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000384private:
reed@google.com27b90fa2013-03-08 18:44:01 +0000385 typedef skiagm::GM INHERITED;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000386};
387
caryclark4693a172016-04-06 08:54:06 -0700388DEF_SIMPLE_GM(bug5099, canvas, 50, 50) {
389 SkPaint p;
390 p.setColor(SK_ColorRED);
391 p.setAntiAlias(true);
392 p.setStyle(SkPaint::kStroke_Style);
393 p.setStrokeWidth(10);
394
395 SkPath path;
396 path.moveTo(6, 27);
397 path.cubicTo(31.5f, 1.5f, 3.5f, 4.5f, 29, 29);
398 canvas->drawPath(path, p);
399}
400
Cary Clarkd4631982017-01-05 12:08:38 -0500401DEF_SIMPLE_GM(bug6083, canvas, 100, 50) {
Ben Wagner29380bd2017-10-09 14:43:00 -0400402 SkPaint p;
403 p.setColor(SK_ColorRED);
404 p.setAntiAlias(true);
405 p.setStyle(SkPaint::kStroke_Style);
406 p.setStrokeWidth(15);
407 canvas->translate(-500, -130);
408 SkPath path;
409 path.moveTo(500.988f, 155.200f);
410 path.lineTo(526.109f, 155.200f);
411 SkPoint p1 = { 526.109f, 155.200f };
412 SkPoint p2 = { 525.968f, 212.968f };
413 SkPoint p3 = { 526.109f, 241.840f };
414 path.cubicTo(p1, p2, p3);
415 canvas->drawPath(path, p);
416 canvas->translate(50, 0);
417 path.reset();
418 p2.set(525.968f, 213.172f);
419 path.moveTo(500.988f, 155.200f);
420 path.lineTo(526.109f, 155.200f);
421 path.cubicTo(p1, p2, p3);
422 canvas->drawPath(path, p);
Cary Clarkd4631982017-01-05 12:08:38 -0500423}
424
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000425//////////////////////////////////////////////////////////////////////////////
426
reed@google.com27b90fa2013-03-08 18:44:01 +0000427DEF_GM( return new CubicPathGM; )
428DEF_GM( return new CubicClosePathGM; )
reed@google.com22999c62013-05-23 19:30:48 +0000429DEF_GM( return new ClippedCubicGM; )
caryclark7d173402015-08-20 08:23:52 -0700430DEF_GM( return new ClippedCubic2GM; )