ecce60bad6
This flag will be used on Android when built for the framework, as well as when built for the WebView. Setting this flag for Android means our tests can fully test CanvasStateTest. Fix CanvasStateTest. It has bit-rotted since disabling SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG. Splitting off from https://codereview.chromium.org/372003002/ , as it seems self-contained. BUG=b/15693384 R=djsollen@google.com, reed@google.com, mtklein@google.com Author: scroggo@google.com Review URL: https://codereview.chromium.org/375943003
274 lines
9.5 KiB
C++
274 lines
9.5 KiB
C++
/*
|
|
* Copyright 2013 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "SkCanvas.h"
|
|
#include "SkCanvasStateUtils.h"
|
|
#include "SkDrawFilter.h"
|
|
#include "SkError.h"
|
|
#include "SkPaint.h"
|
|
#include "SkRRect.h"
|
|
#include "SkRect.h"
|
|
#include "Test.h"
|
|
|
|
static void test_complex_layers(skiatest::Reporter* reporter) {
|
|
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
|
const int WIDTH = 400;
|
|
const int HEIGHT = 400;
|
|
const int SPACER = 10;
|
|
|
|
SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
|
|
SkIntToScalar(WIDTH-(2*SPACER)),
|
|
SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
|
|
|
|
const SkColorType colorTypes[] = {
|
|
kRGB_565_SkColorType, kN32_SkColorType
|
|
};
|
|
|
|
const int layerAlpha[] = { 255, 255, 0 };
|
|
const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
|
|
SkCanvas::kARGB_ClipLayer_SaveFlag,
|
|
SkCanvas::kARGB_NoClipLayer_SaveFlag
|
|
};
|
|
REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
|
|
const int layerCombinations = sizeof(layerAlpha) / sizeof(int);
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(colorTypes); ++i) {
|
|
SkBitmap bitmaps[2];
|
|
for (int j = 0; j < 2; ++j) {
|
|
bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
|
|
colorTypes[i],
|
|
kPremul_SkAlphaType));
|
|
|
|
SkCanvas canvas(bitmaps[j]);
|
|
|
|
canvas.drawColor(SK_ColorRED);
|
|
|
|
for (int k = 0; k < layerCombinations; ++k) {
|
|
// draw a rect within the layer's bounds and again outside the layer's bounds
|
|
canvas.saveLayerAlpha(&rect, layerAlpha[k], flags[k]);
|
|
|
|
SkCanvasState* state = NULL;
|
|
SkCanvas* tmpCanvas = NULL;
|
|
if (j) {
|
|
state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
|
|
REPORTER_ASSERT(reporter, state);
|
|
tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
|
|
REPORTER_ASSERT(reporter, tmpCanvas);
|
|
} else {
|
|
tmpCanvas = SkRef(&canvas);
|
|
}
|
|
|
|
SkPaint bluePaint;
|
|
bluePaint.setColor(SK_ColorBLUE);
|
|
bluePaint.setStyle(SkPaint::kFill_Style);
|
|
|
|
tmpCanvas->drawRect(rect, bluePaint);
|
|
tmpCanvas->translate(0, rect.height() + SPACER);
|
|
tmpCanvas->drawRect(rect, bluePaint);
|
|
|
|
tmpCanvas->unref();
|
|
SkCanvasStateUtils::ReleaseCanvasState(state);
|
|
|
|
canvas.restore();
|
|
|
|
// translate the canvas for the next iteration
|
|
canvas.translate(0, 2*(rect.height() + SPACER));
|
|
}
|
|
}
|
|
|
|
// now we memcmp the two bitmaps
|
|
REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
|
|
REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
|
|
bitmaps[1].getPixels(),
|
|
bitmaps[0].getSize()));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void test_complex_clips(skiatest::Reporter* reporter) {
|
|
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
|
const int WIDTH = 400;
|
|
const int HEIGHT = 400;
|
|
const int SPACER = 10;
|
|
|
|
SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
|
|
layerRect.inset(2*SPACER, 2*SPACER);
|
|
|
|
SkIRect clipRect = layerRect;
|
|
clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
|
|
clipRect.outset(SPACER, SPACER);
|
|
|
|
SkIRect regionBounds = clipRect;
|
|
regionBounds.offset(clipRect.width() + (2*SPACER), 0);
|
|
|
|
SkIRect regionInterior = regionBounds;
|
|
regionInterior.inset(SPACER*3, SPACER*3);
|
|
|
|
SkRegion clipRegion;
|
|
clipRegion.setRect(regionBounds);
|
|
clipRegion.op(regionInterior, SkRegion::kDifference_Op);
|
|
|
|
|
|
const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
|
|
SkRegion::kIntersect_Op,
|
|
SkRegion::kReplace_Op,
|
|
};
|
|
const SkCanvas::SaveFlags flags[] = { SkCanvas::kARGB_NoClipLayer_SaveFlag,
|
|
SkCanvas::kARGB_ClipLayer_SaveFlag,
|
|
SkCanvas::kARGB_NoClipLayer_SaveFlag,
|
|
};
|
|
REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
|
|
const int layerCombinations = sizeof(flags) / sizeof(SkCanvas::SaveFlags);
|
|
|
|
SkBitmap bitmaps[2];
|
|
for (int i = 0; i < 2; ++i) {
|
|
bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
|
|
|
|
SkCanvas canvas(bitmaps[i]);
|
|
|
|
canvas.drawColor(SK_ColorRED);
|
|
|
|
SkRegion localRegion = clipRegion;
|
|
|
|
for (int j = 0; j < layerCombinations; ++j) {
|
|
SkRect layerBounds = SkRect::Make(layerRect);
|
|
canvas.saveLayerAlpha(&layerBounds, 128, flags[j]);
|
|
|
|
SkCanvasState* state = NULL;
|
|
SkCanvas* tmpCanvas = NULL;
|
|
if (i) {
|
|
state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
|
|
REPORTER_ASSERT(reporter, state);
|
|
tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
|
|
REPORTER_ASSERT(reporter, tmpCanvas);
|
|
} else {
|
|
tmpCanvas = SkRef(&canvas);
|
|
}
|
|
|
|
tmpCanvas->save();
|
|
tmpCanvas->clipRect(SkRect::Make(clipRect), clipOps[j]);
|
|
tmpCanvas->drawColor(SK_ColorBLUE);
|
|
tmpCanvas->restore();
|
|
|
|
tmpCanvas->clipRegion(localRegion, clipOps[j]);
|
|
tmpCanvas->drawColor(SK_ColorBLUE);
|
|
|
|
tmpCanvas->unref();
|
|
SkCanvasStateUtils::ReleaseCanvasState(state);
|
|
|
|
canvas.restore();
|
|
|
|
// translate the canvas and region for the next iteration
|
|
canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
|
|
localRegion.translate(0, 2*(layerRect.height() + SPACER));
|
|
}
|
|
}
|
|
|
|
// now we memcmp the two bitmaps
|
|
REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize());
|
|
REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
|
|
bitmaps[1].getPixels(),
|
|
bitmaps[0].getSize()));
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class TestDrawFilter : public SkDrawFilter {
|
|
public:
|
|
virtual bool filter(SkPaint*, Type) SK_OVERRIDE { return true; }
|
|
};
|
|
|
|
static void test_draw_filters(skiatest::Reporter* reporter) {
|
|
TestDrawFilter drawFilter;
|
|
SkBitmap bitmap;
|
|
bitmap.allocN32Pixels(10, 10);
|
|
SkCanvas canvas(bitmap);
|
|
|
|
canvas.setDrawFilter(&drawFilter);
|
|
|
|
SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
|
|
REPORTER_ASSERT(reporter, state);
|
|
SkCanvas* tmpCanvas = SkCanvasStateUtils::CreateFromCanvasState(state);
|
|
REPORTER_ASSERT(reporter, tmpCanvas);
|
|
|
|
REPORTER_ASSERT(reporter, NULL != canvas.getDrawFilter());
|
|
REPORTER_ASSERT(reporter, NULL == tmpCanvas->getDrawFilter());
|
|
|
|
tmpCanvas->unref();
|
|
SkCanvasStateUtils::ReleaseCanvasState(state);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// we need this function to prevent SkError from printing to stdout
|
|
static void error_callback(SkError code, void* ctx) {}
|
|
|
|
static void test_soft_clips(skiatest::Reporter* reporter) {
|
|
SkBitmap bitmap;
|
|
bitmap.allocN32Pixels(10, 10);
|
|
SkCanvas canvas(bitmap);
|
|
|
|
SkRRect roundRect;
|
|
roundRect.setOval(SkRect::MakeWH(5, 5));
|
|
|
|
canvas.clipRRect(roundRect, SkRegion::kIntersect_Op, true);
|
|
|
|
SkSetErrorCallback(error_callback, NULL);
|
|
|
|
SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
|
|
REPORTER_ASSERT(reporter, !state);
|
|
|
|
REPORTER_ASSERT(reporter, kInvalidOperation_SkError == SkGetLastError());
|
|
SkClearLastError();
|
|
}
|
|
|
|
static void test_saveLayer_clip(skiatest::Reporter* reporter) {
|
|
#ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
|
|
const int WIDTH = 100;
|
|
const int HEIGHT = 100;
|
|
const int LAYER_WIDTH = 50;
|
|
const int LAYER_HEIGHT = 50;
|
|
|
|
SkBitmap bitmap;
|
|
bitmap.allocN32Pixels(WIDTH, HEIGHT);
|
|
SkCanvas canvas(bitmap);
|
|
|
|
SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
|
|
canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
|
|
|
|
// Check that saveLayer without the kClipToLayer_SaveFlag leaves the
|
|
// clip stack unchanged.
|
|
canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag);
|
|
SkRect clipStackBounds;
|
|
SkClipStack::BoundsType boundsType;
|
|
canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
|
|
REPORTER_ASSERT(reporter, clipStackBounds.width() == WIDTH);
|
|
REPORTER_ASSERT(reporter, clipStackBounds.height() == HEIGHT);
|
|
canvas.restore();
|
|
|
|
// Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
|
|
// stack to the layer bounds.
|
|
canvas.saveLayer(&bounds, NULL, SkCanvas::kARGB_ClipLayer_SaveFlag);
|
|
canvas.getClipStack()->getBounds(&clipStackBounds, &boundsType);
|
|
REPORTER_ASSERT(reporter, clipStackBounds.width() == LAYER_WIDTH);
|
|
REPORTER_ASSERT(reporter, clipStackBounds.height() == LAYER_HEIGHT);
|
|
|
|
canvas.restore();
|
|
#endif
|
|
}
|
|
|
|
DEF_TEST(CanvasState, reporter) {
|
|
test_complex_layers(reporter);
|
|
test_complex_clips(reporter);
|
|
test_draw_filters(reporter);
|
|
test_soft_clips(reporter);
|
|
test_saveLayer_clip(reporter);
|
|
}
|