cubicpaths.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  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. */
  7. #include "gm/gm.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkFont.h"
  11. #include "include/core/SkMatrix.h"
  12. #include "include/core/SkPaint.h"
  13. #include "include/core/SkPath.h"
  14. #include "include/core/SkPoint.h"
  15. #include "include/core/SkRect.h"
  16. #include "include/core/SkScalar.h"
  17. #include "include/core/SkSize.h"
  18. #include "include/core/SkString.h"
  19. #include "include/core/SkTypeface.h"
  20. #include "include/core/SkTypes.h"
  21. #include "include/utils/SkRandom.h"
  22. #include "tools/ToolUtils.h"
  23. // https://bug.skia.org/1316 shows that this cubic, when slightly clipped, creates big
  24. // (incorrect) changes to its control points.
  25. class ClippedCubicGM : public skiagm::GM {
  26. SkString onShortName() override { return SkString("clippedcubic"); }
  27. SkISize onISize() override { return {1240, 390}; }
  28. virtual void onDraw(SkCanvas* canvas) override {
  29. SkPath path;
  30. path.moveTo(0, 0);
  31. path.cubicTo(140, 150, 40, 10, 170, 150);
  32. SkPaint paint;
  33. SkRect bounds = path.getBounds();
  34. for (SkScalar dy = -1; dy <= 1; dy += 1) {
  35. canvas->save();
  36. for (SkScalar dx = -1; dx <= 1; dx += 1) {
  37. canvas->save();
  38. canvas->clipRect(bounds);
  39. canvas->translate(dx, dy);
  40. canvas->drawPath(path, paint);
  41. canvas->restore();
  42. canvas->translate(bounds.width(), 0);
  43. }
  44. canvas->restore();
  45. canvas->translate(0, bounds.height());
  46. }
  47. }
  48. };
  49. class ClippedCubic2GM : public skiagm::GM {
  50. SkString onShortName() override { return SkString("clippedcubic2"); }
  51. SkISize onISize() override { return {1240, 390}; }
  52. void onDraw(SkCanvas* canvas) override {
  53. canvas->save();
  54. canvas->translate(-2, 120);
  55. drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
  56. canvas->translate(0, 170);
  57. drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
  58. canvas->translate(0, 170);
  59. drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
  60. canvas->translate(0, 170);
  61. drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
  62. canvas->restore();
  63. canvas->save();
  64. canvas->translate(20, -2);
  65. drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 80));
  66. canvas->translate(170, 0);
  67. drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 100, 80));
  68. canvas->translate(170, 0);
  69. drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 30));
  70. canvas->translate(170, 0);
  71. drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 10));
  72. canvas->restore();
  73. }
  74. void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
  75. SkPaint framePaint, fillPaint;
  76. framePaint.setStyle(SkPaint::kStroke_Style);
  77. canvas->drawRect(clip, framePaint);
  78. canvas->drawPath(path, framePaint);
  79. canvas->save();
  80. canvas->clipRect(clip);
  81. canvas->drawPath(path, fillPaint);
  82. canvas->restore();
  83. }
  84. void onOnceBeforeDraw() override {
  85. fPath.moveTo(69.7030518991886f, 0);
  86. fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
  87. 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
  88. fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
  89. -0.013089005235602302f, 131);
  90. fPath.close();
  91. fFlipped = fPath;
  92. SkMatrix matrix;
  93. matrix.reset();
  94. matrix.setScaleX(0);
  95. matrix.setScaleY(0);
  96. matrix.setSkewX(1);
  97. matrix.setSkewY(1);
  98. fFlipped.transform(matrix);
  99. }
  100. SkPath fPath;
  101. SkPath fFlipped;
  102. private:
  103. typedef skiagm::GM INHERITED;
  104. };
  105. class CubicPathGM : public skiagm::GM {
  106. SkString onShortName() override { return SkString("cubicpath"); }
  107. SkISize onISize() override { return {1240, 390}; }
  108. void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
  109. const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
  110. SkPaint::Style style, SkPath::FillType fill,
  111. SkScalar strokeWidth) {
  112. path.setFillType(fill);
  113. SkPaint paint;
  114. paint.setStrokeCap(cap);
  115. paint.setStrokeWidth(strokeWidth);
  116. paint.setStrokeJoin(join);
  117. paint.setColor(color);
  118. paint.setStyle(style);
  119. canvas->save();
  120. canvas->clipRect(clip);
  121. canvas->drawPath(path, paint);
  122. canvas->restore();
  123. }
  124. void onDraw(SkCanvas* canvas) override {
  125. struct FillAndName {
  126. SkPath::FillType fFill;
  127. const char* fName;
  128. };
  129. constexpr FillAndName gFills[] = {
  130. {SkPath::kWinding_FillType, "Winding"},
  131. {SkPath::kEvenOdd_FillType, "Even / Odd"},
  132. {SkPath::kInverseWinding_FillType, "Inverse Winding"},
  133. {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
  134. };
  135. struct StyleAndName {
  136. SkPaint::Style fStyle;
  137. const char* fName;
  138. };
  139. constexpr StyleAndName gStyles[] = {
  140. {SkPaint::kFill_Style, "Fill"},
  141. {SkPaint::kStroke_Style, "Stroke"},
  142. {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
  143. };
  144. struct CapAndName {
  145. SkPaint::Cap fCap;
  146. SkPaint::Join fJoin;
  147. const char* fName;
  148. };
  149. constexpr CapAndName gCaps[] = {
  150. {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
  151. {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
  152. {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
  153. };
  154. struct PathAndName {
  155. SkPath fPath;
  156. const char* fName;
  157. };
  158. PathAndName path;
  159. path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
  160. path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
  161. 60*SK_Scalar1, 20*SK_Scalar1,
  162. 75*SK_Scalar1, 10*SK_Scalar1);
  163. path.fName = "moveTo-cubic";
  164. SkPaint titlePaint;
  165. titlePaint.setColor(SK_ColorBLACK);
  166. titlePaint.setAntiAlias(true);
  167. SkFont font(ToolUtils::create_portable_typeface(), 15);
  168. const char title[] = "Cubic Drawn Into Rectangle Clips With "
  169. "Indicated Style, Fill and Linecaps, with stroke width 10";
  170. canvas->drawString(title, 20, 20, font, titlePaint);
  171. SkRandom rand;
  172. SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
  173. canvas->save();
  174. canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
  175. canvas->save();
  176. for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
  177. if (0 < cap) {
  178. canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
  179. }
  180. canvas->save();
  181. for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
  182. if (0 < fill) {
  183. canvas->translate(0, rect.height() + 40 * SK_Scalar1);
  184. }
  185. canvas->save();
  186. for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
  187. if (0 < style) {
  188. canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
  189. }
  190. SkColor color = 0xff007000;
  191. this->drawPath(path.fPath, canvas, color, rect,
  192. gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
  193. gFills[fill].fFill, SK_Scalar1*10);
  194. SkPaint rectPaint;
  195. rectPaint.setColor(SK_ColorBLACK);
  196. rectPaint.setStyle(SkPaint::kStroke_Style);
  197. rectPaint.setStrokeWidth(-1);
  198. rectPaint.setAntiAlias(true);
  199. canvas->drawRect(rect, rectPaint);
  200. SkPaint labelPaint;
  201. labelPaint.setColor(color);
  202. font.setSize(10);
  203. canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint);
  204. canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint);
  205. canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint);
  206. }
  207. canvas->restore();
  208. }
  209. canvas->restore();
  210. }
  211. canvas->restore();
  212. canvas->restore();
  213. }
  214. };
  215. class CubicClosePathGM : public skiagm::GM {
  216. SkString onShortName() override { return SkString("cubicclosepath"); }
  217. SkISize onISize() override { return {1240, 390}; }
  218. void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
  219. const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
  220. SkPaint::Style style, SkPath::FillType fill,
  221. SkScalar strokeWidth) {
  222. path.setFillType(fill);
  223. SkPaint paint;
  224. paint.setStrokeCap(cap);
  225. paint.setStrokeWidth(strokeWidth);
  226. paint.setStrokeJoin(join);
  227. paint.setColor(color);
  228. paint.setStyle(style);
  229. canvas->save();
  230. canvas->clipRect(clip);
  231. canvas->drawPath(path, paint);
  232. canvas->restore();
  233. }
  234. virtual void onDraw(SkCanvas* canvas) override {
  235. struct FillAndName {
  236. SkPath::FillType fFill;
  237. const char* fName;
  238. };
  239. constexpr FillAndName gFills[] = {
  240. {SkPath::kWinding_FillType, "Winding"},
  241. {SkPath::kEvenOdd_FillType, "Even / Odd"},
  242. {SkPath::kInverseWinding_FillType, "Inverse Winding"},
  243. {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
  244. };
  245. struct StyleAndName {
  246. SkPaint::Style fStyle;
  247. const char* fName;
  248. };
  249. constexpr StyleAndName gStyles[] = {
  250. {SkPaint::kFill_Style, "Fill"},
  251. {SkPaint::kStroke_Style, "Stroke"},
  252. {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
  253. };
  254. struct CapAndName {
  255. SkPaint::Cap fCap;
  256. SkPaint::Join fJoin;
  257. const char* fName;
  258. };
  259. constexpr CapAndName gCaps[] = {
  260. {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
  261. {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
  262. {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
  263. };
  264. struct PathAndName {
  265. SkPath fPath;
  266. const char* fName;
  267. };
  268. PathAndName path;
  269. path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
  270. path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
  271. 60*SK_Scalar1, 20*SK_Scalar1,
  272. 75*SK_Scalar1, 10*SK_Scalar1);
  273. path.fPath.close();
  274. path.fName = "moveTo-cubic-close";
  275. SkPaint titlePaint;
  276. titlePaint.setColor(SK_ColorBLACK);
  277. titlePaint.setAntiAlias(true);
  278. SkFont font(ToolUtils::create_portable_typeface(), 15);
  279. const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
  280. "Indicated Style, Fill and Linecaps, with stroke width 10";
  281. canvas->drawString(title, 20, 20, font, titlePaint);
  282. SkRandom rand;
  283. SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
  284. canvas->save();
  285. canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
  286. canvas->save();
  287. for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
  288. if (0 < cap) {
  289. canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
  290. }
  291. canvas->save();
  292. for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
  293. if (0 < fill) {
  294. canvas->translate(0, rect.height() + 40 * SK_Scalar1);
  295. }
  296. canvas->save();
  297. for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
  298. if (0 < style) {
  299. canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
  300. }
  301. SkColor color = 0xff007000;
  302. this->drawPath(path.fPath, canvas, color, rect,
  303. gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
  304. gFills[fill].fFill, SK_Scalar1*10);
  305. SkPaint rectPaint;
  306. rectPaint.setColor(SK_ColorBLACK);
  307. rectPaint.setStyle(SkPaint::kStroke_Style);
  308. rectPaint.setStrokeWidth(-1);
  309. rectPaint.setAntiAlias(true);
  310. canvas->drawRect(rect, rectPaint);
  311. SkPaint labelPaint;
  312. labelPaint.setColor(color);
  313. labelPaint.setAntiAlias(true);
  314. font.setSize(10);
  315. canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint);
  316. canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint);
  317. canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint);
  318. }
  319. canvas->restore();
  320. }
  321. canvas->restore();
  322. }
  323. canvas->restore();
  324. canvas->restore();
  325. }
  326. };
  327. DEF_SIMPLE_GM(bug5099, canvas, 50, 50) {
  328. SkPaint p;
  329. p.setColor(SK_ColorRED);
  330. p.setAntiAlias(true);
  331. p.setStyle(SkPaint::kStroke_Style);
  332. p.setStrokeWidth(10);
  333. SkPath path;
  334. path.moveTo(6, 27);
  335. path.cubicTo(31.5f, 1.5f, 3.5f, 4.5f, 29, 29);
  336. canvas->drawPath(path, p);
  337. }
  338. DEF_SIMPLE_GM(bug6083, canvas, 100, 50) {
  339. SkPaint p;
  340. p.setColor(SK_ColorRED);
  341. p.setAntiAlias(true);
  342. p.setStyle(SkPaint::kStroke_Style);
  343. p.setStrokeWidth(15);
  344. canvas->translate(-500, -130);
  345. SkPath path;
  346. path.moveTo(500.988f, 155.200f);
  347. path.lineTo(526.109f, 155.200f);
  348. SkPoint p1 = { 526.109f, 155.200f };
  349. SkPoint p2 = { 525.968f, 212.968f };
  350. SkPoint p3 = { 526.109f, 241.840f };
  351. path.cubicTo(p1, p2, p3);
  352. canvas->drawPath(path, p);
  353. canvas->translate(50, 0);
  354. path.reset();
  355. p2.set(525.968f, 213.172f);
  356. path.moveTo(500.988f, 155.200f);
  357. path.lineTo(526.109f, 155.200f);
  358. path.cubicTo(p1, p2, p3);
  359. canvas->drawPath(path, p);
  360. }
  361. //////////////////////////////////////////////////////////////////////////////
  362. DEF_GM( return new CubicPathGM; )
  363. DEF_GM( return new CubicClosePathGM; )
  364. DEF_GM( return new ClippedCubicGM; )
  365. DEF_GM( return new ClippedCubic2GM; )