ClipStackTest.cpp revision a444430281ea35cb76fb42516978b4a93221c2c7
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com#include "Test.h"
9a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com#if SK_SUPPORT_GPU
10a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com    #include "GrClipMaskManager.h"
11a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com#endif
12bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com#include "SkClipStack.h"
131e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org#include "SkPath.h"
1451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com#include "SkRandom.h"
151e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org#include "SkRect.h"
1651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com#include "SkRegion.h"
1780214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
191e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgstatic void test_assign_and_comparison(skiatest::Reporter* reporter) {
201e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkClipStack s;
21d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    bool doAA = false;
221e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
2380214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
2480214e26c57c5fea954006400852e8999e201923robertphillips@google.com
251e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Build up a clip stack with a path, an empty clip, and a rect.
261e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
2780214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
2880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
291e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkPath p;
301e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    p.moveTo(5, 6);
311e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    p.lineTo(7, 8);
321e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    p.lineTo(5, 9);
331e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    p.close();
34d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
351e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
361e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
3780214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
3880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
391e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
40d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
411e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    r = SkRect::MakeLTRB(10, 11, 12, 13);
42d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
431e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
441e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
4580214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
4680214e26c57c5fea954006400852e8999e201923robertphillips@google.com
471e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    r = SkRect::MakeLTRB(14, 15, 16, 17);
48d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
491e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
501e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that assignment works.
511e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkClipStack copy = s;
521e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s == copy);
531e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
541e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that different save levels triggers not equal.
551e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
5680214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
571e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s != copy);
581e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
591e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that an equal, but not copied version is equal.
601e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
6180214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
6280214e26c57c5fea954006400852e8999e201923robertphillips@google.com
631e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    r = SkRect::MakeLTRB(14, 15, 16, 17);
64d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
651e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s == copy);
661e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
671e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that a different op on one level triggers not equal.
681e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
6980214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
701e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
7180214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
7280214e26c57c5fea954006400852e8999e201923robertphillips@google.com
731e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    r = SkRect::MakeLTRB(14, 15, 16, 17);
74d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
751e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s != copy);
761e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
771e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that different state (clip type) triggers not equal.
784c4337291d873c4f27cb7903645863dc65b98a7btomhudson@google.com    // NO LONGER VALID: if a path contains only a rect, we turn
794c4337291d873c4f27cb7903645863dc65b98a7btomhudson@google.com    // it into a bare rect for performance reasons (working
804c4337291d873c4f27cb7903645863dc65b98a7btomhudson@google.com    // around Chromium/JavaScript bad pattern).
814c4337291d873c4f27cb7903645863dc65b98a7btomhudson@google.com/*
821e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
831e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
841e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    SkPath rp;
851e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    rp.addRect(r);
86d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevPath(rp, SkRegion::kUnion_Op, doAA);
871e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s != copy);
884c4337291d873c4f27cb7903645863dc65b98a7btomhudson@google.com*/
891e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
901e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that different rects triggers not equal.
911e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
9280214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
931e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
9480214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
9580214e26c57c5fea954006400852e8999e201923robertphillips@google.com
961e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    r = SkRect::MakeLTRB(24, 25, 26, 27);
97d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
981e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s != copy);
991e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
1001e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Sanity check
1011e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
10280214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
10380214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1041e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    copy.restore();
10580214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
1061e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s == copy);
1071e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
10880214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
1091e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    copy.restore();
11080214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
1111e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s == copy);
1121e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
1131e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    // Test that different paths triggers not equal.
1141e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.restore();
11580214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
1161e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    s.save();
11780214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
11880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1191e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    p.addRect(r);
120d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com    s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
1211e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    REPORTER_ASSERT(reporter, s != copy);
1221e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org}
123bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
124bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.comstatic void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack,
125bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com                         int count) {
12680214e26c57c5fea954006400852e8999e201923robertphillips@google.com    SkClipStack::B2TIter iter(stack);
127bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    int counter = 0;
128bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    while (iter.next()) {
129bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com        counter += 1;
130bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    }
131bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    REPORTER_ASSERT(reporter, count == counter);
132bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com}
133bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
13408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com// Exercise the SkClipStack's bottom to top and bidirectional iterators
13508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com// (including the skipToTopmost functionality)
13680214e26c57c5fea954006400852e8999e201923robertphillips@google.comstatic void test_iterators(skiatest::Reporter* reporter) {
13780214e26c57c5fea954006400852e8999e201923robertphillips@google.com    SkClipStack stack;
13880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
13980214e26c57c5fea954006400852e8999e201923robertphillips@google.com    static const SkRect gRects[] = {
14080214e26c57c5fea954006400852e8999e201923robertphillips@google.com        { 0,   0,  40,  40 },
14180214e26c57c5fea954006400852e8999e201923robertphillips@google.com        { 60,  0, 100,  40 },
14280214e26c57c5fea954006400852e8999e201923robertphillips@google.com        { 0,  60,  40, 100 },
14380214e26c57c5fea954006400852e8999e201923robertphillips@google.com        { 60, 60, 100, 100 }
14480214e26c57c5fea954006400852e8999e201923robertphillips@google.com    };
14580214e26c57c5fea954006400852e8999e201923robertphillips@google.com
14680214e26c57c5fea954006400852e8999e201923robertphillips@google.com    for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
14780214e26c57c5fea954006400852e8999e201923robertphillips@google.com        // the union op will prevent these from being fused together
14880214e26c57c5fea954006400852e8999e201923robertphillips@google.com        stack.clipDevRect(gRects[i], SkRegion::kUnion_Op, false);
14980214e26c57c5fea954006400852e8999e201923robertphillips@google.com    }
15080214e26c57c5fea954006400852e8999e201923robertphillips@google.com
15180214e26c57c5fea954006400852e8999e201923robertphillips@google.com    assert_count(reporter, stack, 4);
15280214e26c57c5fea954006400852e8999e201923robertphillips@google.com
15380214e26c57c5fea954006400852e8999e201923robertphillips@google.com    // bottom to top iteration
15480214e26c57c5fea954006400852e8999e201923robertphillips@google.com    {
1558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkClipStack::Element* element = NULL;
15680214e26c57c5fea954006400852e8999e201923robertphillips@google.com
15780214e26c57c5fea954006400852e8999e201923robertphillips@google.com        SkClipStack::B2TIter iter(stack);
15880214e26c57c5fea954006400852e8999e201923robertphillips@google.com        int i;
15980214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1608182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
1618182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
1628182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
16380214e26c57c5fea954006400852e8999e201923robertphillips@google.com        }
16480214e26c57c5fea954006400852e8999e201923robertphillips@google.com
16580214e26c57c5fea954006400852e8999e201923robertphillips@google.com        SkASSERT(i == 4);
16680214e26c57c5fea954006400852e8999e201923robertphillips@google.com    }
16780214e26c57c5fea954006400852e8999e201923robertphillips@google.com
16880214e26c57c5fea954006400852e8999e201923robertphillips@google.com    // top to bottom iteration
16980214e26c57c5fea954006400852e8999e201923robertphillips@google.com    {
1708182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkClipStack::Element* element = NULL;
17180214e26c57c5fea954006400852e8999e201923robertphillips@google.com
17280214e26c57c5fea954006400852e8999e201923robertphillips@google.com        SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
17380214e26c57c5fea954006400852e8999e201923robertphillips@google.com        int i;
17480214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1758182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
1768182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
1778182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
17880214e26c57c5fea954006400852e8999e201923robertphillips@google.com        }
17980214e26c57c5fea954006400852e8999e201923robertphillips@google.com
18080214e26c57c5fea954006400852e8999e201923robertphillips@google.com        SkASSERT(i == -1);
18180214e26c57c5fea954006400852e8999e201923robertphillips@google.com    }
18280214e26c57c5fea954006400852e8999e201923robertphillips@google.com
18380214e26c57c5fea954006400852e8999e201923robertphillips@google.com    // skipToTopmost
18480214e26c57c5fea954006400852e8999e201923robertphillips@google.com    {
1858182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkClipStack::Element* element = NULL;
18680214e26c57c5fea954006400852e8999e201923robertphillips@google.com
18780214e26c57c5fea954006400852e8999e201923robertphillips@google.com        SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
18880214e26c57c5fea954006400852e8999e201923robertphillips@google.com
1898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        element = iter.skipToTopmost(SkRegion::kUnion_Op);
1908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
1918182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
19280214e26c57c5fea954006400852e8999e201923robertphillips@google.com    }
19380214e26c57c5fea954006400852e8999e201923robertphillips@google.com}
19480214e26c57c5fea954006400852e8999e201923robertphillips@google.com
19508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com// Exercise the SkClipStack's getConservativeBounds computation
1964c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.comstatic void test_bounds(skiatest::Reporter* reporter, bool useRects) {
197607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
198607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    static const int gNumCases = 20;
199607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    static const SkRect gAnswerRectsBW[gNumCases] = {
200607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        // A op B
201607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 50, 50 },
202607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 50, 50 },
203607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 80, 80 },
204607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 80, 80 },
205607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 80, 80 },
206607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
207607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        // invA op B
208607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 80, 80 },
209607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
210607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
211607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
212607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 50, 50 },
213607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
214607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        // A op invB
215607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 50, 50 },
216607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 50, 50 },
217607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
218607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
219607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
220607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
221607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        // invA op invB
222607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
223607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 40, 40, 80, 80 },
224607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 0, 0, 100, 100 },
225607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 80, 80 },
226607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        { 10, 10, 50, 50 },
227607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    };
228607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
229607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    static const SkRegion::Op gOps[] = {
230607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        SkRegion::kIntersect_Op,
231607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        SkRegion::kDifference_Op,
232607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        SkRegion::kUnion_Op,
233607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        SkRegion::kXOR_Op,
234607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        SkRegion::kReverseDifference_Op
235607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    };
236607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
237607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    SkRect rectA, rectB;
238607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
239607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    rectA.iset(10, 10, 50, 50);
240607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    rectB.iset(40, 40, 80, 80);
241607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
242607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    SkPath clipA, clipB;
243607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
244607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
245607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
246607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
247607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    SkClipStack stack;
2487b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com    SkRect devClipBound;
2494c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com    bool isIntersectionOfRects = false;
250607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
251607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    int testCase = 0;
2524c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com    int numBitTests = useRects ? 1 : 4;
2534c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com    for (int invBits = 0; invBits < numBitTests; ++invBits) {
254607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
255607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
256607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            stack.save();
257607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            bool doInvA = SkToBool(invBits & 1);
258607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            bool doInvB = SkToBool(invBits & 2);
259607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
260607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
261607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com                                       SkPath::kEvenOdd_FillType);
262607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
263607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com                                       SkPath::kEvenOdd_FillType);
264607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
2654c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            if (useRects) {
2664c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false);
2674c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                stack.clipDevRect(rectB, gOps[op], false);
2684c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            } else {
2694c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false);
2704c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                stack.clipDevPath(clipB, gOps[op], false);
2714c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            }
272607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
273cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com            REPORTER_ASSERT(reporter, !stack.isWideOpen());
274cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
2757b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
2764c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                                        &isIntersectionOfRects);
2774c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com
2784c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            if (useRects) {
279d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                REPORTER_ASSERT(reporter, isIntersectionOfRects ==
2804c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                        (gOps[op] == SkRegion::kIntersect_Op));
2814c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            } else {
2824c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com                REPORTER_ASSERT(reporter, !isIntersectionOfRects);
2834c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com            }
284607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
285607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            SkASSERT(testCase < gNumCases);
2867b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com            REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
287607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            ++testCase;
288607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
289607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com            stack.restore();
290607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com        }
291607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com    }
292607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com}
293607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com
294cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com// Test out 'isWideOpen' entry point
295cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.comstatic void test_isWideOpen(skiatest::Reporter* reporter) {
296cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
297cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    SkRect rectA, rectB;
298cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
299cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    rectA.iset(10, 10, 40, 40);
300cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    rectB.iset(50, 50, 80, 80);
301cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
302cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    // Stack should initially be wide open
303cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    {
304cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkClipStack stack;
305cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
306cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, stack.isWideOpen());
307cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    }
308cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
309cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    // Test out case where the user specifies a union that includes everything
310cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    {
311cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkClipStack stack;
312cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
313cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkPath clipA, clipB;
314cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
315cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
316cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        clipA.setFillType(SkPath::kInverseEvenOdd_FillType);
317cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
318cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
319cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        clipB.setFillType(SkPath::kInverseEvenOdd_FillType);
320cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
321cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.clipDevPath(clipA, SkRegion::kReplace_Op, false);
322cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.clipDevPath(clipB, SkRegion::kUnion_Op, false);
323cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
324cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, stack.isWideOpen());
325cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    }
326cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
327cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    // Test out union w/ a wide open clip
328cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    {
329cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkClipStack stack;
330cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
331cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.clipDevRect(rectA, SkRegion::kUnion_Op, false);
332cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
333cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, stack.isWideOpen());
334cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    }
335cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
336cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    // Test out empty difference from a wide open clip
337cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    {
338cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkClipStack stack;
339cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
340cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkRect emptyRect;
341cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        emptyRect.setEmpty();
342cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
343cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.clipDevRect(emptyRect, SkRegion::kDifference_Op, false);
344cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
345cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, stack.isWideOpen());
346cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    }
347cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
348cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    // Test out return to wide open
349cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    {
350cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        SkClipStack stack;
351cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
352cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.save();
353cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
354cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.clipDevRect(rectA, SkRegion::kReplace_Op, false);
355cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
356cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, !stack.isWideOpen());
357cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
358cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        stack.restore();
359cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
360cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com        REPORTER_ASSERT(reporter, stack.isWideOpen());
361cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    }
362cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com}
363cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
364100abf49e10544bc4f436bf1f38e6929779621f4bsalomon@google.comstatic int count(const SkClipStack& stack) {
36508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
36608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
36708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
3688182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    const SkClipStack::Element* element = NULL;
36908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    int count = 0;
37008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
3718182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    for (element = iter.prev(); element; element = iter.prev(), ++count) {
37208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        ;
37308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
37408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
37508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    return count;
37608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com}
37708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
37808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com// Test out SkClipStack's merging of rect clips. In particular exercise
37908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com// merging of aa vs. bw rects.
38008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.comstatic void test_rect_merging(skiatest::Reporter* reporter) {
38108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
38208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkRect overlapLeft  = SkRect::MakeLTRB(10, 10, 50, 50);
38308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
38408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
38508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
38608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkRect nestedChild  = SkRect::MakeLTRB(40, 40, 60, 60);
38708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
38808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkRect bound;
38908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    SkClipStack::BoundsType type;
39008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    bool isIntersectionOfRects;
39108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
39208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // all bw overlapping - should merge
39308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
39408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
39508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
39608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, false);
39708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
39808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
39908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
40008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 1 == count(stack));
40108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
40208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
40308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
40408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, isIntersectionOfRects);
40508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
40608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
40708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // all aa overlapping - should merge
40808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
40908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
41008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
41108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
41208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
41308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true);
41408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
41508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 1 == count(stack));
41608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
41708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
41808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
41908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, isIntersectionOfRects);
42008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
42108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
42208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // mixed overlapping - should _not_ merge
42308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
42408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
42508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
42608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
42708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
42808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
42908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
43008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 2 == count(stack));
43108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
43208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
43308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
43408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, !isIntersectionOfRects);
43508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
43608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
43708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // mixed nested (bw inside aa) - should merge
43808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
43908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
44008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
44108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, true);
44208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
44308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false);
44408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
44508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 1 == count(stack));
44608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
44708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
44808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
44908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, isIntersectionOfRects);
45008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
45108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
45208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // mixed nested (aa inside bw) - should merge
45308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
45408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
45508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
45608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, false);
45708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
45808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true);
45908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
46008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 1 == count(stack));
46108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
46208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
46308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
46408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, isIntersectionOfRects);
46508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
46608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
46708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    // reverse nested (aa inside bw) - should _not_ merge
46808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    {
46908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        SkClipStack stack;
47008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
47108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedChild, SkRegion::kReplace_Op, false);
47208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
47308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true);
47408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
47508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, 2 == count(stack));
47608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
47708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        stack.getBounds(&bound, &type, &isIntersectionOfRects);
47808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com
47908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com        REPORTER_ASSERT(reporter, !isIntersectionOfRects);
48008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    }
48108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com}
482cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com
48351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com///////////////////////////////////////////////////////////////////////////////////////////////////
48451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
485a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com#if SK_SUPPORT_GPU
486705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com// Functions that add a shape to the clip stack. The shape is computed from a rectangle.
487705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com// AA is always disabled since the clip stack reducer can cause changes in aa rasterization of the
488705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com// stack. A fractional edge repeated in different elements may be rasterized fewer times using the
489705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com// reduced stack.
490705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comtypedef void (*AddElementFunc) (const SkRect& rect,
491705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com                                bool invert,
492705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com                                SkRegion::Op op,
493705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com                                SkClipStack* stack);
494705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com
495705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comstatic void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
49651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkPath path;
49751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkScalar rx = rect.width() / 10;
498705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    SkScalar ry = rect.height() / 20;
49951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    path.addRoundRect(rect, rx, ry);
500705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    if (invert) {
501705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        path.setFillType(SkPath::kInverseWinding_FillType);
502705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    }
503705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    stack->clipDevPath(path, op, false);
50451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com};
50551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
506705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comstatic void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
507705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    if (invert) {
508705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        SkPath path;
509705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        path.addRect(rect);
510705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        path.setFillType(SkPath::kInverseWinding_FillType);
511705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        stack->clipDevPath(path, op, false);
512705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    } else {
513705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        stack->clipDevRect(rect, op, false);
514705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    }
51551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com};
51651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
517705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comstatic void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipStack* stack) {
51851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkPath path;
51951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    path.addOval(rect);
520705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    if (invert) {
521705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        path.setFillType(SkPath::kInverseWinding_FillType);
522705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    }
523705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    stack->clipDevPath(path, op, false);
52451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com};
52551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
5268182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comstatic void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
5278182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    switch (element.getType()) {
5288182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kRect_Type:
5298182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            stack->clipDevRect(element.getRect(), element.getOp(), element.isAA());
5308182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
5318182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kPath_Type:
5328182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            stack->clipDevPath(element.getPath(), element.getOp(), element.isAA());
5338182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
5348182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kEmpty_Type:
5358182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
5368182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            stack->clipEmpty();
5378182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
53851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    }
53951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com}
54051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
5418182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comstatic void add_elem_to_region(const SkClipStack::Element& element,
54251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                               const SkIRect& bounds,
54351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                               SkRegion* region) {
54451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkRegion elemRegion;
54551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkRegion boundsRgn(bounds);
54651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
5478182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    switch (element.getType()) {
5488182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kRect_Type: {
5498182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            SkPath path;
5508182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            path.addRect(element.getRect());
5518182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            elemRegion.setPath(path, boundsRgn);
5528182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
5538182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        }
5548182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kPath_Type:
5558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            elemRegion.setPath(element.getPath(), boundsRgn);
5568182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            break;
5578182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        case SkClipStack::Element::kEmpty_Type:
5588182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            //
5598182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            region->setEmpty();
5608182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            return;
56151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    }
5628182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    region->op(elemRegion, element.getOp());
56351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com}
56451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
56551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com// This can assist with debugging the clip stack reduction code when the test below fails.
5668182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comstatic void print_clip(const SkClipStack::Element& element) {
56751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const char* kOpStrs[] = {
56851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "DF",
56951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "IS",
57051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "UN",
57151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "XR",
57251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "RD",
57351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        "RP",
57451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    };
5758182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    if (SkClipStack::Element::kEmpty_Type != element.getType()) {
5768182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkRect& bounds = element.getBounds();
5778182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        bool isRect = SkClipStack::Element::kRect_Type == element.getType();
578705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com        SkDebugf("%s %s %s [%f %f] x [%f %f]\n",
5798182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                 kOpStrs[element.getOp()],
5808182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                 (isRect ? "R" : "P"),
5818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com                 (element.isInverseFilled() ? "I" : " "),
58251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                 bounds.fLeft, bounds.fRight, bounds.fTop, bounds.fBottom);
58351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    } else {
58451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkDebugf("EM\n");
58551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    }
58651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com}
58751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
58851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comstatic void test_reduced_clip_stack(skiatest::Reporter* reporter) {
58951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // We construct random clip stacks, reduce them, and then rasterize both versions to verify that
5908ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com    // they are equal.
59151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
59251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // All the clip elements will be contained within these bounds.
59351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const SkRect kBounds = SkRect::MakeWH(100, 100);
59451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
59551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    enum {
59651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        kNumTests = 200,
59751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        kMinElemsPerTest = 1,
59851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        kMaxElemsPerTest = 50,
59951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    };
60051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
60151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // min/max size of a clip element as a fraction of kBounds.
60251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5;
60351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const SkScalar kMaxElemSizeFrac = SK_Scalar1;
60451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
60551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const SkRegion::Op kOps[] = {
60651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kDifference_Op,
60751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kIntersect_Op,
60851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kUnion_Op,
60951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kXOR_Op,
61051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kReverseDifference_Op,
61151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion::kReplace_Op,
61251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    };
61351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
61451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // Replace operations short-circuit the optimizer. We want to make sure that we test this code
61551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // path a little bit but we don't want it to prevent us from testing many longer traversals in
61651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    // the optimizer.
61751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const int kReplaceDiv = 4 * kMaxElemsPerTest;
61851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
619705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    // We want to test inverse fills. However, they are quite rare in practice so don't over do it.
620705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com    static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest;
621705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com
62251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    static const AddElementFunc kElementFuncs[] = {
62351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        add_rect,
62451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        add_round_rect,
62551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        add_oval,
62651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    };
62751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
62851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    SkRandom r;
62951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
63051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    for (int i = 0; i < kNumTests; ++i) {
63151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        // Randomly generate a clip stack.
63251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkClipStack stack;
63351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest);
63451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        for (int e = 0; e < numElems; ++e) {
63551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))];
63651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            if (op == SkRegion::kReplace_Op) {
63751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                if (r.nextU() % kReplaceDiv) {
63851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                    --e;
63951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                    continue;
64051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                }
64151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            }
6428ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com
64351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            // saves can change the clip stack behavior when an element is added.
64451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            bool doSave = r.nextBool();
6458ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com
64651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            SkSize size = SkSize::Make(
64751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                SkScalarFloorToScalar(SkScalarMul(kBounds.width(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac))),
64851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                SkScalarFloorToScalar(SkScalarMul(kBounds.height(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac))));
64951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
65051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            SkPoint xy = {SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth)),
65151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                          SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight))};
65251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
65351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            SkRect rect = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
65451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
655705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com            bool invert = r.nextBiasedBool(kFractionInverted);
656705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com            kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect, invert, op, &stack);
65751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            if (doSave) {
65851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com                stack.save();
65951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            }
66051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        }
66151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
662a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com        SkRect inflatedBounds = kBounds;
663a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com        inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
664a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com        SkIRect inflatedIBounds;
665a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com        inflatedBounds.roundOut(&inflatedIBounds);
666a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com
6678182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        typedef GrReducedClip::ElementList ElementList;
66851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        // Get the reduced version of the stack.
6698182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        ElementList reducedClips;
670a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com
67151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        GrReducedClip::InitialState initial;
672a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com        GrReducedClip::GrReduceClipStack(stack, inflatedBounds, &reducedClips, &initial);
67351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
67451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        // Build a new clip stack based on the reduced clip elements
67551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkClipStack reducedStack;
67651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        if (GrReducedClip::kAllOut_InitialState == initial) {
67751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            // whether the result is bounded or not, the whole plane should start outside the clip.
67851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com            reducedStack.clipEmpty();
67951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        }
6808182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        for (ElementList::Iter iter = reducedClips.headIter(); NULL != iter.get(); iter.next()) {
6818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            add_elem_to_stack(*iter.get(), &reducedStack);
68251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        }
68351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
68451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        // convert both the original stack and reduced stack to SkRegions and see if they're equal
68551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion region;
68651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkRegion reducedRegion;
68751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
68851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        region.setRect(inflatedIBounds);
6898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        const SkClipStack::Element* element;
69051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
6918182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        while ((element = iter.next())) {
6928182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            add_elem_to_region(*element, inflatedIBounds, &region);
69351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        }
69451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
69551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        reducedRegion.setRect(inflatedIBounds);
69651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        iter.reset(reducedStack, SkClipStack::Iter::kBottom_IterStart);
6978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com        while ((element = iter.next())) {
6988182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com            add_elem_to_region(*element, inflatedIBounds, &reducedRegion);
69951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        }
70051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
70151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com        REPORTER_ASSERT(reporter, region == reducedRegion);
70251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com    }
70351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com}
70451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
705a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com#endif
70651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com///////////////////////////////////////////////////////////////////////////////////////////////////
70751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com
708bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.comstatic void TestClipStack(skiatest::Reporter* reporter) {
709bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    SkClipStack stack;
710bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
71180214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
712bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    assert_count(reporter, stack, 0);
713bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
714bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    static const SkIRect gRects[] = {
715bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com        { 0, 0, 100, 100 },
716bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com        { 25, 25, 125, 125 },
717bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com        { 0, 0, 1000, 1000 },
718bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com        { 0, 0, 75, 75 }
719bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    };
720bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
721d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com        stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op);
722bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    }
723bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
724bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    // all of the above rects should have been intersected, leaving only 1 rect
72580214e26c57c5fea954006400852e8999e201923robertphillips@google.com    SkClipStack::B2TIter iter(stack);
7268182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    const SkClipStack::Element* element = iter.next();
7272047f00e4698f83499ab91911999a65c21a951c9epoger@google.com    SkRect answer;
7282047f00e4698f83499ab91911999a65c21a951c9epoger@google.com    answer.iset(25, 25, 75, 75);
729bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
7308182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    REPORTER_ASSERT(reporter, NULL != element);
7318182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
7328182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == element->getOp());
7338182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com    REPORTER_ASSERT(reporter, element->getRect() == answer);
734bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    // now check that we only had one in our iterator
735bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    REPORTER_ASSERT(reporter, !iter.next());
736bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
737bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    stack.reset();
73880214e26c57c5fea954006400852e8999e201923robertphillips@google.com    REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
739bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com    assert_count(reporter, stack, 0);
7401e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org
7411e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org    test_assign_and_comparison(reporter);
74280214e26c57c5fea954006400852e8999e201923robertphillips@google.com    test_iterators(reporter);
74308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    test_bounds(reporter, true);        // once with rects
74408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    test_bounds(reporter, false);       // once with paths
745cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com    test_isWideOpen(reporter);
74608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com    test_rect_merging(reporter);
747e7b3d29a1289e64130dd0ec905d94feedc9d1064bsalomon@google.com#if SK_SUPPORT_GPU
748edb26fdb8349a727b226e90cbeab06cd25f5cac0bsalomon@google.com    test_reduced_clip_stack(reporter);
749e7b3d29a1289e64130dd0ec905d94feedc9d1064bsalomon@google.com#endif
750bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com}
751bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com
752bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com#include "TestClassDef.h"
753bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.comDEFINE_TESTCLASS("ClipStack", TestClipStackClass, TestClipStack)
754