1/*
2 * Copyright 2014 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
8#include "Test.h"
9#include "RecordTestUtils.h"
10
11#include "SkRecord.h"
12#include "SkRecordOpts.h"
13#include "SkRecorder.h"
14#include "SkRecords.h"
15#include "SkXfermode.h"
16
17static const int W = 1920, H = 1080;
18
19DEF_TEST(RecordOpts_NoopDrawSaveRestore, r) {
20    SkRecord record;
21    SkRecorder recorder(&record, W, H);
22
23    // The save and restore are pointless if there's only draw commands in the middle.
24    recorder.save();
25        recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
26        recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
27        recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
28    recorder.restore();
29
30    record.replace<SkRecords::NoOp>(2);  // NoOps should be allowed.
31
32    SkRecordNoopSaveRestores(&record);
33
34    assert_type<SkRecords::NoOp>(r, record, 0);
35    assert_type<SkRecords::DrawRect>(r, record, 1);
36    assert_type<SkRecords::NoOp>(r, record, 2);
37    assert_type<SkRecords::DrawRect>(r, record, 3);
38    assert_type<SkRecords::NoOp>(r, record, 4);
39}
40
41DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
42    SkRecord record;
43    SkRecorder recorder(&record, W, H);
44
45    recorder.save();
46        recorder.clipRect(SkRect::MakeWH(200, 200));
47    recorder.restore();
48
49    SkRecordNoopSaveRestores(&record);
50    for (unsigned i = 0; i < 3; i++) {
51        assert_type<SkRecords::NoOp>(r, record, i);
52    }
53}
54
55DEF_TEST(RecordOpts_NoopSaveRestores, r) {
56    SkRecord record;
57    SkRecorder recorder(&record, W, H);
58
59    // The second pass will clean up this pair after the first pass noops all the innards.
60    recorder.save();
61        // A simple pointless pair of save/restore.
62        recorder.save();
63        recorder.restore();
64
65        // As long as we don't draw in there, everything is a noop.
66        recorder.save();
67            recorder.clipRect(SkRect::MakeWH(200, 200));
68            recorder.clipRect(SkRect::MakeWH(100, 100));
69        recorder.restore();
70    recorder.restore();
71
72    SkRecordNoopSaveRestores(&record);
73    for (unsigned index = 0; index < 8; index++) {
74        assert_type<SkRecords::NoOp>(r, record, index);
75    }
76}
77
78DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
79    SkRecord record;
80    SkRecorder recorder(&record, W, H);
81
82    // A previous bug NoOp'd away the first 3 commands.
83    recorder.save();
84        recorder.saveLayer(NULL, NULL);
85        recorder.restore();
86    recorder.restore();
87
88    SkRecordNoopSaveRestores(&record);
89    assert_type<SkRecords::Save>     (r, record, 0);
90    assert_type<SkRecords::SaveLayer>(r, record, 1);
91    assert_type<SkRecords::Restore>  (r, record, 2);
92    assert_type<SkRecords::Restore>  (r, record, 3);
93}
94
95static void assert_savelayer_restore(skiatest::Reporter* r,
96                                     SkRecord* record,
97                                     unsigned i,
98                                     bool shouldBeNoOped) {
99    SkRecordNoopSaveLayerDrawRestores(record);
100    if (shouldBeNoOped) {
101        assert_type<SkRecords::NoOp>(r, *record, i);
102        assert_type<SkRecords::NoOp>(r, *record, i+2);
103    } else {
104        assert_type<SkRecords::SaveLayer>(r, *record, i);
105        assert_type<SkRecords::Restore>(r, *record, i+2);
106    }
107}
108
109DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
110    SkRecord record;
111    SkRecorder recorder(&record, W, H);
112
113    SkRect bounds = SkRect::MakeWH(100, 200);
114    SkRect   draw = SkRect::MakeWH(50, 60);
115
116    SkPaint goodLayerPaint, badLayerPaint, worseLayerPaint;
117    goodLayerPaint.setColor(0x03000000);  // Only alpha.
118    badLayerPaint.setColor( 0x03040506);  // Not only alpha.
119    worseLayerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);  // Any effect will do.
120
121    SkPaint goodDrawPaint, badDrawPaint;
122    goodDrawPaint.setColor(0xFF020202);  // Opaque.
123    badDrawPaint.setColor( 0x0F020202);  // Not opaque.
124
125    // No change: optimization can't handle bounds.
126    recorder.saveLayer(&bounds, NULL);
127        recorder.drawRect(draw, goodDrawPaint);
128    recorder.restore();
129    assert_savelayer_restore(r, &record, 0, false);
130
131    // SaveLayer/Restore removed: no bounds + no paint = no point.
132    recorder.saveLayer(NULL, NULL);
133        recorder.drawRect(draw, goodDrawPaint);
134    recorder.restore();
135    assert_savelayer_restore(r, &record, 3, true);
136
137    // TODO(mtklein): test case with null draw paint
138
139    // No change: layer paint isn't alpha-only.
140    recorder.saveLayer(NULL, &badLayerPaint);
141        recorder.drawRect(draw, goodDrawPaint);
142    recorder.restore();
143    assert_savelayer_restore(r, &record, 6, false);
144
145    // No change: layer paint has an effect.
146    recorder.saveLayer(NULL, &worseLayerPaint);
147        recorder.drawRect(draw, goodDrawPaint);
148    recorder.restore();
149    assert_savelayer_restore(r, &record, 9, false);
150
151    // No change: draw paint isn't opaque.
152    recorder.saveLayer(NULL, &goodLayerPaint);
153        recorder.drawRect(draw, badDrawPaint);
154    recorder.restore();
155    assert_savelayer_restore(r, &record, 12, false);
156
157    // SaveLayer/Restore removed: we can fold in the alpha!
158    recorder.saveLayer(NULL, &goodLayerPaint);
159        recorder.drawRect(draw, goodDrawPaint);
160    recorder.restore();
161    assert_savelayer_restore(r, &record, 15, true);
162
163    const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
164    REPORTER_ASSERT(r, drawRect != NULL);
165    REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
166}
167