QuickRejectTest.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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/SkDrawLooper.h"
  10. #include "include/core/SkPoint3.h"
  11. #include "include/core/SkTypes.h"
  12. #include "include/effects/SkLightingImageFilter.h"
  13. #include "src/core/SkArenaAlloc.h"
  14. #include "tests/Test.h"
  15. /*
  16. * Subclass of looper that just draws once, with an offset in X.
  17. */
  18. class TestLooper : public SkDrawLooper {
  19. public:
  20. SkDrawLooper::Context* makeContext(SkCanvas*, SkArenaAlloc* alloc) const override {
  21. return alloc->make<TestDrawLooperContext>();
  22. }
  23. private:
  24. SK_FLATTENABLE_HOOKS(TestLooper)
  25. class TestDrawLooperContext : public SkDrawLooper::Context {
  26. public:
  27. TestDrawLooperContext() : fOnce(true) {}
  28. ~TestDrawLooperContext() override {}
  29. bool next(SkCanvas* canvas, SkPaint*) override {
  30. if (fOnce) {
  31. fOnce = false;
  32. canvas->translate(SkIntToScalar(10), 0);
  33. return true;
  34. }
  35. return false;
  36. }
  37. private:
  38. bool fOnce;
  39. };
  40. };
  41. sk_sp<SkFlattenable> TestLooper::CreateProc(SkReadBuffer&) { return sk_make_sp<TestLooper>(); }
  42. static void test_drawBitmap(skiatest::Reporter* reporter) {
  43. SkBitmap src;
  44. src.allocN32Pixels(10, 10);
  45. src.eraseColor(SK_ColorWHITE);
  46. SkBitmap dst;
  47. dst.allocN32Pixels(10, 10);
  48. dst.eraseColor(SK_ColorTRANSPARENT);
  49. SkCanvas canvas(dst);
  50. SkPaint paint;
  51. // we are initially transparent
  52. REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
  53. // we see the bitmap drawn
  54. canvas.drawBitmap(src, 0, 0, &paint);
  55. REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
  56. // reverify we are clear again
  57. dst.eraseColor(SK_ColorTRANSPARENT);
  58. REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
  59. // if the bitmap is clipped out, we don't draw it
  60. canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
  61. REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
  62. #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
  63. // now install our looper, which will draw, since it internally translates
  64. // to the left. The test is to ensure that canvas' quickReject machinary
  65. // allows us through, even though sans-looper we would look like we should
  66. // be clipped out.
  67. paint.setLooper(sk_make_sp<TestLooper>());
  68. canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
  69. REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
  70. #endif
  71. }
  72. static void test_layers(skiatest::Reporter* reporter) {
  73. SkCanvas canvas(100, 100);
  74. SkRect r = SkRect::MakeWH(10, 10);
  75. REPORTER_ASSERT(reporter, false == canvas.quickReject(r));
  76. r.offset(300, 300);
  77. REPORTER_ASSERT(reporter, true == canvas.quickReject(r));
  78. // Test that saveLayer updates quickReject
  79. SkRect bounds = SkRect::MakeLTRB(50, 50, 70, 70);
  80. canvas.saveLayer(&bounds, nullptr);
  81. REPORTER_ASSERT(reporter, true == canvas.quickReject(SkRect::MakeWH(10, 10)));
  82. REPORTER_ASSERT(reporter, false == canvas.quickReject(SkRect::MakeWH(60, 60)));
  83. }
  84. static void test_quick_reject(skiatest::Reporter* reporter) {
  85. SkCanvas canvas(100, 100);
  86. SkRect r0 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
  87. SkRect r1 = SkRect::MakeLTRB(-50.0f, 110.0f, 50.0f, 120.0f);
  88. SkRect r2 = SkRect::MakeLTRB(110.0f, -50.0f, 120.0f, 50.0f);
  89. SkRect r3 = SkRect::MakeLTRB(-120.0f, -50.0f, 120.0f, 50.0f);
  90. SkRect r4 = SkRect::MakeLTRB(-50.0f, -120.0f, 50.0f, 120.0f);
  91. SkRect r5 = SkRect::MakeLTRB(-120.0f, -120.0f, 120.0f, 120.0f);
  92. SkRect r6 = SkRect::MakeLTRB(-120.0f, -120.0f, -110.0f, -110.0f);
  93. SkRect r7 = SkRect::MakeLTRB(SK_ScalarNaN, -50.0f, 50.0f, 50.0f);
  94. SkRect r8 = SkRect::MakeLTRB(-50.0f, SK_ScalarNaN, 50.0f, 50.0f);
  95. SkRect r9 = SkRect::MakeLTRB(-50.0f, -50.0f, SK_ScalarNaN, 50.0f);
  96. SkRect r10 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, SK_ScalarNaN);
  97. REPORTER_ASSERT(reporter, false == canvas.quickReject(r0));
  98. REPORTER_ASSERT(reporter, true == canvas.quickReject(r1));
  99. REPORTER_ASSERT(reporter, true == canvas.quickReject(r2));
  100. REPORTER_ASSERT(reporter, false == canvas.quickReject(r3));
  101. REPORTER_ASSERT(reporter, false == canvas.quickReject(r4));
  102. REPORTER_ASSERT(reporter, false == canvas.quickReject(r5));
  103. REPORTER_ASSERT(reporter, true == canvas.quickReject(r6));
  104. REPORTER_ASSERT(reporter, true == canvas.quickReject(r7));
  105. REPORTER_ASSERT(reporter, true == canvas.quickReject(r8));
  106. REPORTER_ASSERT(reporter, true == canvas.quickReject(r9));
  107. REPORTER_ASSERT(reporter, true == canvas.quickReject(r10));
  108. SkMatrix m = SkMatrix::MakeScale(2.0f);
  109. m.setTranslateX(10.0f);
  110. m.setTranslateY(10.0f);
  111. canvas.setMatrix(m);
  112. SkRect r11 = SkRect::MakeLTRB(5.0f, 5.0f, 100.0f, 100.0f);
  113. SkRect r12 = SkRect::MakeLTRB(5.0f, 50.0f, 100.0f, 100.0f);
  114. SkRect r13 = SkRect::MakeLTRB(50.0f, 5.0f, 100.0f, 100.0f);
  115. REPORTER_ASSERT(reporter, false == canvas.quickReject(r11));
  116. REPORTER_ASSERT(reporter, true == canvas.quickReject(r12));
  117. REPORTER_ASSERT(reporter, true == canvas.quickReject(r13));
  118. }
  119. DEF_TEST(QuickReject, reporter) {
  120. test_drawBitmap(reporter);
  121. test_layers(reporter);
  122. test_quick_reject(reporter);
  123. }
  124. // Regression test to make sure that we keep fIsScaleTranslate up to date on the canvas.
  125. // It is possible to set a new matrix on the canvas without calling setMatrix(). This tests
  126. // that code path.
  127. DEF_TEST(QuickReject_MatrixState, reporter) {
  128. SkCanvas canvas(100, 100);
  129. SkMatrix matrix;
  130. matrix.setRotate(45.0f);
  131. canvas.setMatrix(matrix);
  132. SkPaint paint;
  133. sk_sp<SkImageFilter> filter = SkLightingImageFilter::MakeDistantLitDiffuse(
  134. SkPoint3::Make(1.0f, 1.0f, 1.0f), 0xFF0000FF, 2.0f, 0.5f, nullptr);
  135. REPORTER_ASSERT(reporter, filter);
  136. paint.setImageFilter(filter);
  137. SkCanvas::SaveLayerRec rec;
  138. rec.fPaint = &paint;
  139. canvas.saveLayer(rec);
  140. // quickReject() will assert if the matrix is out of sync.
  141. canvas.quickReject(SkRect::MakeWH(100.0f, 100.0f));
  142. }
  143. #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
  144. #include "include/core/SkSurface.h"
  145. #include "include/effects/SkLayerDrawLooper.h"
  146. DEF_TEST(looper_nothingtodraw, reporter) {
  147. auto surf = SkSurface::MakeRasterN32Premul(20, 20);
  148. SkPaint paint;
  149. paint.setColor(0);
  150. REPORTER_ASSERT(reporter, paint.nothingToDraw());
  151. SkLayerDrawLooper::Builder builder;
  152. builder.addLayer();
  153. paint.setDrawLooper(builder.detach());
  154. // the presence of the looper fools this predicate, so we think it might draw
  155. REPORTER_ASSERT(reporter, !paint.nothingToDraw());
  156. // Before fixing, this would assert in ~AutoDrawLooper() in SkCanvas.cpp as it checked for
  157. // a balance in the save/restore count after handling the looper. Before the fix, this
  158. // code would call nothingToDraw() and since it now clears the looper, that predicate will
  159. // return true, aborting the sequence prematurely, and not finishing the iterator on the looper
  160. // which handles the final "restore". This was a bug -- we *must* call the looper's iterator
  161. // until it returns done to keep the canvas balanced. The fix was to remove this early-exit
  162. // in the autodrawlooper. Now this call won't assert.
  163. // See https://skia-review.googlesource.com/c/skia/+/121220
  164. surf->getCanvas()->drawRect({1, 1, 10, 10}, paint);
  165. }
  166. #endif