1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "Test.h"
8#include "SkBitmap.h"
9#include "SkCanvas.h"
10#include "SkDraw.h"
11#include "SkDevice.h"
12#include "SkLayerDrawLooper.h"
13#include "SkMatrix.h"
14#include "SkPaint.h"
15#include "SkRect.h"
16#include "SkRefCnt.h"
17#include "SkScalar.h"
18#include "SkXfermode.h"
19
20namespace {
21
22class FakeDevice : public SkDevice {
23public:
24    FakeDevice() : SkDevice(SkBitmap::kARGB_8888_Config, 100, 100) { }
25
26    virtual void drawRect(const SkDraw& draw, const SkRect& r,
27                          const SkPaint& paint) SK_OVERRIDE {
28        fLastMatrix = *draw.fMatrix;
29        SkDevice::drawRect(draw, r, paint);
30    }
31
32    SkMatrix fLastMatrix;
33};
34
35} // namespace
36
37static void test_frontToBack(skiatest::Reporter* reporter) {
38    SkAutoTUnref<SkLayerDrawLooper> looper(SkNEW(SkLayerDrawLooper));
39    SkLayerDrawLooper::LayerInfo layerInfo;
40
41    // Add the front layer, with the defaults.
42    (void)looper->addLayer(layerInfo);
43
44    // Add the back layer, with some layer info set.
45    layerInfo.fOffset.set(SkFloatToScalar(10.0f), SkFloatToScalar(20.0f));
46    layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
47    SkPaint* layerPaint = looper->addLayer(layerInfo);
48    layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
49
50    FakeDevice device;
51    SkCanvas canvas(&device);
52    SkPaint paint;
53    looper->init(&canvas);
54
55    // The back layer should come first.
56    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
57    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
58    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
59    REPORTER_ASSERT(reporter, SkFloatToScalar(10.0f) == device.fLastMatrix.getTranslateX());
60    REPORTER_ASSERT(reporter, SkFloatToScalar(20.0f) == device.fLastMatrix.getTranslateY());
61    paint.reset();
62
63    // Then the front layer.
64    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
65    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
66    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
67    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateX());
68    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateY());
69
70    // Only two layers were added, so that should be the end.
71    REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint));
72}
73
74static void test_backToFront(skiatest::Reporter* reporter) {
75    SkAutoTUnref<SkLayerDrawLooper> looper(SkNEW(SkLayerDrawLooper));
76    SkLayerDrawLooper::LayerInfo layerInfo;
77
78    // Add the back layer, with the defaults.
79    (void)looper->addLayerOnTop(layerInfo);
80
81    // Add the front layer, with some layer info set.
82    layerInfo.fOffset.set(SkFloatToScalar(10.0f), SkFloatToScalar(20.0f));
83    layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
84    SkPaint* layerPaint = looper->addLayerOnTop(layerInfo);
85    layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
86
87    FakeDevice device;
88    SkCanvas canvas(&device);
89    SkPaint paint;
90    looper->init(&canvas);
91
92    // The back layer should come first.
93    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
94    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
95    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
96    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateX());
97    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateY());
98    paint.reset();
99
100    // Then the front layer.
101    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
102    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
103    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
104    REPORTER_ASSERT(reporter, SkFloatToScalar(10.0f) == device.fLastMatrix.getTranslateX());
105    REPORTER_ASSERT(reporter, SkFloatToScalar(20.0f) == device.fLastMatrix.getTranslateY());
106
107    // Only two layers were added, so that should be the end.
108    REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint));
109}
110
111static void test_mixed(skiatest::Reporter* reporter) {
112    SkAutoTUnref<SkLayerDrawLooper> looper(SkNEW(SkLayerDrawLooper));
113    SkLayerDrawLooper::LayerInfo layerInfo;
114
115    // Add the back layer, with the defaults.
116    (void)looper->addLayer(layerInfo);
117
118    // Add the front layer, with some layer info set.
119    layerInfo.fOffset.set(SkFloatToScalar(10.0f), SkFloatToScalar(20.0f));
120    layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
121    SkPaint* layerPaint = looper->addLayerOnTop(layerInfo);
122    layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
123
124    FakeDevice device;
125    SkCanvas canvas(&device);
126    SkPaint paint;
127    looper->init(&canvas);
128
129    // The back layer should come first.
130    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
131    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
132    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
133    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateX());
134    REPORTER_ASSERT(reporter, SkFloatToScalar(0.0f) == device.fLastMatrix.getTranslateY());
135    paint.reset();
136
137    // Then the front layer.
138    REPORTER_ASSERT(reporter, looper->next(&canvas, &paint));
139    REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
140    canvas.drawRect(SkRect::MakeWH(SkFloatToScalar(50.0f), SkFloatToScalar(50.0f)), paint);
141    REPORTER_ASSERT(reporter, SkFloatToScalar(10.0f) == device.fLastMatrix.getTranslateX());
142    REPORTER_ASSERT(reporter, SkFloatToScalar(20.0f) == device.fLastMatrix.getTranslateY());
143
144    // Only two layers were added, so that should be the end.
145    REPORTER_ASSERT(reporter, !looper->next(&canvas, &paint));
146}
147
148static void TestLayerDrawLooper(skiatest::Reporter* reporter) {
149    test_frontToBack(reporter);
150    test_backToFront(reporter);
151    test_mixed(reporter);
152}
153
154#include "TestClassDef.h"
155DEFINE_TESTCLASS("LayerDrawLooper", TestLayerDrawLooperClass, TestLayerDrawLooper)
156