OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/paint/paint_op_buffer.h" | |
6 #include "cc/test/test_skcanvas.h" | |
7 #include "testing/gtest/include/gtest/gtest.h" | |
8 | |
9 namespace cc { | |
10 | |
11 TEST(PaintOpBufferTest, Empty) { | |
12 PaintOpBuffer buffer; | |
13 EXPECT_EQ(buffer.approximateOpCount(), 0); | |
14 EXPECT_EQ(buffer.approximateBytesUsed(), sizeof(PaintOpBuffer)); | |
15 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
16 | |
17 buffer.Reset(); | |
18 EXPECT_EQ(buffer.approximateOpCount(), 0); | |
19 EXPECT_EQ(buffer.approximateBytesUsed(), sizeof(PaintOpBuffer)); | |
20 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
21 } | |
22 | |
23 TEST(PaintOpBufferTest, SimpleAppend) { | |
24 SkRect rect = SkRect::MakeXYWH(2, 3, 4, 5); | |
25 PaintFlags flags; | |
26 flags.setColor(SK_ColorMAGENTA); | |
27 flags.setAlpha(100); | |
28 SkColor draw_color = SK_ColorRED; | |
29 SkBlendMode blend = SkBlendMode::kSrc; | |
30 | |
31 PaintOpBuffer buffer; | |
32 buffer.push<SaveLayerOp>(&rect, &flags); | |
33 buffer.push<SaveOp>(); | |
34 buffer.push<DrawColorOp>(draw_color, blend); | |
35 buffer.push<RestoreOp>(); | |
36 | |
37 EXPECT_EQ(buffer.approximateOpCount(), 4); | |
38 | |
39 PaintOpBuffer::Iterator iter(&buffer); | |
40 ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer); | |
41 SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter); | |
42 EXPECT_EQ(save_op->bounds, rect); | |
43 EXPECT_TRUE(save_op->flags == flags); | |
44 ++iter; | |
45 | |
46 ASSERT_EQ(iter->GetType(), PaintOpType::Save); | |
47 ++iter; | |
48 | |
49 ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor); | |
50 DrawColorOp* op = static_cast<DrawColorOp*>(*iter); | |
51 EXPECT_EQ(op->color, draw_color); | |
52 EXPECT_EQ(op->mode, blend); | |
53 ++iter; | |
54 | |
55 ASSERT_EQ(iter->GetType(), PaintOpType::Restore); | |
56 ++iter; | |
57 | |
58 EXPECT_FALSE(iter); | |
59 } | |
60 | |
61 // PaintOpBuffer has a special case for first ops stored locally, so | |
62 // make sure that appending different kind of ops as a first op works | |
63 // properly, as well as resetting and reusing the first local op. | |
64 TEST(PaintOpBufferTest, FirstOpWithAndWithoutData) { | |
65 PaintOpBuffer buffer; | |
66 char text[] = "asdf"; | |
vmpstr
2017/04/13 20:25:53
xD nice sample text!
| |
67 | |
68 // Use a color filter and its ref count to verify that the destructor | |
69 // is called on ops after reset. | |
70 PaintFlags flags; | |
71 sk_sp<SkColorFilter> filter = | |
72 SkColorFilter::MakeModeFilter(SK_ColorMAGENTA, SkBlendMode::kSrcOver); | |
73 flags.setColorFilter(filter); | |
74 EXPECT_EQ(filter->getRefCnt(), 2); | |
75 | |
76 buffer.push_with_data<DrawTextOp>(text, arraysize(text), 0.f, 0.f, flags); | |
77 EXPECT_EQ(filter->getRefCnt(), 3); | |
78 | |
79 // Verify that when the first op has data, which may not fit in the | |
80 // PaintRecord internal buffer, that it adds a noop as the first op | |
81 // and then appends the "op with data" into the heap buffer. | |
82 ASSERT_EQ(buffer.approximateOpCount(), 2); | |
83 EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::Noop); | |
84 | |
85 // Verify iteration behavior and brief smoke test of op state. | |
86 { | |
87 PaintOpBuffer::Iterator iter(&buffer); | |
88 PaintOp* noop = *iter; | |
89 EXPECT_EQ(buffer.GetFirstOp(), noop); | |
90 ++iter; | |
91 | |
92 PaintOp* op = *iter; | |
93 ASSERT_EQ(op->GetType(), PaintOpType::DrawText); | |
94 DrawTextOp* draw_text_op = static_cast<DrawTextOp*>(op); | |
95 EXPECT_EQ(draw_text_op->bytes, arraysize(text)); | |
96 | |
97 void* data = paint_op_data(draw_text_op); | |
98 EXPECT_EQ(memcmp(data, text, arraysize(text)), 0); | |
99 | |
100 ++iter; | |
101 EXPECT_FALSE(iter); | |
102 } | |
103 | |
104 // Reset, verify state, and append an op that will fit in the first slot. | |
105 buffer.Reset(); | |
106 EXPECT_EQ(filter->getRefCnt(), 2); | |
107 | |
108 ASSERT_EQ(buffer.approximateOpCount(), 0); | |
109 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
110 | |
111 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
112 buffer.push<DrawRectOp>(rect, flags); | |
113 EXPECT_EQ(filter->getRefCnt(), 3); | |
114 | |
115 ASSERT_EQ(buffer.approximateOpCount(), 1); | |
116 EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::DrawRect); | |
117 | |
118 PaintOpBuffer::Iterator iter(&buffer); | |
119 ASSERT_EQ(iter->GetType(), PaintOpType::DrawRect); | |
120 DrawRectOp* draw_rect_op = static_cast<DrawRectOp*>(*iter); | |
121 EXPECT_EQ(draw_rect_op->rect, rect); | |
122 | |
123 ++iter; | |
124 EXPECT_FALSE(iter); | |
125 | |
126 buffer.Reset(); | |
127 ASSERT_EQ(buffer.approximateOpCount(), 0); | |
128 EXPECT_EQ(filter->getRefCnt(), 2); | |
129 } | |
130 | |
131 TEST(PaintOpBufferTest, Peek) { | |
132 PaintOpBuffer buffer; | |
133 | |
134 uint8_t alpha = 100; | |
135 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
136 PaintFlags draw_flags; | |
137 buffer.push<DrawRectOp>(SkRect::MakeXYWH(1, 2, 3, 4), draw_flags); | |
138 buffer.push<RestoreOp>(); | |
139 buffer.push<SaveOp>(); | |
140 buffer.push<NoopOp>(); | |
141 buffer.push<RestoreOp>(); | |
142 | |
143 PaintOpBuffer::Iterator init_iter(&buffer); | |
144 PaintOp* peek[2] = {*init_iter, init_iter.peek1()}; | |
145 | |
146 // Expect that while iterating that next = current.peek1() and that | |
147 // next.peek1() == current.peek2(). | |
148 for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) { | |
149 EXPECT_EQ(*iter, peek[0]) << iter.op_idx(); | |
150 EXPECT_EQ(iter.peek1(), peek[1]) << iter.op_idx(); | |
151 | |
152 peek[0] = iter.peek1(); | |
153 peek[1] = iter.peek2(); | |
154 } | |
155 } | |
156 | |
157 TEST(PaintOpBufferTest, PeekEmpty) { | |
158 PaintOpBuffer empty; | |
159 PaintOpBuffer::Iterator empty_iter(&empty); | |
160 EXPECT_EQ(nullptr, empty_iter.peek1()); | |
161 EXPECT_EQ(nullptr, empty_iter.peek2()); | |
162 } | |
163 | |
164 // Verify that a SaveLayerAlpha / Draw / Restore can be optimized to just | |
165 // a draw with opacity. | |
166 TEST(PaintOpBufferTest, SaveDrawRestore) { | |
167 PaintOpBuffer buffer; | |
168 | |
169 uint8_t alpha = 100; | |
170 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
171 | |
172 PaintFlags draw_flags; | |
173 draw_flags.setColor(SK_ColorMAGENTA); | |
174 draw_flags.setAlpha(50); | |
175 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha()); | |
176 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
177 buffer.push<DrawRectOp>(rect, draw_flags); | |
178 buffer.push<RestoreOp>(); | |
179 | |
180 SaveCountingCanvas canvas; | |
181 buffer.playback(&canvas); | |
182 | |
183 EXPECT_EQ(0, canvas.save_count_); | |
184 EXPECT_EQ(0, canvas.restore_count_); | |
185 EXPECT_EQ(rect, canvas.draw_rect_); | |
186 | |
187 // Expect the alpha from the draw and the save layer to be folded together. | |
188 // Since alpha is stored in a uint8_t and gets rounded, so use tolerance. | |
189 float expected_alpha = alpha * 50 / 255.f; | |
190 EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f); | |
191 } | |
192 | |
193 // The same as SaveDrawRestore, but test that the optimization doesn't apply | |
194 // when the drawing op's flags are not compatible with being folded into the | |
195 // save layer with opacity. | |
196 TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) { | |
197 PaintOpBuffer buffer; | |
198 | |
199 uint8_t alpha = 100; | |
200 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
201 | |
202 PaintFlags draw_flags; | |
203 draw_flags.setColor(SK_ColorMAGENTA); | |
204 draw_flags.setAlpha(50); | |
205 draw_flags.setBlendMode(SkBlendMode::kSrc); | |
206 EXPECT_FALSE(draw_flags.SupportsFoldingAlpha()); | |
207 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
208 buffer.push<DrawRectOp>(rect, draw_flags); | |
209 buffer.push<RestoreOp>(); | |
210 | |
211 SaveCountingCanvas canvas; | |
212 buffer.playback(&canvas); | |
213 | |
214 EXPECT_EQ(1, canvas.save_count_); | |
215 EXPECT_EQ(1, canvas.restore_count_); | |
216 EXPECT_EQ(rect, canvas.draw_rect_); | |
217 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha()); | |
218 } | |
219 | |
220 // The same as SaveDrawRestore, but test that the optimization doesn't apply | |
221 // when there are more than one ops between the save and restore. | |
222 TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) { | |
223 PaintOpBuffer buffer; | |
224 | |
225 uint8_t alpha = 100; | |
226 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
227 | |
228 PaintFlags draw_flags; | |
229 draw_flags.setColor(SK_ColorMAGENTA); | |
230 draw_flags.setAlpha(50); | |
231 draw_flags.setBlendMode(SkBlendMode::kSrcOver); | |
232 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha()); | |
233 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
234 buffer.push<DrawRectOp>(rect, draw_flags); | |
235 buffer.push<NoopOp>(); | |
236 buffer.push<RestoreOp>(); | |
237 | |
238 SaveCountingCanvas canvas; | |
239 buffer.playback(&canvas); | |
240 | |
241 EXPECT_EQ(1, canvas.save_count_); | |
242 EXPECT_EQ(1, canvas.restore_count_); | |
243 EXPECT_EQ(rect, canvas.draw_rect_); | |
244 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha()); | |
245 } | |
246 | |
247 } // namespace cc | |
OLD | NEW |