p3.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /*
  2. * Copyright 2018 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/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkColorSpace.h"
  12. #include "include/core/SkFilterQuality.h"
  13. #include "include/core/SkFont.h"
  14. #include "include/core/SkImageInfo.h"
  15. #include "include/core/SkMatrix.h"
  16. #include "include/core/SkPaint.h"
  17. #include "include/core/SkPathEffect.h"
  18. #include "include/core/SkPixmap.h"
  19. #include "include/core/SkPoint.h"
  20. #include "include/core/SkRefCnt.h"
  21. #include "include/core/SkScalar.h"
  22. #include "include/core/SkShader.h"
  23. #include "include/core/SkString.h"
  24. #include "include/core/SkTileMode.h"
  25. #include "include/core/SkTypes.h"
  26. #include "include/effects/SkDashPathEffect.h"
  27. #include "include/effects/SkGradientShader.h"
  28. #include "src/core/SkColorSpaceXformSteps.h"
  29. #include <math.h>
  30. #include <string.h>
  31. static bool nearly_equal(SkColor4f x, SkColor4f y) {
  32. const float K = 0.01f;
  33. return fabsf(x.fR - y.fR) < K
  34. && fabsf(x.fG - y.fG) < K
  35. && fabsf(x.fB - y.fB) < K
  36. && fabsf(x.fA - y.fA) < K;
  37. }
  38. static SkString fmt(SkColor4f c) {
  39. return SkStringPrintf("%.2g %.2g %.2g %.2g", c.fR, c.fG, c.fB, c.fA);
  40. }
  41. static SkColor4f transform(SkColor4f c, SkColorSpace* src, SkColorSpace* dst) {
  42. SkColorSpaceXformSteps(src, kUnpremul_SkAlphaType,
  43. dst, kUnpremul_SkAlphaType).apply(c.vec());
  44. return c;
  45. }
  46. static void compare_pixel(const char* label,
  47. SkCanvas* canvas, int x, int y,
  48. SkColor4f color, SkColorSpace* cs) {
  49. SkPaint paint;
  50. SkFont font;
  51. auto canvas_cs = canvas->imageInfo().refColorSpace();
  52. // I'm not really sure if this makes things easier or harder to follow,
  53. // but we sniff the canvas to grab its current y-translate, so that (x,y)
  54. // can be written in sort of chunk-relative terms.
  55. const SkMatrix& m = canvas->getTotalMatrix();
  56. SkASSERT(m.isTranslate());
  57. SkScalar dy = m.getTranslateY();
  58. SkASSERT(dy == (int)dy);
  59. y += (int)dy;
  60. SkBitmap bm;
  61. bm.allocPixels(SkImageInfo::Make(1,1, kRGBA_F32_SkColorType, kUnpremul_SkAlphaType, canvas_cs));
  62. if (!canvas->readPixels(bm, x,y)) {
  63. MarkGMGood(canvas, 140,40);
  64. canvas->drawString("can't readPixels() on this canvas :(", 100,20, font, paint);
  65. return;
  66. }
  67. SkColor4f pixel;
  68. memcpy(&pixel, bm.getAddr(0,0), sizeof(pixel));
  69. SkColor4f expected = transform(color,cs, canvas_cs.get());
  70. if (canvas->imageInfo().colorType() < kRGBA_F16_SkColorType) {
  71. // We can't expect normalized formats to hold values outside [0,1].
  72. for (int i = 0; i < 4; ++i) {
  73. expected[i] = SkTPin(expected[i], 0.0f, 1.0f);
  74. }
  75. }
  76. if (canvas->imageInfo().colorType() == kGray_8_SkColorType) {
  77. // Drawing into Gray8 is known to be maybe-totally broken.
  78. // TODO: update expectation here to be {lum,lum,lum,1} if we fix Gray8.
  79. expected = SkColor4f{NAN, NAN, NAN, 1};
  80. }
  81. if (nearly_equal(pixel, expected)) {
  82. MarkGMGood(canvas, 140,40);
  83. } else {
  84. MarkGMBad(canvas, 140,40);
  85. }
  86. struct {
  87. const char* label;
  88. SkColor4f color;
  89. } lines[] = {
  90. {"Pixel:" , pixel },
  91. {"Expected:", expected},
  92. };
  93. SkAutoCanvasRestore saveRestore(canvas, true);
  94. canvas->drawString(label, 80,20, font, paint);
  95. for (auto l : lines) {
  96. canvas->translate(0,20);
  97. canvas->drawString(l.label, 80,20, font, paint);
  98. canvas->drawString(fmt(l.color).c_str(), 140,20, font, paint);
  99. }
  100. }
  101. DEF_SIMPLE_GM(p3, canvas, 450, 1300) {
  102. auto p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
  103. auto srgb = SkColorSpace::MakeSRGB();
  104. auto p3_to_srgb = [&](SkColor4f c) {
  105. SkPaint p;
  106. p.setColor4f(c, p3.get());
  107. return p.getColor4f();
  108. };
  109. // Draw a P3 red rectangle and check the corner.
  110. {
  111. SkPaint paint;
  112. paint.setColor4f({1,0,0,1}, p3.get());
  113. canvas->drawRect({10,10,70,70}, paint);
  114. compare_pixel("drawRect P3 red ",
  115. canvas, 10,10,
  116. {1,0,0,1}, p3.get());
  117. }
  118. canvas->translate(0,80);
  119. // Draw a P3 red bitmap, using a draw.
  120. {
  121. SkBitmap bm;
  122. bm.allocPixels(SkImageInfo::Make(60,60, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3));
  123. SkPaint paint;
  124. paint.setColor4f({1,0,0,1}, p3.get());
  125. SkCanvas{bm}.drawPaint(paint);
  126. canvas->drawBitmap(bm, 10,10);
  127. compare_pixel("drawBitmap P3 red, from drawPaint",
  128. canvas, 10,10,
  129. {1,0,0,1}, p3.get());
  130. }
  131. canvas->translate(0,80);
  132. // Draw a P3 red bitmap, using SkBitmap::eraseColor().
  133. {
  134. SkBitmap bm;
  135. bm.allocPixels(SkImageInfo::Make(60,60, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3));
  136. bm.eraseColor(0xffff0000/*in P3*/);
  137. canvas->drawBitmap(bm, 10,10);
  138. compare_pixel("drawBitmap P3 red, from SkBitmap::eraseColor()",
  139. canvas, 10,10,
  140. {1,0,0,1}, p3.get());
  141. }
  142. canvas->translate(0,80);
  143. // Draw a P3 red bitmap, using SkPixmap::erase().
  144. {
  145. SkBitmap bm;
  146. bm.allocPixels(SkImageInfo::Make(60,60, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3));
  147. // At the moment only SkPixmap has an erase() that takes an SkColor4f.
  148. SkPixmap pm;
  149. SkAssertResult(bm.peekPixels(&pm));
  150. SkAssertResult(pm.erase({1,0,0,1} /*in p3*/));
  151. canvas->drawBitmap(bm, 10,10);
  152. compare_pixel("drawBitmap P3 red, from SkPixmap::erase",
  153. canvas, 10,10,
  154. {1,0,0,1}, p3.get());
  155. }
  156. canvas->translate(0,80);
  157. // Draw a P3 red bitmap wrapped in a shader, using SkPixmap::erase().
  158. {
  159. SkBitmap bm;
  160. bm.allocPixels(SkImageInfo::Make(60,60, kRGBA_F16_SkColorType, kPremul_SkAlphaType, p3));
  161. // At the moment only SkPixmap has an erase() that takes an SkColor4f.
  162. SkPixmap pm;
  163. SkAssertResult(bm.peekPixels(&pm));
  164. SkAssertResult(pm.erase({1,0,0,1} /*in p3*/));
  165. SkPaint paint;
  166. paint.setShader(bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat));
  167. canvas->drawRect({10,10,70,70}, paint);
  168. compare_pixel("drawBitmapAsShader P3 red, from SkPixmap::erase",
  169. canvas, 10,10,
  170. {1,0,0,1}, p3.get());
  171. }
  172. canvas->translate(0,80);
  173. // TODO(mtklein): sample and check the middle points of these gradients too.
  174. // Draw a gradient from P3 red to P3 green interpolating in unpremul P3, checking the corners.
  175. {
  176. SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
  177. SkColor4f colors[] = {{1,0,0,1}, {0,1,0,1}};
  178. SkPaint paint;
  179. paint.setShader(SkGradientShader::MakeLinear(points, colors, p3,
  180. nullptr, SK_ARRAY_COUNT(colors),
  181. SkTileMode::kClamp));
  182. canvas->drawRect({10,10,70,70}, paint);
  183. canvas->save();
  184. compare_pixel("UPM P3 gradient, P3 red",
  185. canvas, 10,10,
  186. {1,0,0,1}, p3.get());
  187. canvas->translate(180, 0);
  188. compare_pixel("UPM P3 gradient, P3 green",
  189. canvas, 69,69,
  190. {0,1,0,1}, p3.get());
  191. canvas->restore();
  192. }
  193. canvas->translate(0,80);
  194. // Draw a gradient from P3 red to P3 green interpolating in premul P3, checking the corners.
  195. {
  196. SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
  197. SkColor4f colors[] = {{1,0,0,1}, {0,1,0,1}};
  198. SkPaint paint;
  199. paint.setShader(
  200. SkGradientShader::MakeLinear(points, colors, p3,
  201. nullptr, SK_ARRAY_COUNT(colors),
  202. SkTileMode::kClamp,
  203. SkGradientShader::kInterpolateColorsInPremul_Flag,
  204. nullptr/*local matrix*/));
  205. canvas->drawRect({10,10,70,70}, paint);
  206. canvas->save();
  207. compare_pixel("PM P3 gradient, P3 red",
  208. canvas, 10,10,
  209. {1,0,0,1}, p3.get());
  210. canvas->translate(180, 0);
  211. compare_pixel("PM P3 gradient, P3 green",
  212. canvas, 69,69,
  213. {0,1,0,1}, p3.get());
  214. canvas->restore();
  215. }
  216. canvas->translate(0,80);
  217. // Draw a gradient from P3 red to P3 green interpolating in unpremul sRGB, checking the corners.
  218. {
  219. SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
  220. SkColor4f colors[] = {p3_to_srgb({1,0,0,1}), p3_to_srgb({0,1,0,1})};
  221. SkPaint paint;
  222. paint.setShader(SkGradientShader::MakeLinear(points, colors, srgb,
  223. nullptr, SK_ARRAY_COUNT(colors),
  224. SkTileMode::kClamp));
  225. canvas->drawRect({10,10,70,70}, paint);
  226. canvas->save();
  227. compare_pixel("UPM sRGB gradient, P3 red",
  228. canvas, 10,10,
  229. {1,0,0,1}, p3.get());
  230. canvas->translate(180, 0);
  231. compare_pixel("UPM sRGB gradient, P3 green",
  232. canvas, 69,69,
  233. {0,1,0,1}, p3.get());
  234. canvas->restore();
  235. }
  236. canvas->translate(0,80);
  237. // Draw a gradient from P3 red to P3 green interpolating in premul sRGB, checking the corners.
  238. {
  239. SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
  240. SkColor4f colors[] = {p3_to_srgb({1,0,0,1}), p3_to_srgb({0,1,0,1})};
  241. SkPaint paint;
  242. paint.setShader(
  243. SkGradientShader::MakeLinear(points, colors, srgb,
  244. nullptr, SK_ARRAY_COUNT(colors),
  245. SkTileMode::kClamp,
  246. SkGradientShader::kInterpolateColorsInPremul_Flag,
  247. nullptr/*local matrix*/));
  248. canvas->drawRect({10,10,70,70}, paint);
  249. canvas->save();
  250. compare_pixel("PM sRGB gradient, P3 red",
  251. canvas, 10,10,
  252. {1,0,0,1}, p3.get());
  253. canvas->translate(180, 0);
  254. compare_pixel("PM sRGB gradient, P3 green",
  255. canvas, 69,69,
  256. {0,1,0,1}, p3.get());
  257. canvas->restore();
  258. }
  259. canvas->translate(0,80);
  260. // Leon's blue -> green -> red gradient, interpolating in premul.
  261. {
  262. SkPoint points[] = {{10.5,10.5}, {10.5,69.5}};
  263. SkColor4f colors[] = { {0,0,1,1}, {0,1,0,1}, {1,0,0,1} };
  264. SkPaint paint;
  265. paint.setShader(
  266. SkGradientShader::MakeLinear(points, colors, p3,
  267. nullptr, SK_ARRAY_COUNT(colors),
  268. SkTileMode::kClamp,
  269. SkGradientShader::kInterpolateColorsInPremul_Flag,
  270. nullptr/*local matrix*/));
  271. canvas->drawRect({10,10,70,70}, paint);
  272. canvas->save();
  273. compare_pixel("Leon's gradient, P3 blue",
  274. canvas, 10,10,
  275. {0,0,1,1}, p3.get());
  276. canvas->translate(180, 0);
  277. compare_pixel("Leon's gradient, P3 red",
  278. canvas, 10,69,
  279. {1,0,0,1}, p3.get());
  280. canvas->restore();
  281. }
  282. canvas->translate(0,80);
  283. // Draw an A8 image with a P3 red, scaled and not, as a shader or bitmap.
  284. {
  285. uint8_t mask[256];
  286. for (int i = 0; i < 256; i++) {
  287. mask[i] = 255-i;
  288. }
  289. SkBitmap bm;
  290. bm.installPixels(SkImageInfo::MakeA8(16,16), mask, 16);
  291. SkPaint as_bitmap;
  292. as_bitmap.setColor4f({1,0,0,1}, p3.get());
  293. as_bitmap.setFilterQuality(kLow_SkFilterQuality);
  294. SkPaint as_shader;
  295. as_shader.setColor4f({1,0,0,1}, p3.get());
  296. as_shader.setFilterQuality(kLow_SkFilterQuality);
  297. as_shader.setShader(bm.makeShader());
  298. canvas->drawBitmap(bm, 10,10, &as_bitmap);
  299. compare_pixel("A8 sprite bitmap P3 red",
  300. canvas, 10,10,
  301. {1,0,0,1}, p3.get());
  302. canvas->translate(0, 80);
  303. canvas->save();
  304. canvas->translate(10,10);
  305. canvas->drawRect({0,0,16,16}, as_shader);
  306. canvas->restore();
  307. compare_pixel("A8 sprite shader P3 red",
  308. canvas, 10,10,
  309. {1,0,0,1}, p3.get());
  310. canvas->translate(0,80);
  311. canvas->drawBitmapRect(bm, {10,10,70,70}, &as_bitmap);
  312. compare_pixel("A8 scaled bitmap P3 red",
  313. canvas, 10,10,
  314. {1,0,0,1}, p3.get());
  315. canvas->translate(0,80);
  316. canvas->save();
  317. canvas->translate(10,10);
  318. canvas->scale(3.75,3.75);
  319. canvas->drawRect({0,0,16,16}, as_shader);
  320. canvas->restore();
  321. compare_pixel("A8 scaled shader P3 red",
  322. canvas, 10,10,
  323. {1,0,0,1}, p3.get());
  324. }
  325. // TODO: draw P3 colors more ways
  326. }
  327. DEF_SIMPLE_GM(p3_ovals, canvas, 450, 320) {
  328. auto p3 = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
  329. // Test cases that exercise each Op in GrOvalOpFactory.cpp
  330. // Draw a circle and check the center (CircleOp)
  331. {
  332. SkPaint paint;
  333. paint.setAntiAlias(true);
  334. paint.setColor4f({ 1,0,0,1 }, p3.get());
  335. canvas->drawCircle(40, 40, 30, paint);
  336. compare_pixel("drawCircle P3 red ",
  337. canvas, 40, 40,
  338. { 1,0,0,1 }, p3.get());
  339. }
  340. canvas->translate(0, 80);
  341. // Draw an oval and check the center (EllipseOp)
  342. {
  343. SkPaint paint;
  344. paint.setAntiAlias(true);
  345. paint.setColor4f({ 1,0,0,1 }, p3.get());
  346. canvas->drawOval({ 20,10,60,70 }, paint);
  347. compare_pixel("drawOval P3 red ",
  348. canvas, 40, 40,
  349. { 1,0,0,1 }, p3.get());
  350. }
  351. canvas->translate(0, 80);
  352. // Draw a butt-capped dashed circle and check the top of the stroke (ButtCappedDashedCircleOp)
  353. {
  354. SkPaint paint;
  355. paint.setAntiAlias(true);
  356. paint.setColor4f({ 1,0,0,1 }, p3.get());
  357. paint.setStyle(SkPaint::kStroke_Style);
  358. float intervals[] = { 70, 10 };
  359. paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
  360. paint.setStrokeWidth(10);
  361. canvas->drawCircle(40, 40, 30, paint);
  362. compare_pixel("drawDashedCircle P3 red ",
  363. canvas, 40, 10,
  364. { 1,0,0,1 }, p3.get());
  365. }
  366. canvas->translate(0, 80);
  367. // Draw an oval with rotation and check the center (DIEllipseOp)
  368. {
  369. SkPaint paint;
  370. paint.setAntiAlias(true);
  371. paint.setColor4f({ 1,0,0,1 }, p3.get());
  372. canvas->save();
  373. canvas->translate(40, 40);
  374. canvas->rotate(45);
  375. canvas->drawOval({ -20,-30,20,30 }, paint);
  376. canvas->restore();
  377. compare_pixel("drawRotatedOval P3 red ",
  378. canvas, 40, 40,
  379. { 1,0,0,1 }, p3.get());
  380. }
  381. canvas->translate(0, 80);
  382. }