Improve CanvasState cross-library tests
Several things are accomplished as part of this: 1. The canvas_state_lib build target is brought back so that we can actually test the canvas state sharing across library boundaries. 2. The canvas state helper functions are updated to work with DLLs (confirmed tests pass on Windows in cross library mode) 3. The tests now always run, and the cross-state define only changes what version of the helper functions are used 4. Updated the dlopen code in the test to use the SkOSLibrary ports instead of calling dlopen/dlclose directly. 5. Fix bugs in SkCanvasStateUtils that were uncovered as part of always running these tests. 6. Switches the define away from SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG to SK_TEST_CANVAS_STATE_CROSS_LIBRARY, since these tests are not strictly speaking testing the unclipped layer feature. Change-Id: Id4ae41e4bc3fb8227367deac899878ecf9d7b98e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/341003 Reviewed-by: Derek Sollenberger <djsollen@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
ae95077db6
commit
3021795041
9
BUILD.gn
9
BUILD.gn
@ -2034,6 +2034,15 @@ if (skia_enable_tools) {
|
||||
"modules/svg",
|
||||
]
|
||||
}
|
||||
|
||||
# optional separate library to dlopen when running CanvasStateTests.
|
||||
shared_library("canvas_state_lib") {
|
||||
sources = [
|
||||
"tests/CanvasStateHelpers.cpp",
|
||||
"tests/CanvasStateHelpers.h",
|
||||
]
|
||||
deps = [ ":skia" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_win) {
|
||||
|
@ -2999,7 +2999,7 @@ const SkPaint& SkCanvas::LayerIter::paint() const {
|
||||
}
|
||||
|
||||
SkIRect SkCanvas::LayerIter::clipBounds() const {
|
||||
return fImpl->fDevice->getGlobalBounds();
|
||||
return fImpl->fDevice->devClipBounds();
|
||||
}
|
||||
|
||||
int SkCanvas::LayerIter::x() const { return fDeviceOrigin.fX; }
|
||||
|
@ -10,5 +10,6 @@
|
||||
|
||||
void* SkLoadDynamicLibrary(const char* libraryName);
|
||||
void* SkGetProcedureAddress(void* library, const char* functionName);
|
||||
bool SkFreeDynamicLibrary(void* library);
|
||||
|
||||
#endif
|
||||
|
@ -18,4 +18,9 @@ void* SkLoadDynamicLibrary(const char* libraryName) {
|
||||
void* SkGetProcedureAddress(void* library, const char* functionName) {
|
||||
return dlsym(library, functionName);
|
||||
}
|
||||
|
||||
bool SkFreeDynamicLibrary(void* library) {
|
||||
return dlclose(library) == 0;
|
||||
}
|
||||
|
||||
#endif//!defined(SK_BUILD_FOR_WIN)
|
||||
|
@ -18,4 +18,8 @@ void* SkGetProcedureAddress(void* library, const char* functionName) {
|
||||
return reinterpret_cast<void*>(::GetProcAddress((HMODULE)library, functionName));
|
||||
}
|
||||
|
||||
bool SkFreeDynamicLibrary(void* library) {
|
||||
return FreeLibrary((HMODULE)library);
|
||||
}
|
||||
|
||||
#endif//defined(SK_BUILD_FOR_WIN)
|
||||
|
@ -110,12 +110,20 @@ public:
|
||||
}
|
||||
|
||||
~SkCanvasState_v1() {
|
||||
// loop through the layers and free the data allocated to the clipRects
|
||||
// loop through the layers and free the data allocated to the clipRects.
|
||||
// See setup_MC_state, clipRects is only allocated when the clip isn't empty; and empty
|
||||
// is implicitly represented as clipRectCount == 0.
|
||||
for (int i = 0; i < layerCount; ++i) {
|
||||
sk_free(layers[i].mcState.clipRects);
|
||||
if (layers[i].mcState.clipRectCount > 0) {
|
||||
sk_free(layers[i].mcState.clipRects);
|
||||
}
|
||||
}
|
||||
|
||||
sk_free(mcState.clipRects);
|
||||
if (mcState.clipRectCount > 0) {
|
||||
sk_free(mcState.clipRects);
|
||||
}
|
||||
|
||||
// layers is always allocated, even if it's with sk_malloc(0), so this is safe.
|
||||
sk_free(layers);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,11 @@
|
||||
*/
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
|
||||
#if !defined(SK_TEST_CANVAS_STATE_CROSS_LIBRARY)
|
||||
|
||||
#include "tests/CanvasStateHelpers.h"
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkClipOp.h"
|
||||
#include "include/core/SkColor.h"
|
||||
@ -15,7 +19,6 @@
|
||||
#include "include/core/SkRegion.h"
|
||||
#include "include/core/SkScalar.h"
|
||||
#include "include/utils/SkCanvasStateUtils.h"
|
||||
#include "tests/CanvasStateHelpers.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -72,4 +75,5 @@ extern "C" bool complex_clips_draw_from_canvas_state(SkCanvasState* state,
|
||||
complex_clips_draw(canvas.get(), left, top, right, bottom, clipOp, localRegion);
|
||||
return true;
|
||||
}
|
||||
#endif // SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
|
||||
#endif // SK_TEST_CANVAS_STATE_CROSS_LIBRARY
|
||||
|
@ -10,11 +10,22 @@
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
// See CanvasStateTest. These functions are either linked in to 'dm' directly (when this flag is
|
||||
// not defined), or built in a shared library that is dlopened by the test. In that case, they
|
||||
// should not be visible in 'dm', but the shared library will not have this flag set and compiles
|
||||
// them as expected.
|
||||
#if !defined(SK_TEST_CANVAS_STATE_CROSS_LIBRARY)
|
||||
|
||||
class SkCanvas;
|
||||
class SkCanvasState;
|
||||
class SkRegion;
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN)
|
||||
#define EXPORT _declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Helper function to perform drawing to an SkCanvas. Used by both
|
||||
* test_complex_layers and complex_layers_draw_from_canvas_state.
|
||||
@ -28,7 +39,7 @@ void complex_layers_draw(SkCanvas* canvas, float left, float top,
|
||||
* Used by test_complex_layers test in CanvasStateTest. Marked as extern
|
||||
* so it can be called from a separate library.
|
||||
*/
|
||||
extern "C" bool complex_layers_draw_from_canvas_state(SkCanvasState* state,
|
||||
extern "C" bool EXPORT complex_layers_draw_from_canvas_state(SkCanvasState* state,
|
||||
float left, float top, float right, float bottom, int32_t spacer);
|
||||
|
||||
/*
|
||||
@ -44,9 +55,9 @@ void complex_clips_draw(SkCanvas* canvas, int32_t left, int32_t top,
|
||||
* Used by test_complex_clips test in CanvasStateTest. Marked as extern
|
||||
* so it can be called from a separate library.
|
||||
*/
|
||||
extern "C" bool complex_clips_draw_from_canvas_state(SkCanvasState* state,
|
||||
extern "C" bool EXPORT complex_clips_draw_from_canvas_state(SkCanvasState* state,
|
||||
int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t clipOp,
|
||||
int32_t regionRects, int32_t* rectCoords);
|
||||
|
||||
#endif // SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
#endif // SK_TEST_CANVAS_STATE_CROSS_LIBRARY
|
||||
#endif // CanvasStateHelpers_DEFINED
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/core/SkClipOpPriv.h"
|
||||
#include "src/core/SkTLazy.h"
|
||||
#include "tests/CanvasStateHelpers.h"
|
||||
#include "tests/Test.h"
|
||||
#include "tools/flags/CommandLineFlags.h"
|
||||
|
||||
@ -29,48 +28,59 @@
|
||||
|
||||
class SkCanvasState;
|
||||
|
||||
// dlopen and the library flag are only used for tests which require this flag.
|
||||
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
#include <dlfcn.h>
|
||||
// Uncomment to include tests of CanvasState across a library boundary. This will change how 'dm'
|
||||
// is built so that the functions defined in CanvasStateHelpers do not exist inside 'dm', and are
|
||||
// instead compiled as part of the 'canvas_state_lib' build target. This produces a shared library
|
||||
// that must be passed to 'dm' using the --library flag when running.
|
||||
// #define SK_TEST_CANVAS_STATE_CROSS_LIBRARY
|
||||
|
||||
// Must be included after SK_TEST_CANVAS_STATE_CROSS_LIBRARY is defined
|
||||
#include "tests/CanvasStateHelpers.h"
|
||||
|
||||
// dlopen, the library flag and canvas state helpers are only used for tests which require this flag
|
||||
#if defined(SK_TEST_CANVAS_STATE_CROSS_LIBRARY)
|
||||
|
||||
static DEFINE_string(library, "",
|
||||
"Support library to use for CanvasState test. If empty (the default), "
|
||||
"the test will be run without crossing a library boundary. Otherwise, "
|
||||
"it is expected to be a full path to a shared library file, which will"
|
||||
" be dynamically loaded. Functions from the library will be called to "
|
||||
"test SkCanvasState. Instructions for generating the library are in "
|
||||
"gyp/canvas_state_lib.gyp");
|
||||
"Support library to use for CanvasState test. Must be provided when"
|
||||
" SK_TEST_CANVAS_STATE_CROSS_LIBRARY to specify the dynamically loaded library"
|
||||
" that receives the captured canvas state. Functions from the library will be"
|
||||
" called to test SkCanvasState. The library is built from the canvas_state_lib"
|
||||
" target");
|
||||
|
||||
#include "src/ports/SkOSLibrary.h"
|
||||
|
||||
// This class calls dlopen on the library passed in to the command line flag library, and handles
|
||||
// calling dlclose when it goes out of scope.
|
||||
// Automatically loads library passed to --library flag and closes it when it goes out of scope.
|
||||
class OpenLibResult {
|
||||
public:
|
||||
// If the flag library was passed to this run of the test, attempt to open it using dlopen and
|
||||
// report whether it succeeded.
|
||||
OpenLibResult(skiatest::Reporter* reporter) {
|
||||
if (FLAGS_library.count() == 1) {
|
||||
fHandle = dlopen(FLAGS_library[0], RTLD_LAZY | RTLD_LOCAL);
|
||||
REPORTER_ASSERT(reporter, fHandle != nullptr, "Failed to open library!");
|
||||
fLibrary = SkLoadDynamicLibrary(FLAGS_library[0]);
|
||||
REPORTER_ASSERT(reporter, fLibrary != nullptr, "Failed to open library!");
|
||||
} else {
|
||||
fHandle = nullptr;
|
||||
fLibrary = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically call dlclose when going out of scope.
|
||||
~OpenLibResult() {
|
||||
if (fHandle) {
|
||||
dlclose(fHandle);
|
||||
if (fLibrary) {
|
||||
SkFreeDynamicLibrary(fLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer to the shared library object.
|
||||
void* handle() { return fHandle; }
|
||||
// Load a function address from the library object, or null if the library had failed
|
||||
void* procAddress(const char* funcName) {
|
||||
if (fLibrary) {
|
||||
return SkGetProcedureAddress(fLibrary, funcName);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void* fHandle;
|
||||
void* fLibrary;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static void write_image(const SkImage* img, const char path[]) {
|
||||
auto data = img->encodeToData();
|
||||
SkFILEWStream(path).write(data->data(), data->size());
|
||||
@ -96,7 +106,7 @@ static void compare(skiatest::Reporter* reporter, SkImage* img0, SkImage* img1)
|
||||
REPORTER_ASSERT(reporter, pm[0].computeByteSize() == pm[1].computeByteSize());
|
||||
REPORTER_ASSERT(reporter, pm[0].rowBytes() == (size_t)pm[0].width() * pm[0].info().bytesPerPixel());
|
||||
REPORTER_ASSERT(reporter, pm[1].rowBytes() == (size_t)pm[1].width() * pm[1].info().bytesPerPixel());
|
||||
if (memcmp(pm[0].addr(0, 0), pm[1].addr(0, 0), pm[0].computeByteSize())) {
|
||||
if (memcmp(pm[0].addr(0, 0), pm[1].addr(0, 0), pm[0].computeByteSize()) != 0) {
|
||||
REPORTER_ASSERT(reporter, false);
|
||||
}
|
||||
}
|
||||
@ -125,13 +135,12 @@ DEF_TEST(CanvasState_test_complex_layers, reporter) {
|
||||
bool (*drawFn)(SkCanvasState* state, float l, float t,
|
||||
float r, float b, int32_t s);
|
||||
|
||||
#if defined(SK_TEST_CANVAS_STATE_CROSS_LIBRARY)
|
||||
OpenLibResult openLibResult(reporter);
|
||||
if (openLibResult.handle() != nullptr) {
|
||||
*(void**) (&drawFn) = dlsym(openLibResult.handle(),
|
||||
"complex_layers_draw_from_canvas_state");
|
||||
} else {
|
||||
drawFn = complex_layers_draw_from_canvas_state;
|
||||
}
|
||||
*(void**) (&drawFn) = openLibResult.procAddress("complex_layers_draw_from_canvas_state");
|
||||
#else
|
||||
drawFn = complex_layers_draw_from_canvas_state;
|
||||
#endif
|
||||
|
||||
REPORTER_ASSERT(reporter, drawFn);
|
||||
if (!drawFn) {
|
||||
@ -186,11 +195,9 @@ DEF_TEST(CanvasState_test_complex_layers, reporter) {
|
||||
compare(reporter, images[0].get(), images[1].get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
||||
DEF_TEST(CanvasState_test_complex_clips, reporter) {
|
||||
const int WIDTH = 400;
|
||||
const int HEIGHT = 400;
|
||||
@ -216,7 +223,7 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
|
||||
|
||||
const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
|
||||
SkRegion::kIntersect_Op,
|
||||
SkRegion::kReplace_Op,
|
||||
SkRegion::kDifference_Op,
|
||||
};
|
||||
const SkCanvas::SaveLayerFlags flags[] = {
|
||||
static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
|
||||
@ -229,13 +236,12 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
|
||||
int32_t r, int32_t b, int32_t clipOp,
|
||||
int32_t regionRects, int32_t* rectCoords);
|
||||
|
||||
#if defined(SK_TEST_CANVAS_STATE_CROSS_LIBRARY)
|
||||
OpenLibResult openLibResult(reporter);
|
||||
if (openLibResult.handle() != nullptr) {
|
||||
*(void**) (&drawFn) = dlsym(openLibResult.handle(),
|
||||
"complex_clips_draw_from_canvas_state");
|
||||
} else {
|
||||
drawFn = complex_clips_draw_from_canvas_state;
|
||||
}
|
||||
*(void**) (&drawFn) = openLibResult.procAddress("complex_clips_draw_from_canvas_state");
|
||||
#else
|
||||
drawFn = complex_clips_draw_from_canvas_state;
|
||||
#endif
|
||||
|
||||
REPORTER_ASSERT(reporter, drawFn);
|
||||
if (!drawFn) {
|
||||
@ -253,7 +259,7 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAlpha(128);
|
||||
for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) {
|
||||
for (size_t j = 0; j < SK_ARRAY_COUNT(clipOps); ++j) {
|
||||
SkRect layerBounds = SkRect::Make(layerRect);
|
||||
canvas->saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint, flags[j]));
|
||||
|
||||
@ -293,7 +299,6 @@ DEF_TEST(CanvasState_test_complex_clips, reporter) {
|
||||
|
||||
compare(reporter, images[0].get(), images[1].get());
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user