Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: cc/tiles/gpu_image_decode_controller_unittest.cc

Issue 1832573004: Gpu Image Decode Controller (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
vmpstr 2016/03/25 22:37:30 2016
ericrk 2016/03/28 22:10:53 Done.
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/tiles/gpu_image_decode_controller.h"
6
7 #include "cc/playback/draw_image.h"
8 #include "cc/raster/tile_task_runner.h"
9 #include "cc/test/test_context_provider.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace cc {
13 namespace {
14
15 skia::RefPtr<SkImage> CreateImage(int width, int height) {
16 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
17 SkBitmap bitmap;
18 bitmap.allocPixels(info);
19 return skia::AdoptRef(SkImage::NewFromBitmap(bitmap));
20 }
21
22 SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
23 SkMatrix matrix;
24 matrix.setScale(scale.width(), scale.height());
25
26 if (!is_decomposable) {
27 // Perspective is not decomposable, add it.
28 matrix[SkMatrix::kMPersp0] = 0.1f;
29 }
30
31 return matrix;
32 }
33
34 void ScheduleTask(ImageDecodeTask* task) {
35 task->WillSchedule();
36 task->ScheduleOnOriginThread(nullptr);
37 task->DidSchedule();
38 }
39
40 void RunTask(ImageDecodeTask* task) {
41 task->WillRun();
42 task->RunOnWorkerThread();
43 task->DidRun();
44 }
45
46 void CompleteTask(ImageDecodeTask* task) {
47 task->WillComplete();
48 task->CompleteOnOriginThread(nullptr);
49 task->DidComplete();
50 }
51
52 TEST(GpuImageDecodeControllerTest, GetTaskForImageSameImage) {
53 auto context_provider = TestContextProvider::Create();
54 context_provider->BindToCurrentThread();
55 GpuImageDecodeController controller(context_provider.get());
56 skia::RefPtr<SkImage> image = CreateImage(100, 100);
57 bool is_decomposable = true;
58 SkFilterQuality quality = kHigh_SkFilterQuality;
59 uint64_t prepare_tiles_id = 1;
60
61 DrawImage draw_image(
62 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
63 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
64 scoped_refptr<ImageDecodeTask> task;
65 bool need_unref =
66 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
67 EXPECT_TRUE(need_unref);
68 EXPECT_TRUE(task);
69
70 DrawImage another_draw_image(
71 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
72 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
73 scoped_refptr<ImageDecodeTask> another_task;
74 need_unref = controller.GetTaskForImageAndRef(
75 another_draw_image, prepare_tiles_id, &another_task);
76 EXPECT_TRUE(need_unref);
77 EXPECT_TRUE(task.get() == another_task.get());
78
79 controller.UnrefImage(draw_image);
80 controller.UnrefImage(draw_image);
81 }
82
83 TEST(GpuImageDecodeControllerTest, GetTaskForImageDifferentImage) {
84 auto context_provider = TestContextProvider::Create();
85 context_provider->BindToCurrentThread();
86 GpuImageDecodeController controller(context_provider.get());
87 bool is_decomposable = true;
88 uint64_t prepare_tiles_id = 1;
89 SkFilterQuality quality = kHigh_SkFilterQuality;
90
91 skia::RefPtr<SkImage> first_image = CreateImage(100, 100);
92 DrawImage first_draw_image(
93 first_image.get(),
94 SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
95 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
96 scoped_refptr<ImageDecodeTask> first_task;
97 bool need_unref = controller.GetTaskForImageAndRef(
98 first_draw_image, prepare_tiles_id, &first_task);
99 EXPECT_TRUE(need_unref);
100 EXPECT_TRUE(first_task);
101
102 skia::RefPtr<SkImage> second_image = CreateImage(100, 100);
103 DrawImage second_draw_image(
104 second_image.get(),
105 SkIRect::MakeWH(second_image->width(), second_image->height()), quality,
106 CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable));
107 scoped_refptr<ImageDecodeTask> second_task;
108 need_unref = controller.GetTaskForImageAndRef(second_draw_image,
109 prepare_tiles_id, &second_task);
110 EXPECT_TRUE(need_unref);
111 EXPECT_TRUE(second_task);
112 EXPECT_TRUE(first_task.get() != second_task.get());
113
114 controller.UnrefImage(first_draw_image);
115 controller.UnrefImage(second_draw_image);
116 }
117
118 void ProcessTask(ImageDecodeTask* task) {
vmpstr 2016/03/25 22:37:30 Move this near the top please
ericrk 2016/03/28 22:10:53 Done.
119 ScheduleTask(task);
120 RunTask(task);
121 CompleteTask(task);
122 }
123 TEST(GpuImageDecodeControllerTest, GetTaskForImageAlreadyDecoded) {
124 auto context_provider = TestContextProvider::Create();
125 context_provider->BindToCurrentThread();
126 GpuImageDecodeController controller(context_provider.get());
127 bool is_decomposable = true;
128 uint64_t prepare_tiles_id = 1;
129 SkFilterQuality quality = kHigh_SkFilterQuality;
130
131 skia::RefPtr<SkImage> image = CreateImage(100, 100);
132 DrawImage draw_image(
133 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
134 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
135 scoped_refptr<ImageDecodeTask> task;
136 bool need_unref =
137 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
138 EXPECT_TRUE(need_unref);
139 EXPECT_TRUE(task);
140 EXPECT_TRUE(task->dependency());
141
142 ProcessTask(task->dependency().get());
143 ScheduleTask(task.get());
144 RunTask(task.get());
145
146 scoped_refptr<ImageDecodeTask> another_task;
147 need_unref = controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id,
148 &another_task);
149 EXPECT_TRUE(need_unref);
150 EXPECT_FALSE(another_task);
151
152 CompleteTask(task.get());
153
154 controller.UnrefImage(draw_image);
155 controller.UnrefImage(draw_image);
156 }
157
158 TEST(GpuImageDecodeControllerTest, GetTaskForImageCanceledGetsNewTask) {
159 auto context_provider = TestContextProvider::Create();
160 context_provider->BindToCurrentThread();
161 GpuImageDecodeController controller(context_provider.get());
162 bool is_decomposable = true;
163 uint64_t prepare_tiles_id = 1;
164 SkFilterQuality quality = kHigh_SkFilterQuality;
165
166 skia::RefPtr<SkImage> image = CreateImage(100, 100);
167 DrawImage draw_image(
168 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
169 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
170 scoped_refptr<ImageDecodeTask> task;
171 bool need_unref =
172 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
173 EXPECT_TRUE(need_unref);
174 EXPECT_TRUE(task);
175
176 ProcessTask(task->dependency().get());
177 ScheduleTask(task.get());
178
179 scoped_refptr<ImageDecodeTask> another_task;
180 need_unref = controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id,
181 &another_task);
182 EXPECT_TRUE(need_unref);
183 EXPECT_TRUE(another_task.get() == task.get());
184
185 // Didn't run the task, complete it (it was canceled).
186 CompleteTask(task.get());
187
188 // Fully cancel everything (so the raster would unref things).
189 controller.UnrefImage(draw_image);
190 controller.UnrefImage(draw_image);
191
192 // Here a new task is created.
193 scoped_refptr<ImageDecodeTask> third_task;
194 need_unref = controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id,
195 &third_task);
196 EXPECT_TRUE(need_unref);
197 EXPECT_TRUE(third_task);
198 EXPECT_FALSE(third_task.get() == task.get());
199
200 controller.UnrefImage(draw_image);
201 }
202
203 TEST(GpuImageDecodeControllerTest,
204 GetTaskForImageCanceledWhileReffedGetsNewTask) {
205 auto context_provider = TestContextProvider::Create();
206 context_provider->BindToCurrentThread();
207 GpuImageDecodeController controller(context_provider.get());
208 bool is_decomposable = true;
209 uint64_t prepare_tiles_id = 1;
210 SkFilterQuality quality = kHigh_SkFilterQuality;
211
212 skia::RefPtr<SkImage> image = CreateImage(100, 100);
213 DrawImage draw_image(
214 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
215 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
216 scoped_refptr<ImageDecodeTask> task;
217 bool need_unref =
218 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
219 EXPECT_TRUE(need_unref);
220 EXPECT_TRUE(task);
221
222 ProcessTask(task->dependency().get());
223 ScheduleTask(task.get());
224
225 scoped_refptr<ImageDecodeTask> another_task;
226 need_unref = controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id,
227 &another_task);
228 EXPECT_TRUE(need_unref);
229 EXPECT_TRUE(another_task.get() == task.get());
230
231 // Didn't run the task, complete it (it was canceled).
232 CompleteTask(task.get());
233
234 // Note that here, everything is reffed, but a new task is created. This is
235 // possible with repeated schedule/cancel operations.
236 scoped_refptr<ImageDecodeTask> third_task;
237 need_unref = controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id,
238 &third_task);
239 EXPECT_TRUE(need_unref);
240 EXPECT_TRUE(third_task);
241 EXPECT_FALSE(third_task.get() == task.get());
242
243 // 3 Unrefs!
244 controller.UnrefImage(draw_image);
245 controller.UnrefImage(draw_image);
246 controller.UnrefImage(draw_image);
247 }
248
249 TEST(GpuImageDecodeControllerTest, GetDecodedImageForDraw) {
250 auto context_provider = TestContextProvider::Create();
251 context_provider->BindToCurrentThread();
252 GpuImageDecodeController controller(context_provider.get());
253 bool is_decomposable = true;
254 uint64_t prepare_tiles_id = 1;
255 SkFilterQuality quality = kHigh_SkFilterQuality;
256
257 skia::RefPtr<SkImage> image = CreateImage(100, 100);
258 DrawImage draw_image(
259 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
260 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
261 scoped_refptr<ImageDecodeTask> task;
262 bool need_unref =
263 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
264 EXPECT_TRUE(need_unref);
265 EXPECT_TRUE(task);
266
267 ProcessTask(task->dependency().get());
268 ProcessTask(task.get());
269
270 DecodedDrawImage decoded_draw_image =
271 controller.GetDecodedImageForDraw(draw_image);
272 EXPECT_TRUE(decoded_draw_image.image());
273 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
274 EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
275
276 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
277 controller.UnrefImage(draw_image);
278 }
279
280 TEST(GpuImageDecodeControllerTest, GetLargeDecodedImageForDraw) {
281 auto context_provider = TestContextProvider::Create();
282 context_provider->BindToCurrentThread();
283 GpuImageDecodeController controller(context_provider.get());
284 bool is_decomposable = true;
285 uint64_t prepare_tiles_id = 1;
286 SkFilterQuality quality = kHigh_SkFilterQuality;
287
288 skia::RefPtr<SkImage> image = CreateImage(1, 24000);
289 DrawImage draw_image(
290 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
291 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
292 scoped_refptr<ImageDecodeTask> task;
293 bool need_unref =
294 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
295 EXPECT_TRUE(need_unref);
296 EXPECT_TRUE(task);
297
298 ProcessTask(task->dependency().get());
299 ProcessTask(task.get());
300
301 DecodedDrawImage decoded_draw_image =
302 controller.GetDecodedImageForDraw(draw_image);
303 EXPECT_TRUE(decoded_draw_image.image());
304 EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
305 EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
306
307 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
308 controller.UnrefImage(draw_image);
309 }
310
311 TEST(GpuImageDecodeControllerTest, GetDecodedImageForDrawAtRasterDecode) {
312 auto context_provider = TestContextProvider::Create();
313 context_provider->BindToCurrentThread();
314 GpuImageDecodeController controller(context_provider.get());
315 bool is_decomposable = true;
316 uint64_t prepare_tiles_id = 1;
317 SkFilterQuality quality = kHigh_SkFilterQuality;
318
319 controller.SetCachedItemLimit(0);
320 controller.SetCachedBytesLimit(0);
321
322 skia::RefPtr<SkImage> image = CreateImage(100, 100);
323 DrawImage draw_image(
324 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
325 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
326
327 scoped_refptr<ImageDecodeTask> task;
328 bool need_unref =
329 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
330 EXPECT_FALSE(need_unref);
331 EXPECT_FALSE(task);
332
333 DecodedDrawImage decoded_draw_image =
334 controller.GetDecodedImageForDraw(draw_image);
335 EXPECT_TRUE(decoded_draw_image.image());
336 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
337 EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
338
339 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
340 }
341
342 TEST(GpuImageDecodeControllerTest, AtRasterAddedToCacheIfSpaceAllows) {
343 auto context_provider = TestContextProvider::Create();
344 context_provider->BindToCurrentThread();
345 GpuImageDecodeController controller(context_provider.get());
346 bool is_decomposable = true;
347 uint64_t prepare_tiles_id = 1;
348 SkFilterQuality quality = kHigh_SkFilterQuality;
349
350 controller.SetCachedItemLimit(0);
351 controller.SetCachedBytesLimit(0);
352
353 skia::RefPtr<SkImage> image = CreateImage(100, 100);
354 DrawImage draw_image(
355 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
356 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
357
358 scoped_refptr<ImageDecodeTask> task;
359 bool need_unref =
360 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
361 EXPECT_FALSE(need_unref);
362 EXPECT_FALSE(task);
363
364 controller.SetCachedItemLimit(1000);
365 controller.SetCachedBytesLimit(96 * 1024 * 1024);
366
367 DecodedDrawImage decoded_draw_image =
368 controller.GetDecodedImageForDraw(draw_image);
369 EXPECT_TRUE(decoded_draw_image.image());
370 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
371 EXPECT_FALSE(decoded_draw_image.is_at_raster_decode());
372
373 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
374 }
375
376 TEST(GpuImageDecodeControllerTest, AtRasterUsedDirectlyIfSpaceAllows) {
377 auto context_provider = TestContextProvider::Create();
378 context_provider->BindToCurrentThread();
379 GpuImageDecodeController controller(context_provider.get());
380 bool is_decomposable = true;
381 uint64_t prepare_tiles_id = 1;
382 SkFilterQuality quality = kHigh_SkFilterQuality;
383
384 controller.SetCachedItemLimit(0);
385 controller.SetCachedBytesLimit(0);
386
387 skia::RefPtr<SkImage> image = CreateImage(100, 100);
388 DrawImage draw_image(
389 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
390 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
391
392 scoped_refptr<ImageDecodeTask> task;
393 bool need_unref =
394 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
395 EXPECT_FALSE(need_unref);
396 EXPECT_FALSE(task);
397
398 DecodedDrawImage decoded_draw_image =
399 controller.GetDecodedImageForDraw(draw_image);
400 EXPECT_TRUE(decoded_draw_image.image());
401 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
402 EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
403
404 controller.SetCachedItemLimit(1000);
405 controller.SetCachedBytesLimit(96 * 1024 * 1024);
406
407 scoped_refptr<ImageDecodeTask> another_task;
408 bool another_task_needs_unref =
409 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
410 EXPECT_TRUE(another_task_needs_unref);
411 EXPECT_FALSE(another_task);
412
413 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
414 controller.UnrefImage(draw_image);
415 }
416 TEST(GpuImageDecodeControllerTest,
417 GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
418 auto context_provider = TestContextProvider::Create();
419 context_provider->BindToCurrentThread();
420 GpuImageDecodeController controller(context_provider.get());
421 bool is_decomposable = true;
422 SkFilterQuality quality = kHigh_SkFilterQuality;
423
424 controller.SetCachedItemLimit(0);
425 controller.SetCachedBytesLimit(0);
426
427 skia::RefPtr<SkImage> image = CreateImage(100, 100);
428 DrawImage draw_image(
429 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
430 CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable));
431
432 DecodedDrawImage decoded_draw_image =
433 controller.GetDecodedImageForDraw(draw_image);
434 EXPECT_TRUE(decoded_draw_image.image());
435 EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
436 EXPECT_TRUE(decoded_draw_image.is_at_raster_decode());
437
438 DecodedDrawImage another_decoded_draw_image =
439 controller.GetDecodedImageForDraw(draw_image);
440 EXPECT_EQ(decoded_draw_image.image()->uniqueID(),
441 another_decoded_draw_image.image()->uniqueID());
442
443 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
444 controller.DrawWithImageFinished(draw_image, another_decoded_draw_image);
445 }
446
447 TEST(GpuImageDecodeControllerTest, ZeroSizedImagesAreSkipped) {
448 auto context_provider = TestContextProvider::Create();
449 context_provider->BindToCurrentThread();
450 GpuImageDecodeController controller(context_provider.get());
451 bool is_decomposable = true;
452 uint64_t prepare_tiles_id = 1;
453 SkFilterQuality quality = kHigh_SkFilterQuality;
454
455 skia::RefPtr<SkImage> image = CreateImage(100, 100);
456 DrawImage draw_image(
457 image.get(), SkIRect::MakeWH(image->width(), image->height()), quality,
458 CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable));
459
460 scoped_refptr<ImageDecodeTask> task;
461 bool need_unref =
462 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
463 EXPECT_FALSE(task);
464 EXPECT_FALSE(need_unref);
465
466 DecodedDrawImage decoded_draw_image =
467 controller.GetDecodedImageForDraw(draw_image);
468 EXPECT_FALSE(decoded_draw_image.image());
469
470 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
471 }
472
473 TEST(GpuImageDecodeControllerTest, NonOverlappingSrcRectImagesAreSkipped) {
474 auto context_provider = TestContextProvider::Create();
475 context_provider->BindToCurrentThread();
476 GpuImageDecodeController controller(context_provider.get());
477 bool is_decomposable = true;
478 uint64_t prepare_tiles_id = 1;
479 SkFilterQuality quality = kHigh_SkFilterQuality;
480
481 skia::RefPtr<SkImage> image = CreateImage(100, 100);
482 DrawImage draw_image(
483 image.get(), SkIRect::MakeXYWH(150, 150, image->width(), image->height()),
484 quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable));
485
486 scoped_refptr<ImageDecodeTask> task;
487 bool need_unref =
488 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
489 EXPECT_FALSE(task);
490 EXPECT_FALSE(need_unref);
491
492 DecodedDrawImage decoded_draw_image =
493 controller.GetDecodedImageForDraw(draw_image);
494 EXPECT_FALSE(decoded_draw_image.image());
495
496 controller.DrawWithImageFinished(draw_image, decoded_draw_image);
497 }
498
499 TEST(GpuImageDecodeControllerTest, CancelledTasksDoNotCountAgainstBudget) {
500 auto context_provider = TestContextProvider::Create();
501 context_provider->BindToCurrentThread();
502 GpuImageDecodeController controller(context_provider.get());
503 bool is_decomposable = true;
504 uint64_t prepare_tiles_id = 1;
505 SkFilterQuality quality = kHigh_SkFilterQuality;
506
507 skia::RefPtr<SkImage> image = CreateImage(100, 100);
508 DrawImage draw_image(
509 image.get(), SkIRect::MakeXYWH(0, 0, image->width(), image->height()),
510 quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable));
511
512 scoped_refptr<ImageDecodeTask> task;
513 bool need_unref =
514 controller.GetTaskForImageAndRef(draw_image, prepare_tiles_id, &task);
515 EXPECT_NE(0, controller.GetBytesUsedForTesting());
516 EXPECT_TRUE(task);
517 EXPECT_TRUE(need_unref);
518
519 ScheduleTask(task->dependency().get());
520 CompleteTask(task->dependency().get());
521 ScheduleTask(task.get());
522 CompleteTask(task.get());
523
524 controller.UnrefImage(draw_image);
525 EXPECT_EQ(0, controller.GetBytesUsedForTesting());
526 }
527
528 } // namespace
529 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698