SampleHairline.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 "include/core/SkBitmap.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColorFilter.h"
  10. #include "include/core/SkColorPriv.h"
  11. #include "include/core/SkGraphics.h"
  12. #include "include/core/SkPath.h"
  13. #include "include/core/SkRegion.h"
  14. #include "include/core/SkShader.h"
  15. #include "include/core/SkStream.h"
  16. #include "include/core/SkTime.h"
  17. #include "include/core/SkTypeface.h"
  18. #include "include/effects/SkCornerPathEffect.h"
  19. #include "include/effects/SkGradientShader.h"
  20. #include "include/private/SkTo.h"
  21. #include "include/utils/SkRandom.h"
  22. #include "samplecode/Sample.h"
  23. #include "src/utils/SkUTF.h"
  24. static SkRandom gRand;
  25. static void generate_pts(SkPoint pts[], int count, int w, int h) {
  26. for (int i = 0; i < count; i++) {
  27. pts[i].set(gRand.nextUScalar1() * 3 * w - SkIntToScalar(w),
  28. gRand.nextUScalar1() * 3 * h - SkIntToScalar(h));
  29. }
  30. }
  31. static bool check_zeros(const SkPMColor pixels[], int count, int skip) {
  32. for (int i = 0; i < count; i++) {
  33. if (*pixels) {
  34. return false;
  35. }
  36. pixels += skip;
  37. }
  38. return true;
  39. }
  40. static bool check_bitmap_margin(const SkBitmap& bm, int margin) {
  41. size_t rb = bm.rowBytes();
  42. for (int i = 0; i < margin; i++) {
  43. if (!check_zeros(bm.getAddr32(0, i), bm.width(), 1)) {
  44. return false;
  45. }
  46. int bottom = bm.height() - i - 1;
  47. if (!check_zeros(bm.getAddr32(0, bottom), bm.width(), 1)) {
  48. return false;
  49. }
  50. // left column
  51. if (!check_zeros(bm.getAddr32(i, 0), bm.height(), SkToInt(rb >> 2))) {
  52. return false;
  53. }
  54. int right = bm.width() - margin + i;
  55. if (!check_zeros(bm.getAddr32(right, 0), bm.height(),
  56. SkToInt(rb >> 2))) {
  57. return false;
  58. }
  59. }
  60. return true;
  61. }
  62. #define WIDTH 620
  63. #define HEIGHT 460
  64. #define MARGIN 10
  65. static void line_proc(SkCanvas* canvas, const SkPaint& paint,
  66. const SkBitmap& bm) {
  67. const int N = 2;
  68. SkPoint pts[N];
  69. for (int i = 0; i < 400; i++) {
  70. generate_pts(pts, N, WIDTH, HEIGHT);
  71. canvas->drawLine(pts[0], pts[1], paint);
  72. if (!check_bitmap_margin(bm, MARGIN)) {
  73. SkDebugf("---- hairline failure (%g %g) (%g %g)\n",
  74. pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
  75. break;
  76. }
  77. }
  78. }
  79. static void poly_proc(SkCanvas* canvas, const SkPaint& paint,
  80. const SkBitmap& bm) {
  81. const int N = 8;
  82. SkPoint pts[N];
  83. for (int i = 0; i < 50; i++) {
  84. generate_pts(pts, N, WIDTH, HEIGHT);
  85. SkPath path;
  86. path.moveTo(pts[0]);
  87. for (int j = 1; j < N; j++) {
  88. path.lineTo(pts[j]);
  89. }
  90. canvas->drawPath(path, paint);
  91. }
  92. }
  93. static SkPoint ave(const SkPoint& a, const SkPoint& b) {
  94. SkPoint c = a + b;
  95. c.fX = SkScalarHalf(c.fX);
  96. c.fY = SkScalarHalf(c.fY);
  97. return c;
  98. }
  99. static void quad_proc(SkCanvas* canvas, const SkPaint& paint,
  100. const SkBitmap& bm) {
  101. const int N = 30;
  102. SkPoint pts[N];
  103. for (int i = 0; i < 10; i++) {
  104. generate_pts(pts, N, WIDTH, HEIGHT);
  105. SkPath path;
  106. path.moveTo(pts[0]);
  107. for (int j = 1; j < N - 2; j++) {
  108. path.quadTo(pts[j], ave(pts[j], pts[j+1]));
  109. }
  110. path.quadTo(pts[N - 2], pts[N - 1]);
  111. canvas->drawPath(path, paint);
  112. }
  113. }
  114. static void add_cubic(SkPath* path, const SkPoint& mid, const SkPoint& end) {
  115. SkPoint start;
  116. path->getLastPt(&start);
  117. path->cubicTo(ave(start, mid), ave(mid, end), end);
  118. }
  119. static void cube_proc(SkCanvas* canvas, const SkPaint& paint,
  120. const SkBitmap& bm) {
  121. const int N = 30;
  122. SkPoint pts[N];
  123. for (int i = 0; i < 10; i++) {
  124. generate_pts(pts, N, WIDTH, HEIGHT);
  125. SkPath path;
  126. path.moveTo(pts[0]);
  127. for (int j = 1; j < N - 2; j++) {
  128. add_cubic(&path, pts[j], ave(pts[j], pts[j+1]));
  129. }
  130. add_cubic(&path, pts[N - 2], pts[N - 1]);
  131. canvas->drawPath(path, paint);
  132. }
  133. }
  134. typedef void (*HairProc)(SkCanvas*, const SkPaint&, const SkBitmap&);
  135. static const struct {
  136. const char* fName;
  137. HairProc fProc;
  138. } gProcs[] = {
  139. { "line", line_proc },
  140. { "poly", poly_proc },
  141. { "quad", quad_proc },
  142. { "cube", cube_proc },
  143. };
  144. static int cycle_hairproc_index(int index) {
  145. return (index + 1) % SK_ARRAY_COUNT(gProcs);
  146. }
  147. class HairlineView : public Sample {
  148. SkMSec fNow;
  149. int fProcIndex;
  150. bool fDoAA;
  151. public:
  152. HairlineView() {
  153. fProcIndex = 0;
  154. fDoAA = true;
  155. fNow = 0;
  156. }
  157. protected:
  158. SkString name() override { return SkStringPrintf("Hair-%s", gProcs[fProcIndex].fName); }
  159. void show_bitmaps(SkCanvas* canvas, const SkBitmap& b0, const SkBitmap& b1,
  160. const SkIRect& inset) {
  161. canvas->drawBitmap(b0, 0, 0, nullptr);
  162. canvas->drawBitmap(b1, SkIntToScalar(b0.width()), 0, nullptr);
  163. }
  164. void onDrawContent(SkCanvas* canvas) override {
  165. gRand.setSeed(fNow);
  166. SkBitmap bm, bm2;
  167. bm.allocN32Pixels(WIDTH + MARGIN*2, HEIGHT + MARGIN*2);
  168. // this will erase our margin, which we want to always stay 0
  169. bm.eraseColor(SK_ColorTRANSPARENT);
  170. bm2.installPixels(SkImageInfo::MakeN32Premul(WIDTH, HEIGHT),
  171. bm.getAddr32(MARGIN, MARGIN), bm.rowBytes());
  172. SkCanvas c2(bm2);
  173. SkPaint paint;
  174. paint.setAntiAlias(fDoAA);
  175. paint.setStyle(SkPaint::kStroke_Style);
  176. bm2.eraseColor(SK_ColorTRANSPARENT);
  177. gProcs[fProcIndex].fProc(&c2, paint, bm);
  178. canvas->drawBitmap(bm2, SkIntToScalar(10), SkIntToScalar(10), nullptr);
  179. }
  180. bool onAnimate(double /*nanos*/) override {
  181. if (fDoAA) {
  182. fProcIndex = cycle_hairproc_index(fProcIndex);
  183. // todo: signal that we want to rebuild our TITLE
  184. }
  185. fDoAA = !fDoAA;
  186. return true;
  187. }
  188. Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, ModifierKey modi) override {
  189. fDoAA = !fDoAA;
  190. return this->INHERITED::onFindClickHandler(x, y, modi);
  191. }
  192. private:
  193. typedef Sample INHERITED;
  194. };
  195. //////////////////////////////////////////////////////////////////////////////
  196. DEF_SAMPLE( return new HairlineView(); )