sk_sp<SkLights> fLights;
#endif
- /** After calling saveLayer(), there can be any number of devices that make
- up the top-most drawing area. LayerIter can be used to iterate through
- those devices. Note that the iterator is only valid until the next API
- call made on the canvas. Ownership of all pointers in the iterator stays
- with the canvas, so none of them should be modified or deleted.
- */
- class LayerIter /*: SkNoncopyable*/ {
- public:
- /** Initialize iterator with canvas, and set values for 1st device */
- LayerIter(SkCanvas*, bool skipEmptyClips);
- ~LayerIter();
-
- /** Return true if the iterator is done */
- bool done() const { return fDone; }
- /** Cycle to the next device */
- void next();
-
- // These reflect the current device in the iterator
-
- SkBaseDevice* device() const;
- const SkMatrix& matrix() const;
- const SkRasterClip& clip() const;
- const SkPaint& paint() const;
- int x() const;
- int y() const;
-
- private:
- // used to embed the SkDrawIter object directly in our instance, w/o
- // having to expose that class def to the public. There is an assert
- // in our constructor to ensure that fStorage is large enough
- // (though needs to be a compile-time-assert!). We use intptr_t to work
- // safely with 32 and 64 bit machines (to ensure the storage is enough)
- intptr_t fStorage[32];
- class SkDrawIter* fImpl; // this points at fStorage
- SkPaint fDefaultPaint;
- bool fDone;
- };
-
// default impl defers to getDevice()->newSurface(info)
virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&);
const SkImageFilter* imageFilter = NULL);
private:
+ /** After calling saveLayer(), there can be any number of devices that make
+ up the top-most drawing area. LayerIter can be used to iterate through
+ those devices. Note that the iterator is only valid until the next API
+ call made on the canvas. Ownership of all pointers in the iterator stays
+ with the canvas, so none of them should be modified or deleted.
+ */
+ class LayerIter /*: SkNoncopyable*/ {
+ public:
+ /** Initialize iterator with canvas, and set values for 1st device */
+ LayerIter(SkCanvas*);
+ ~LayerIter();
+
+ /** Return true if the iterator is done */
+ bool done() const { return fDone; }
+ /** Cycle to the next device */
+ void next();
+
+ // These reflect the current device in the iterator
+
+ SkBaseDevice* device() const;
+ const SkMatrix& matrix() const;
+ const SkRasterClip& clip() const;
+ const SkPaint& paint() const;
+ int x() const;
+ int y() const;
+
+ private:
+ // used to embed the SkDrawIter object directly in our instance, w/o
+ // having to expose that class def to the public. There is an assert
+ // in our constructor to ensure that fStorage is large enough
+ // (though needs to be a compile-time-assert!). We use intptr_t to work
+ // safely with 32 and 64 bit machines (to ensure the storage is enough)
+ intptr_t fStorage[32];
+ class SkDrawIter* fImpl; // this points at fStorage
+ SkPaint fDefaultPaint;
+ bool fDone;
+ };
+
static bool BoundsAffectsClip(SaveLayerFlags);
static SaveLayerFlags LegacySaveFlagsToSaveLayerFlags(uint32_t legacySaveFlags);
void checkForDeferredSave();
void internalSetMatrix(const SkMatrix&);
- friend class CanvasTestingAccess; // for testing
friend class SkDrawIter; // needs setupDrawForLayerDevice()
friend class AutoDrawLooper;
friend class SkLua; // needs top layer size and offset
class SkDrawIter : public SkDraw {
public:
- SkDrawIter(SkCanvas* canvas, bool skipEmptyClips = true) {
+ SkDrawIter(SkCanvas* canvas) {
canvas = canvas->canvasForDrawIter();
fCanvas = canvas;
canvas->updateDeviceCMCache();
fClipStack = canvas->fClipStack;
fCurrLayer = canvas->fMCRec->fTopLayer;
- fSkipEmptyClips = skipEmptyClips;
}
bool next() {
// skip over recs with empty clips
- if (fSkipEmptyClips) {
- while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
- fCurrLayer = fCurrLayer->fNext;
- }
+ while (fCurrLayer && fCurrLayer->fClip.isEmpty()) {
+ fCurrLayer = fCurrLayer->fNext;
}
const DeviceCM* rec = fCurrLayer;
SkCanvas* fCanvas;
const DeviceCM* fCurrLayer;
const SkPaint* fPaint; // May be null.
- SkBool8 fSkipEmptyClips;
typedef SkDraw INHERITED;
};
// "rawBounds" is the original bounds of the primitive about to be drawn, unmodified by the
// paint. It's used to determine the size of the offscreen layer for filters.
// If null, the clip will be used instead.
- AutoDrawLooper(SkCanvas* canvas, const SkSurfaceProps& props, const SkPaint& paint,
- bool skipLayerForImageFilter = false,
+ AutoDrawLooper(SkCanvas* canvas, const SkPaint& paint, bool skipLayerForImageFilter = false,
const SkRect* rawBounds = nullptr) : fOrigPaint(paint) {
fCanvas = canvas;
#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
////////// macros to place around the internal draw calls //////////////////
-#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
- this->predrawNotify(); \
- AutoDrawLooper looper(this, fProps, paint, skipLayerForFilter, bounds); \
- while (looper.next(SkDrawFilter::kBitmap_Type)) { \
+#define LOOPER_BEGIN_DRAWBITMAP(paint, skipLayerForFilter, bounds) \
+ this->predrawNotify(); \
+ AutoDrawLooper looper(this, paint, skipLayerForFilter, bounds); \
+ while (looper.next(SkDrawFilter::kBitmap_Type)) { \
SkDrawIter iter(this);
#define LOOPER_BEGIN_DRAWDEVICE(paint, type) \
this->predrawNotify(); \
- AutoDrawLooper looper(this, fProps, paint, true); \
+ AutoDrawLooper looper(this, paint, true); \
while (looper.next(type)) { \
SkDrawIter iter(this);
#define LOOPER_BEGIN(paint, type, bounds) \
this->predrawNotify(); \
- AutoDrawLooper looper(this, fProps, paint, false, bounds); \
+ AutoDrawLooper looper(this, paint, false, bounds); \
while (looper.next(type)) { \
SkDrawIter iter(this);
#define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
this->predrawNotify(bounds, &paint, auxOpaque); \
- AutoDrawLooper looper(this, fProps, paint, false, bounds); \
+ AutoDrawLooper looper(this, paint, false, bounds); \
while (looper.next(type)) { \
SkDrawIter iter(this);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
-SkCanvas::LayerIter::LayerIter(SkCanvas* canvas, bool skipEmptyClips) {
+SkCanvas::LayerIter::LayerIter(SkCanvas* canvas) {
static_assert(sizeof(fStorage) >= sizeof(SkDrawIter), "fStorage_too_small");
SkASSERT(canvas);
- fImpl = new (fStorage) SkDrawIter(canvas, skipEmptyClips);
+ fImpl = new (fStorage) SkDrawIter(canvas);
fDone = !fImpl->next();
}
}
};
-static bool equal_clips(const SkCanvas& a, const SkCanvas& b) {
- if (a.isClipEmpty()) {
- return b.isClipEmpty();
- }
- if (!a.isClipRect()) {
- // this is liberally true, since we don't expose a way to know this exactly (for non-rects)
- return !b.isClipRect();
- }
- SkIRect ar, br;
- a.getClipDeviceBounds(&ar);
- b.getClipDeviceBounds(&br);
- return ar == br;
-}
-
class Canvas2CanvasClipVisitor : public SkCanvas::ClipVisitor {
public:
Canvas2CanvasClipVisitor(SkCanvas* target) : fTarget(target) {}
SkCanvas* fTarget;
};
-static void test_clipVisitor(skiatest::Reporter* reporter, SkCanvas* canvas) {
- SkISize size = canvas->getDeviceSize();
-
- SkBitmap bm;
- bm.setInfo(SkImageInfo::MakeN32Premul(size.width(), size.height()));
- SkCanvas c(bm);
-
- Canvas2CanvasClipVisitor visitor(&c);
- canvas->replayClips(&visitor);
-
- REPORTER_ASSERT(reporter, equal_clips(c, *canvas));
-}
-
static void test_clipstack(skiatest::Reporter* reporter) {
// The clipstack is refcounted, and needs to be able to out-live the canvas if a client has
// ref'd it.
static const char* const kDefaultAssertMessageFormat = "%s";
static const char* const kCanvasDrawAssertMessageFormat =
"Drawing test step %s with SkCanvas";
-static const char* const kNWayDrawAssertMessageFormat =
- "Drawing test step %s with SkNWayCanvas";
-static const char* const kNWayStateAssertMessageFormat =
- "test step %s, SkNWayCanvas state consistency";
-static const char* const kNWayIndirect1StateAssertMessageFormat =
- "test step %s, SkNWayCanvas indirect canvas 1 state consistency";
-static const char* const kNWayIndirect2StateAssertMessageFormat =
- "test step %s, SkNWayCanvas indirect canvas 2 state consistency";
static const char* const kPdfAssertMessageFormat =
"PDF sanity check failed %s";
TEST_STEP(DescribeTopLayer, DescribeTopLayerTestStep);
-class CanvasTestingAccess {
-public:
- static bool SameState(const SkCanvas* canvas1, const SkCanvas* canvas2) {
- SkCanvas::LayerIter layerIter1(const_cast<SkCanvas*>(canvas1), false);
- SkCanvas::LayerIter layerIter2(const_cast<SkCanvas*>(canvas2), false);
- while (!layerIter1.done() && !layerIter2.done()) {
- if (layerIter1.matrix() != layerIter2.matrix()) {
- return false;
- }
- if (layerIter1.clip() != layerIter2.clip()) {
- return false;
- }
- if (layerIter1.paint() != layerIter2.paint()) {
- return false;
- }
- if (layerIter1.x() != layerIter2.x()) {
- return false;
- }
- if (layerIter1.y() != layerIter2.y()) {
- return false;
- }
- layerIter1.next();
- layerIter2.next();
- }
- if (!layerIter1.done()) {
- return false;
- }
- if (!layerIter2.done()) {
- return false;
- }
- return true;
- }
-};
-
-static void AssertCanvasStatesEqual(skiatest::Reporter* reporter, const TestData& d,
- const SkCanvas* canvas1, const SkCanvas* canvas2,
- CanvasTestStep* testStep) {
- REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDeviceSize() ==
- canvas2->getDeviceSize(), testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, canvas1->getSaveCount() ==
- canvas2->getSaveCount(), testStep->assertMessage());
-
- SkRect bounds1, bounds2;
- REPORTER_ASSERT_MESSAGE(reporter,
- canvas1->getClipBounds(&bounds1) == canvas2->getClipBounds(&bounds2),
- testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2,
- testStep->assertMessage());
-
-#ifdef SK_SUPPORT_LEGACY_DRAWFILTER
- REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDrawFilter() ==
- canvas2->getDrawFilter(), testStep->assertMessage());
-#endif
-
- SkIRect deviceBounds1, deviceBounds2;
- REPORTER_ASSERT_MESSAGE(reporter,
- canvas1->getClipDeviceBounds(&deviceBounds1) ==
- canvas2->getClipDeviceBounds(&deviceBounds2),
- testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, deviceBounds1 == deviceBounds2, testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalMatrix() ==
- canvas2->getTotalMatrix(), testStep->assertMessage());
- REPORTER_ASSERT_MESSAGE(reporter, equal_clips(*canvas1, *canvas2), testStep->assertMessage());
-
- REPORTER_ASSERT_MESSAGE(reporter,
- CanvasTestingAccess::SameState(canvas1, canvas2),
- testStep->assertMessage());
-}
-
-static void TestPdfDevice(skiatest::Reporter* reporter,
- const TestData& d,
- CanvasTestStep* testStep) {
+static void TestPdfDevice(skiatest::Reporter* reporter, const TestData& d, CanvasTestStep* step) {
SkDynamicMemoryWStream outStream;
sk_sp<SkDocument> doc(SkDocument::MakePDF(&outStream));
REPORTER_ASSERT(reporter, doc);
SkCanvas* canvas = doc->beginPage(SkIntToScalar(d.fWidth),
SkIntToScalar(d.fHeight));
REPORTER_ASSERT(reporter, canvas);
- testStep->setAssertMessageFormat(kPdfAssertMessageFormat);
- testStep->draw(canvas, d, reporter);
+ step->setAssertMessageFormat(kPdfAssertMessageFormat);
+ step->draw(canvas, d, reporter);
REPORTER_ASSERT(reporter, doc->close());
}
-// unused
-static void TestNWayCanvasStateConsistency(
- skiatest::Reporter* reporter,
- const TestData& d,
- CanvasTestStep* testStep,
- const SkCanvas& referenceCanvas) {
-
- SkBitmap indirectStore1;
- createBitmap(&indirectStore1, 0xFFFFFFFF);
- SkCanvas indirectCanvas1(indirectStore1);
-
- SkBitmap indirectStore2;
- createBitmap(&indirectStore2, 0xFFFFFFFF);
- SkCanvas indirectCanvas2(indirectStore2);
-
- SkISize canvasSize = referenceCanvas.getDeviceSize();
- SkNWayCanvas nWayCanvas(canvasSize.width(), canvasSize.height());
- nWayCanvas.addCanvas(&indirectCanvas1);
- nWayCanvas.addCanvas(&indirectCanvas2);
-
- testStep->setAssertMessageFormat(kNWayDrawAssertMessageFormat);
- testStep->draw(&nWayCanvas, d, reporter);
- // Verify that the SkNWayCanvas reports consitent state
- testStep->setAssertMessageFormat(kNWayStateAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, d, &nWayCanvas, &referenceCanvas, testStep);
- // Verify that the indirect canvases report consitent state
- testStep->setAssertMessageFormat(kNWayIndirect1StateAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, d, &indirectCanvas1, &referenceCanvas, testStep);
- testStep->setAssertMessageFormat(kNWayIndirect2StateAssertMessageFormat);
- AssertCanvasStatesEqual(reporter, d, &indirectCanvas2, &referenceCanvas, testStep);
-}
-
/*
* This sub-test verifies that the test step passes when executed
* with SkCanvas and with classes derrived from SkCanvas. It also verifies
testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat);
testStep->draw(&referenceCanvas, d, reporter);
- // The following test code is disabled because SkNWayCanvas does not
- // report correct clipping and device bounds information
- // Issue: http://code.google.com/p/skia/issues/detail?id=501
-
- if (false) { // avoid bit rot, suppress warning
- TestNWayCanvasStateConsistency(reporter, d, testStep, referenceCanvas);
- }
-
- if (false) { // avoid bit rot, suppress warning
- test_clipVisitor(reporter, &referenceCanvas);
- }
test_clipstack(reporter);
}