15587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com/*
25587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com * Copyright 2013 Google Inc.
35587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com *
45587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com * Use of this source code is governed by a BSD-style license that can be
55587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com * found in the LICENSE file.
65587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com */
75587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
824519371cb541db6f59d903d21878ed9c45eb549scroggo#include "CanvasStateHelpers.h"
95587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com#include "SkCanvas.h"
105587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com#include "SkCanvasStateUtils.h"
1124519371cb541db6f59d903d21878ed9c45eb549scroggo#include "SkCommandLineFlags.h"
125587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com#include "SkDrawFilter.h"
1307f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org#include "SkError.h"
145587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com#include "SkPaint.h"
155587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com#include "SkRRect.h"
168f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "SkRect.h"
178f6884aab8aecd7657cf3f9cdbc682f0deca29c5tfarina@chromium.org#include "Test.h"
185587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1924519371cb541db6f59d903d21878ed9c45eb549scroggo// dlopen and the library flag are only used for tests which require this flag.
20b93ba45b58ad24e0e2cb75b842e24ff711c368b0reed@google.com#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
2124519371cb541db6f59d903d21878ed9c45eb549scroggo#include <dlfcn.h>
2224519371cb541db6f59d903d21878ed9c45eb549scroggo
2324519371cb541db6f59d903d21878ed9c45eb549scroggoDEFINE_string(library, "", "Support library to use for CanvasState test. If empty (the default), "
2424519371cb541db6f59d903d21878ed9c45eb549scroggo                           "the test will be run without crossing a library boundary. Otherwise, "
2524519371cb541db6f59d903d21878ed9c45eb549scroggo                           "it is expected to be a full path to a shared library file, which will"
2624519371cb541db6f59d903d21878ed9c45eb549scroggo                           " be dynamically loaded. Functions from the library will be called to "
2724519371cb541db6f59d903d21878ed9c45eb549scroggo                           "test SkCanvasState. Instructions for generating the library are in "
2824519371cb541db6f59d903d21878ed9c45eb549scroggo                           "gyp/canvas_state_lib.gyp");
2924519371cb541db6f59d903d21878ed9c45eb549scroggo
3024519371cb541db6f59d903d21878ed9c45eb549scroggo
3124519371cb541db6f59d903d21878ed9c45eb549scroggo// This class calls dlopen on the library passed in to the command line flag library, and handles
3224519371cb541db6f59d903d21878ed9c45eb549scroggo// calling dlclose when it goes out of scope.
3324519371cb541db6f59d903d21878ed9c45eb549scroggoclass OpenLibResult {
3424519371cb541db6f59d903d21878ed9c45eb549scroggopublic:
3524519371cb541db6f59d903d21878ed9c45eb549scroggo    // If the flag library was passed to this run of the test, attempt to open it using dlopen and
3624519371cb541db6f59d903d21878ed9c45eb549scroggo    // report whether it succeeded.
3724519371cb541db6f59d903d21878ed9c45eb549scroggo    OpenLibResult(skiatest::Reporter* reporter) {
3824519371cb541db6f59d903d21878ed9c45eb549scroggo        if (FLAGS_library.count() == 1) {
3924519371cb541db6f59d903d21878ed9c45eb549scroggo            fHandle = dlopen(FLAGS_library[0], RTLD_LAZY | RTLD_LOCAL);
4024519371cb541db6f59d903d21878ed9c45eb549scroggo            REPORTER_ASSERT_MESSAGE(reporter, fHandle != NULL, "Failed to open library!");
4124519371cb541db6f59d903d21878ed9c45eb549scroggo        } else {
4224519371cb541db6f59d903d21878ed9c45eb549scroggo            fHandle = NULL;
4324519371cb541db6f59d903d21878ed9c45eb549scroggo        }
4424519371cb541db6f59d903d21878ed9c45eb549scroggo    }
4524519371cb541db6f59d903d21878ed9c45eb549scroggo
4624519371cb541db6f59d903d21878ed9c45eb549scroggo    // Automatically call dlclose when going out of scope.
4724519371cb541db6f59d903d21878ed9c45eb549scroggo    ~OpenLibResult() {
4824519371cb541db6f59d903d21878ed9c45eb549scroggo        if (fHandle) {
4924519371cb541db6f59d903d21878ed9c45eb549scroggo            dlclose(fHandle);
5024519371cb541db6f59d903d21878ed9c45eb549scroggo        }
5124519371cb541db6f59d903d21878ed9c45eb549scroggo    }
5224519371cb541db6f59d903d21878ed9c45eb549scroggo
5324519371cb541db6f59d903d21878ed9c45eb549scroggo    // Pointer to the shared library object.
5424519371cb541db6f59d903d21878ed9c45eb549scroggo    void* handle() { return fHandle; }
5524519371cb541db6f59d903d21878ed9c45eb549scroggo
5624519371cb541db6f59d903d21878ed9c45eb549scroggoprivate:
5724519371cb541db6f59d903d21878ed9c45eb549scroggo    void* fHandle;
5824519371cb541db6f59d903d21878ed9c45eb549scroggo};
5924519371cb541db6f59d903d21878ed9c45eb549scroggo
6024519371cb541db6f59d903d21878ed9c45eb549scroggoDEF_TEST(CanvasState_test_complex_layers, reporter) {
615587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    const int WIDTH = 400;
625587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    const int HEIGHT = 400;
635587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    const int SPACER = 10;
645587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
6520146b3f7339d2c71c416397135e70e34f7fedb1djsollen@google.com    SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
6620146b3f7339d2c71c416397135e70e34f7fedb1djsollen@google.com                                   SkIntToScalar(WIDTH-(2*SPACER)),
6720146b3f7339d2c71c416397135e70e34f7fedb1djsollen@google.com                                   SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
685587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
69fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org    const SkColorType colorTypes[] = {
7028fcae2ec77eb16a79e155f8d788b20457f1c951commit-bot@chromium.org        kRGB_565_SkColorType, kN32_SkColorType
715587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    };
725587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
735587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    const int layerAlpha[] = { 255, 255, 0 };
745587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
755587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                                          SkCanvas::kARGB_ClipLayer_SaveFlag,
765587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                                          SkCanvas::kARGB_NoClipLayer_SaveFlag
775587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    };
785587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
7924519371cb541db6f59d903d21878ed9c45eb549scroggo
8024519371cb541db6f59d903d21878ed9c45eb549scroggo    bool (*drawFn)(SkCanvasState* state, float l, float t,
8124519371cb541db6f59d903d21878ed9c45eb549scroggo                   float r, float b, int32_t s);
8224519371cb541db6f59d903d21878ed9c45eb549scroggo
8324519371cb541db6f59d903d21878ed9c45eb549scroggo    OpenLibResult openLibResult(reporter);
8424519371cb541db6f59d903d21878ed9c45eb549scroggo    if (openLibResult.handle() != NULL) {
8524519371cb541db6f59d903d21878ed9c45eb549scroggo        *(void**) (&drawFn) = dlsym(openLibResult.handle(),
8624519371cb541db6f59d903d21878ed9c45eb549scroggo                                    "complex_layers_draw_from_canvas_state");
8724519371cb541db6f59d903d21878ed9c45eb549scroggo    } else {
8824519371cb541db6f59d903d21878ed9c45eb549scroggo        drawFn = complex_layers_draw_from_canvas_state;
8924519371cb541db6f59d903d21878ed9c45eb549scroggo    }
9024519371cb541db6f59d903d21878ed9c45eb549scroggo
9124519371cb541db6f59d903d21878ed9c45eb549scroggo    REPORTER_ASSERT(reporter, drawFn);
9224519371cb541db6f59d903d21878ed9c45eb549scroggo    if (!drawFn) {
9324519371cb541db6f59d903d21878ed9c45eb549scroggo        return;
9424519371cb541db6f59d903d21878ed9c45eb549scroggo    }
955587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
96ecce60bad6e3b7a72e1eba820bc3be15d39a1c21scroggo    for (size_t i = 0; i < SK_ARRAY_COUNT(colorTypes); ++i) {
975587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        SkBitmap bitmaps[2];
985587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        for (int j = 0; j < 2; ++j) {
99fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org            bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
100fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org                                                     colorTypes[i],
101fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org                                                     kPremul_SkAlphaType));
1025587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1035587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com            SkCanvas canvas(bitmaps[j]);
1045587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1055587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com            canvas.drawColor(SK_ColorRED);
1065587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
10724519371cb541db6f59d903d21878ed9c45eb549scroggo            for (size_t k = 0; k < SK_ARRAY_COUNT(layerAlpha); ++k) {
1085587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                // draw a rect within the layer's bounds and again outside the layer's bounds
1095587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
1105587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1115587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                if (j) {
11224519371cb541db6f59d903d21878ed9c45eb549scroggo                    // Capture from the first Skia.
11324519371cb541db6f59d903d21878ed9c45eb549scroggo                    SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
1145587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                    REPORTER_ASSERT(reporter, state);
1155587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
11624519371cb541db6f59d903d21878ed9c45eb549scroggo                    // And draw to it in the second Skia.
11724519371cb541db6f59d903d21878ed9c45eb549scroggo                    bool success = complex_layers_draw_from_canvas_state(state,
11824519371cb541db6f59d903d21878ed9c45eb549scroggo                            rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, SPACER);
11924519371cb541db6f59d903d21878ed9c45eb549scroggo                    REPORTER_ASSERT(reporter, success);
1205587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
12124519371cb541db6f59d903d21878ed9c45eb549scroggo                    // And release it in the *first* Skia.
12224519371cb541db6f59d903d21878ed9c45eb549scroggo                    SkCanvasStateUtils::ReleaseCanvasState(state);
12324519371cb541db6f59d903d21878ed9c45eb549scroggo                } else {
12424519371cb541db6f59d903d21878ed9c45eb549scroggo                    // Draw in the first Skia.
12524519371cb541db6f59d903d21878ed9c45eb549scroggo                    complex_layers_draw(&canvas, rect.fLeft, rect.fTop,
12624519371cb541db6f59d903d21878ed9c45eb549scroggo                                        rect.fRight, rect.fBottom, SPACER);
12724519371cb541db6f59d903d21878ed9c45eb549scroggo                }
1285587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1295587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                canvas.restore();
1305587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1315587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                // translate the canvas for the next iteration
1325587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                canvas.translate(0, 2*(rect.height() + SPACER));
1335587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com            }
1345587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        }
1355587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1365587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        // now we memcmp the two bitmaps
1375587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
1385587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com        REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
1395587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                                          bitmaps[1].getPixels(),
1405587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com                                          bitmaps[0].getSize()));
1415587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    }
1425587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com}
14324519371cb541db6f59d903d21878ed9c45eb549scroggo#endif
1445587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
1455587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com////////////////////////////////////////////////////////////////////////////////
1465587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
147b93ba45b58ad24e0e2cb75b842e24ff711c368b0reed@google.com#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
14824519371cb541db6f59d903d21878ed9c45eb549scroggoDEF_TEST(CanvasState_test_complex_clips, reporter) {
149339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    const int WIDTH = 400;
150339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    const int HEIGHT = 400;
1511037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com    const int SPACER = 10;
152339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
1531037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com    SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
154339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    layerRect.inset(2*SPACER, 2*SPACER);
155339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
1561037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com    SkIRect clipRect = layerRect;
157339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
158339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    clipRect.outset(SPACER, SPACER);
159339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
1601037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com    SkIRect regionBounds = clipRect;
161339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    regionBounds.offset(clipRect.width() + (2*SPACER), 0);
162339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
163339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    SkIRect regionInterior = regionBounds;
164339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    regionInterior.inset(SPACER*3, SPACER*3);
165339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
166339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    SkRegion clipRegion;
167339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    clipRegion.setRect(regionBounds);
168339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    clipRegion.op(regionInterior, SkRegion::kDifference_Op);
169339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
170339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
171339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
172339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                     SkRegion::kIntersect_Op,
173339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                     SkRegion::kReplace_Op,
174339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    };
175339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
176339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                          SkCanvas::kARGB_ClipLayer_SaveFlag,
177339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                          SkCanvas::kARGB_NoClipLayer_SaveFlag,
178339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    };
179339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
18024519371cb541db6f59d903d21878ed9c45eb549scroggo
18124519371cb541db6f59d903d21878ed9c45eb549scroggo    bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t,
18224519371cb541db6f59d903d21878ed9c45eb549scroggo                   int32_t r, int32_t b, int32_t clipOp,
18324519371cb541db6f59d903d21878ed9c45eb549scroggo                   int32_t regionRects, int32_t* rectCoords);
18424519371cb541db6f59d903d21878ed9c45eb549scroggo
18524519371cb541db6f59d903d21878ed9c45eb549scroggo    OpenLibResult openLibResult(reporter);
18624519371cb541db6f59d903d21878ed9c45eb549scroggo    if (openLibResult.handle() != NULL) {
18724519371cb541db6f59d903d21878ed9c45eb549scroggo        *(void**) (&drawFn) = dlsym(openLibResult.handle(),
18824519371cb541db6f59d903d21878ed9c45eb549scroggo                                    "complex_clips_draw_from_canvas_state");
18924519371cb541db6f59d903d21878ed9c45eb549scroggo    } else {
19024519371cb541db6f59d903d21878ed9c45eb549scroggo        drawFn = complex_clips_draw_from_canvas_state;
19124519371cb541db6f59d903d21878ed9c45eb549scroggo    }
19224519371cb541db6f59d903d21878ed9c45eb549scroggo
19324519371cb541db6f59d903d21878ed9c45eb549scroggo    REPORTER_ASSERT(reporter, drawFn);
19424519371cb541db6f59d903d21878ed9c45eb549scroggo    if (!drawFn) {
19524519371cb541db6f59d903d21878ed9c45eb549scroggo        return;
19624519371cb541db6f59d903d21878ed9c45eb549scroggo    }
197339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
198339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    SkBitmap bitmaps[2];
199339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    for (int i = 0; i < 2; ++i) {
200fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org        bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
201339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
202339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com        SkCanvas canvas(bitmaps[i]);
203339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
204339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com        canvas.drawColor(SK_ColorRED);
205339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
206339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com        SkRegion localRegion = clipRegion;
207339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
20824519371cb541db6f59d903d21878ed9c45eb549scroggo        for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) {
2091037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com            SkRect layerBounds = SkRect::Make(layerRect);
2101037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com            canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
211339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
212339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com            if (i) {
21324519371cb541db6f59d903d21878ed9c45eb549scroggo                SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
214339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                REPORTER_ASSERT(reporter, state);
215339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
21624519371cb541db6f59d903d21878ed9c45eb549scroggo                SkRegion::Iterator iter(localRegion);
21724519371cb541db6f59d903d21878ed9c45eb549scroggo                SkTDArray<int32_t> rectCoords;
21824519371cb541db6f59d903d21878ed9c45eb549scroggo                for (; !iter.done(); iter.next()) {
21924519371cb541db6f59d903d21878ed9c45eb549scroggo                    const SkIRect& rect = iter.rect();
22024519371cb541db6f59d903d21878ed9c45eb549scroggo                    *rectCoords.append() = rect.fLeft;
22124519371cb541db6f59d903d21878ed9c45eb549scroggo                    *rectCoords.append() = rect.fTop;
22224519371cb541db6f59d903d21878ed9c45eb549scroggo                    *rectCoords.append() = rect.fRight;
22324519371cb541db6f59d903d21878ed9c45eb549scroggo                    *rectCoords.append() = rect.fBottom;
22424519371cb541db6f59d903d21878ed9c45eb549scroggo                }
22524519371cb541db6f59d903d21878ed9c45eb549scroggo                bool success = drawFn(state, clipRect.fLeft, clipRect.fTop,
22624519371cb541db6f59d903d21878ed9c45eb549scroggo                                      clipRect.fRight, clipRect.fBottom, clipOps[j],
22724519371cb541db6f59d903d21878ed9c45eb549scroggo                                      rectCoords.count() / 4, rectCoords.begin());
22824519371cb541db6f59d903d21878ed9c45eb549scroggo                REPORTER_ASSERT(reporter, success);
229339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
23024519371cb541db6f59d903d21878ed9c45eb549scroggo                SkCanvasStateUtils::ReleaseCanvasState(state);
23124519371cb541db6f59d903d21878ed9c45eb549scroggo            } else {
23224519371cb541db6f59d903d21878ed9c45eb549scroggo                complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop,
23324519371cb541db6f59d903d21878ed9c45eb549scroggo                                   clipRect.fRight, clipRect.fBottom, clipOps[j],
23424519371cb541db6f59d903d21878ed9c45eb549scroggo                                   localRegion);
23524519371cb541db6f59d903d21878ed9c45eb549scroggo            }
236339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
237339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com            canvas.restore();
238339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
239339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com            // translate the canvas and region for the next iteration
2401037c7b9f2f0220c4f0a90faebe3c89d4981c1e3djsollen@google.com            canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
241339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com            localRegion.translate(0, 2*(layerRect.height() + SPACER));
242339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com        }
243339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    }
244339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
245339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    // now we memcmp the two bitmaps
246339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
247339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com    REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
248339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                      bitmaps[1].getPixels(),
249339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com                                      bitmaps[0].getSize()));
250339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com}
25124519371cb541db6f59d903d21878ed9c45eb549scroggo#endif
252339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
253339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com////////////////////////////////////////////////////////////////////////////////
254339e79fbeabae18a8b9ea094293c7c25eaf9dd68djsollen@google.com
2555587ac09beec4c056332504f3fa85990520b43fddjsollen@google.comclass TestDrawFilter : public SkDrawFilter {
2565587ac09beec4c056332504f3fa85990520b43fddjsollen@google.compublic:
25736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool filter(SkPaint*, Type) override { return true; }
2585587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com};
2595587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
26024519371cb541db6f59d903d21878ed9c45eb549scroggoDEF_TEST(CanvasState_test_draw_filters, reporter) {
2615587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    TestDrawFilter drawFilter;
26215a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkBitmap bitmap;
26315a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    bitmap.allocN32Pixels(10, 10);
26415a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkCanvas canvas(bitmap);
2655587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2665587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    canvas.setDrawFilter(&drawFilter);
2675587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2685587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
2695587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    REPORTER_ASSERT(reporter, state);
2705587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
2715587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    REPORTER_ASSERT(reporter, tmpCanvas);
2725587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
27349f085dddff10473b6ebf832a974288300224e60bsalomon    REPORTER_ASSERT(reporter, canvas.getDrawFilter());
2745587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
2755587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2765587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    tmpCanvas->unref();
2775587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    SkCanvasStateUtils::ReleaseCanvasState(state);
2785587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com}
2795587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2805587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com////////////////////////////////////////////////////////////////////////////////
2815587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
28207f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org// we need this function to prevent SkError from printing to stdout
28307f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.orgstatic void error_callback(SkError code, void* ctx) {}
28407f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org
28524519371cb541db6f59d903d21878ed9c45eb549scroggoDEF_TEST(CanvasState_test_soft_clips, reporter) {
28615a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkBitmap bitmap;
28715a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    bitmap.allocN32Pixels(10, 10);
28815a140599942f70e47380e3f700a825c7cece3b4commit-bot@chromium.org    SkCanvas canvas(bitmap);
2895587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2905587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    SkRRect roundRect;
2915587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    roundRect.setOval(SkRect::MakeWH(5, 5));
2925587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
2935587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
2945587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
29507f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org    SkSetErrorCallback(error_callback, NULL);
29607f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org
2975587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
2985587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com    REPORTER_ASSERT(reporter, !state);
29907f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org
30007f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org    REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
30107f6cf372dc003694c79cfb313923fef9eaf8dc8commit-bot@chromium.org    SkClearLastError();
3025587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com}
3035587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com
304b93ba45b58ad24e0e2cb75b842e24ff711c368b0reed@google.com#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
30524519371cb541db6f59d903d21878ed9c45eb549scroggoDEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
30689f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    const int WIDTH = 100;
30789f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    const int HEIGHT = 100;
30889f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    const int LAYER_WIDTH = 50;
30989f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    const int LAYER_HEIGHT = 50;
31089f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org
31189f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    SkBitmap bitmap;
31289f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    bitmap.allocN32Pixels(WIDTH, HEIGHT);
31389f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    SkCanvas canvas(bitmap);
31489f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org
31589f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
31689f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
31789f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org
31889f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    // Check that saveLayer without the kClipToLayer_SaveFlag leaves the
31989f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    // clip stack unchanged.
32089f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
32189f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    SkRect clipStackBounds;
32289f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    SkClipStack::BoundsType boundsType;
32389f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
32489f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
32589f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
32689f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.restore();
32789f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org
32889f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
32989f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    // stack to the layer bounds.
33089f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
33189f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
33289f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
33389f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
33489f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org
33589f077ced4918ded7e911bc5052b61c90ad57a9asenorblanco@chromium.org    canvas.restore();
3365587ac09beec4c056332504f3fa85990520b43fddjsollen@google.com}
33724519371cb541db6f59d903d21878ed9c45eb549scroggo#endif
338