13d60812865bb034851da777a91413ab584929887reed@google.com/*
23d60812865bb034851da777a91413ab584929887reed@google.com * Copyright 2011 Google Inc.
33d60812865bb034851da777a91413ab584929887reed@google.com *
43d60812865bb034851da777a91413ab584929887reed@google.com * Use of this source code is governed by a BSD-style license that can be
53d60812865bb034851da777a91413ab584929887reed@google.com * found in the LICENSE file.
63d60812865bb034851da777a91413ab584929887reed@google.com */
73d60812865bb034851da777a91413ab584929887reed@google.com
873fe7b07e6391da81dfc48d600d7b3141be1f471Herb Derby#include "SkArenaAlloc.h"
939e085559ddbd088866abdf50a48f7ab5b283830Florin Malita#include "SkBitmap.h"
103d60812865bb034851da777a91413ab584929887reed@google.com#include "SkCanvas.h"
11cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett#include "SkColorSpaceXformer.h"
123d60812865bb034851da777a91413ab584929887reed@google.com#include "SkDrawLooper.h"
139da5a5a198e5dc9148f7f30a6089377590eee55bmsarett#include "SkLightingImageFilter.h"
1479fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org#include "SkTypes.h"
158f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "Test.h"
163d60812865bb034851da777a91413ab584929887reed@google.com
173d60812865bb034851da777a91413ab584929887reed@google.com/*
183d60812865bb034851da777a91413ab584929887reed@google.com *  Subclass of looper that just draws once, with an offset in X.
193d60812865bb034851da777a91413ab584929887reed@google.com */
203d60812865bb034851da777a91413ab584929887reed@google.comclass TestLooper : public SkDrawLooper {
213d60812865bb034851da777a91413ab584929887reed@google.compublic:
223d60812865bb034851da777a91413ab584929887reed@google.com
2373fe7b07e6391da81dfc48d600d7b3141be1f471Herb Derby    SkDrawLooper::Context* makeContext(SkCanvas*, SkArenaAlloc* alloc) const override {
2473fe7b07e6391da81dfc48d600d7b3141be1f471Herb Derby        return alloc->make<TestDrawLooperContext>();
253d60812865bb034851da777a91413ab584929887reed@google.com    }
263d60812865bb034851da777a91413ab584929887reed@google.com
27cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett    sk_sp<SkDrawLooper> onMakeColorSpace(SkColorSpaceXformer*) const override {
28cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett        return nullptr;
29cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett    }
30cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett
310f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING
3236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void toString(SkString* str) const override {
334991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        str->append("TestLooper:");
344991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    }
354991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#endif
364991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
37fc6c37b981daeece7474ce61070c707c37eefa62Mike Klein    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(TestLooper)
387e44bb191633e225fd0455c267dbf67f9ee8633emtklein
3979fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.orgprivate:
4079fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org    class TestDrawLooperContext : public SkDrawLooper::Context {
4179fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org    public:
4279fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org        TestDrawLooperContext() : fOnce(true) {}
43d3b65972aad96453ff4510caa3e25a2b847c6d1eBrian Salomon        ~TestDrawLooperContext() override {}
4479fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org
4536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein        bool next(SkCanvas* canvas, SkPaint*) override {
4679fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org            if (fOnce) {
4779fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org                fOnce = false;
4879fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org                canvas->translate(SkIntToScalar(10), 0);
4979fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org                return true;
5079fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org            }
5179fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org            return false;
5279fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org        }
53cdc651d29d88e87ef84d5a586879db2c16ff4579Matt Sarett
5479fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org    private:
5579fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org        bool fOnce;
5679fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org    };
573d60812865bb034851da777a91413ab584929887reed@google.com};
583d60812865bb034851da777a91413ab584929887reed@google.com
5960c9b58b3214b0154c931656e91e39b230e987d8reedsk_sp<SkFlattenable> TestLooper::CreateProc(SkReadBuffer&) { return sk_make_sp<TestLooper>(); }
607e44bb191633e225fd0455c267dbf67f9ee8633emtklein
613d60812865bb034851da777a91413ab584929887reed@google.comstatic void test_drawBitmap(skiatest::Reporter* reporter) {
623d60812865bb034851da777a91413ab584929887reed@google.com    SkBitmap src;
63deee496cd30070e52556dcb538c2e5eb39b66b81mike@reedtribe.org    src.allocN32Pixels(10, 10);
643d60812865bb034851da777a91413ab584929887reed@google.com    src.eraseColor(SK_ColorWHITE);
653d60812865bb034851da777a91413ab584929887reed@google.com
663d60812865bb034851da777a91413ab584929887reed@google.com    SkBitmap dst;
67deee496cd30070e52556dcb538c2e5eb39b66b81mike@reedtribe.org    dst.allocN32Pixels(10, 10);
68dbfac8a72393eaf01670aeb3244de0e18d8faf98junov@google.com    dst.eraseColor(SK_ColorTRANSPARENT);
693d60812865bb034851da777a91413ab584929887reed@google.com
703d60812865bb034851da777a91413ab584929887reed@google.com    SkCanvas canvas(dst);
713d60812865bb034851da777a91413ab584929887reed@google.com    SkPaint  paint;
723d60812865bb034851da777a91413ab584929887reed@google.com
733d60812865bb034851da777a91413ab584929887reed@google.com    // we are initially transparent
743d60812865bb034851da777a91413ab584929887reed@google.com    REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
753d60812865bb034851da777a91413ab584929887reed@google.com
763d60812865bb034851da777a91413ab584929887reed@google.com    // we see the bitmap drawn
773d60812865bb034851da777a91413ab584929887reed@google.com    canvas.drawBitmap(src, 0, 0, &paint);
783d60812865bb034851da777a91413ab584929887reed@google.com    REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
793d60812865bb034851da777a91413ab584929887reed@google.com
803d60812865bb034851da777a91413ab584929887reed@google.com    // reverify we are clear again
81dbfac8a72393eaf01670aeb3244de0e18d8faf98junov@google.com    dst.eraseColor(SK_ColorTRANSPARENT);
823d60812865bb034851da777a91413ab584929887reed@google.com    REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
833d60812865bb034851da777a91413ab584929887reed@google.com
843d60812865bb034851da777a91413ab584929887reed@google.com    // if the bitmap is clipped out, we don't draw it
853d60812865bb034851da777a91413ab584929887reed@google.com    canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
863d60812865bb034851da777a91413ab584929887reed@google.com    REPORTER_ASSERT(reporter, 0 == *dst.getAddr32(5, 5));
873d60812865bb034851da777a91413ab584929887reed@google.com
883d60812865bb034851da777a91413ab584929887reed@google.com    // now install our looper, which will draw, since it internally translates
893d60812865bb034851da777a91413ab584929887reed@google.com    // to the left. The test is to ensure that canvas' quickReject machinary
903d60812865bb034851da777a91413ab584929887reed@google.com    // allows us through, even though sans-looper we would look like we should
913d60812865bb034851da777a91413ab584929887reed@google.com    // be clipped out.
927b380d0d0e91ae6967c52bfa14853a77b9551de4reed    paint.setLooper(sk_make_sp<TestLooper>());
933d60812865bb034851da777a91413ab584929887reed@google.com    canvas.drawBitmap(src, SkIntToScalar(-10), 0, &paint);
943d60812865bb034851da777a91413ab584929887reed@google.com    REPORTER_ASSERT(reporter, 0xFFFFFFFF == *dst.getAddr32(5, 5));
953d60812865bb034851da777a91413ab584929887reed@google.com}
963d60812865bb034851da777a91413ab584929887reed@google.com
979b3aa54bc9605257c701cf465813f5fb1d7ba39ereedstatic void test_layers(skiatest::Reporter* reporter) {
989b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    SkCanvas canvas(100, 100);
999b3aa54bc9605257c701cf465813f5fb1d7ba39ereed
1009b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    SkRect r = SkRect::MakeWH(10, 10);
1019b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    REPORTER_ASSERT(reporter, false == canvas.quickReject(r));
1029b3aa54bc9605257c701cf465813f5fb1d7ba39ereed
1039b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    r.offset(300, 300);
1049b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    REPORTER_ASSERT(reporter, true == canvas.quickReject(r));
1059b3aa54bc9605257c701cf465813f5fb1d7ba39ereed
1069b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    // Test that saveLayer updates quickReject
1079b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    SkRect bounds = SkRect::MakeLTRB(50, 50, 70, 70);
10896fcdcc219d2a0d3579719b84b28bede76efba64halcanary    canvas.saveLayer(&bounds, nullptr);
1099b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    REPORTER_ASSERT(reporter, true == canvas.quickReject(SkRect::MakeWH(10, 10)));
1109b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    REPORTER_ASSERT(reporter, false == canvas.quickReject(SkRect::MakeWH(60, 60)));
1119b3aa54bc9605257c701cf465813f5fb1d7ba39ereed}
1129b3aa54bc9605257c701cf465813f5fb1d7ba39ereed
113fbfa25802709139c2f14e304319c9541da65ca27msarettstatic void test_quick_reject(skiatest::Reporter* reporter) {
114fbfa25802709139c2f14e304319c9541da65ca27msarett    SkCanvas canvas(100, 100);
115fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r0 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
116fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r1 = SkRect::MakeLTRB(-50.0f, 110.0f, 50.0f, 120.0f);
117fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r2 = SkRect::MakeLTRB(110.0f, -50.0f, 120.0f, 50.0f);
118fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r3 = SkRect::MakeLTRB(-120.0f, -50.0f, 120.0f, 50.0f);
119fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r4 = SkRect::MakeLTRB(-50.0f, -120.0f, 50.0f, 120.0f);
120fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r5 = SkRect::MakeLTRB(-120.0f, -120.0f, 120.0f, 120.0f);
121fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r6 = SkRect::MakeLTRB(-120.0f, -120.0f, -110.0f, -110.0f);
122fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r7 = SkRect::MakeLTRB(SK_ScalarNaN, -50.0f, 50.0f, 50.0f);
123fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r8 = SkRect::MakeLTRB(-50.0f, SK_ScalarNaN, 50.0f, 50.0f);
124fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r9 = SkRect::MakeLTRB(-50.0f, -50.0f, SK_ScalarNaN, 50.0f);
125fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r10 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, SK_ScalarNaN);
126fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, false == canvas.quickReject(r0));
127fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r1));
128fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r2));
129fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, false == canvas.quickReject(r3));
130fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, false == canvas.quickReject(r4));
131fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, false == canvas.quickReject(r5));
132fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r6));
133fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r7));
134fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r8));
135fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r9));
136fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r10));
137fbfa25802709139c2f14e304319c9541da65ca27msarett
138fbfa25802709139c2f14e304319c9541da65ca27msarett    SkMatrix m = SkMatrix::MakeScale(2.0f);
139fbfa25802709139c2f14e304319c9541da65ca27msarett    m.setTranslateX(10.0f);
140fbfa25802709139c2f14e304319c9541da65ca27msarett    m.setTranslateY(10.0f);
141fbfa25802709139c2f14e304319c9541da65ca27msarett    canvas.setMatrix(m);
142fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r11 = SkRect::MakeLTRB(5.0f, 5.0f, 100.0f, 100.0f);
143fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r12 = SkRect::MakeLTRB(5.0f, 50.0f, 100.0f, 100.0f);
144fbfa25802709139c2f14e304319c9541da65ca27msarett    SkRect r13 = SkRect::MakeLTRB(50.0f, 5.0f, 100.0f, 100.0f);
145fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, false == canvas.quickReject(r11));
146fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r12));
147fbfa25802709139c2f14e304319c9541da65ca27msarett    REPORTER_ASSERT(reporter, true == canvas.quickReject(r13));
148fbfa25802709139c2f14e304319c9541da65ca27msarett}
149fbfa25802709139c2f14e304319c9541da65ca27msarett
150e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.orgDEF_TEST(QuickReject, reporter) {
1513d60812865bb034851da777a91413ab584929887reed@google.com    test_drawBitmap(reporter);
1529b3aa54bc9605257c701cf465813f5fb1d7ba39ereed    test_layers(reporter);
153fbfa25802709139c2f14e304319c9541da65ca27msarett    test_quick_reject(reporter);
1543d60812865bb034851da777a91413ab584929887reed@google.com}
1559da5a5a198e5dc9148f7f30a6089377590eee55bmsarett
1569da5a5a198e5dc9148f7f30a6089377590eee55bmsarett// Regression test to make sure that we keep fIsScaleTranslate up to date on the canvas.
1579da5a5a198e5dc9148f7f30a6089377590eee55bmsarett// It is possible to set a new matrix on the canvas without calling setMatrix().  This tests
1589da5a5a198e5dc9148f7f30a6089377590eee55bmsarett// that code path.
1599da5a5a198e5dc9148f7f30a6089377590eee55bmsarettDEF_TEST(QuickReject_MatrixState, reporter) {
1609da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    SkCanvas canvas(100, 100);
1619da5a5a198e5dc9148f7f30a6089377590eee55bmsarett
1629da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    SkMatrix matrix;
1639da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    matrix.setRotate(45.0f);
1649da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    canvas.setMatrix(matrix);
1659da5a5a198e5dc9148f7f30a6089377590eee55bmsarett
1669da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    SkPaint paint;
1679da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    sk_sp<SkImageFilter> filter = SkLightingImageFilter::MakeDistantLitDiffuse(
1689da5a5a198e5dc9148f7f30a6089377590eee55bmsarett            SkPoint3::Make(1.0f, 1.0f, 1.0f), 0xFF0000FF, 2.0f, 0.5f, nullptr);
1699da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    REPORTER_ASSERT(reporter, filter);
1709da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    paint.setImageFilter(filter);
1719da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    SkCanvas::SaveLayerRec rec;
1729da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    rec.fPaint = &paint;
1739da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    canvas.saveLayer(rec);
1749da5a5a198e5dc9148f7f30a6089377590eee55bmsarett
1759da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    // quickReject() will assert if the matrix is out of sync.
1769da5a5a198e5dc9148f7f30a6089377590eee55bmsarett    canvas.quickReject(SkRect::MakeWH(100.0f, 100.0f));
1779da5a5a198e5dc9148f7f30a6089377590eee55bmsarett}
178