1 // Copyright (c) 2012 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.
5 #include "ppapi/tests/test_graphics_2d.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/ppb_graphics_2d.h"
14 #include "ppapi/cpp/completion_callback.h"
15 #include "ppapi/cpp/graphics_2d.h"
16 #include "ppapi/cpp/graphics_3d.h"
17 #include "ppapi/cpp/image_data.h"
18 #include "ppapi/cpp/instance.h"
19 #include "ppapi/cpp/module.h"
20 #include "ppapi/cpp/rect.h"
21 #include "ppapi/tests/test_utils.h"
22 #include "ppapi/tests/testing_instance.h"
24 REGISTER_TEST_CASE(Graphics2D
);
28 bool CanFlushContext(pp::Instance
* instance
, pp::Graphics2D
* context
) {
29 TestCompletionCallback
callback(instance
->pp_instance());
30 callback
.WaitForResult(context
->Flush(callback
.GetCallback()));
31 return (callback
.result() == PP_OK
);
34 bool CanFlushContextC(pp::Instance
* instance
, PP_Resource graphics_2d
,
35 const PPB_Graphics2D_1_1
* graphics_2d_if
) {
36 TestCompletionCallback
callback(instance
->pp_instance());
37 callback
.WaitForResult(graphics_2d_if
->Flush(
38 graphics_2d
, callback
.GetCallback().pp_completion_callback()));
39 return (callback
.result() == PP_OK
);
44 TestGraphics2D::TestGraphics2D(TestingInstance
* instance
)
46 is_view_changed_(false),
47 post_quit_on_view_changed_(false) {
50 bool TestGraphics2D::Init() {
51 graphics_2d_interface_
= static_cast<const PPB_Graphics2D
*>(
52 pp::Module::Get()->GetBrowserInterface(PPB_GRAPHICS_2D_INTERFACE_1_1
));
53 image_data_interface_
= static_cast<const PPB_ImageData
*>(
54 pp::Module::Get()->GetBrowserInterface(PPB_IMAGEDATA_INTERFACE_1_0
));
55 return graphics_2d_interface_
&& image_data_interface_
&&
56 CheckTestingInterface();
59 void TestGraphics2D::RunTests(const std::string
& filter
) {
60 RUN_TEST(InvalidResource
, filter
);
61 RUN_TEST(InvalidSize
, filter
);
62 RUN_TEST(Humongous
, filter
);
63 RUN_TEST(InitToZero
, filter
);
64 RUN_TEST(Describe
, filter
);
65 RUN_TEST(Scale
, filter
);
66 RUN_TEST_FORCEASYNC_AND_NOT(Paint
, filter
);
67 RUN_TEST_FORCEASYNC_AND_NOT(Scroll
, filter
);
68 RUN_TEST_FORCEASYNC_AND_NOT(Replace
, filter
);
69 RUN_TEST_FORCEASYNC_AND_NOT(Flush
, filter
);
70 RUN_TEST_FORCEASYNC_AND_NOT(FlushOffscreenUpdate
, filter
);
71 RUN_TEST(Dev
, filter
);
72 RUN_TEST(ReplaceContentsCaching
, filter
);
73 RUN_TEST(BindNull
, filter
);
76 void TestGraphics2D::QuitMessageLoop() {
77 testing_interface_
->QuitMessageLoop(instance_
->pp_instance());
80 bool TestGraphics2D::ReadImageData(const pp::Graphics2D
& dc
,
82 const pp::Point
& top_left
) const {
83 return PP_ToBool(testing_interface_
->ReadImageData(
86 &top_left
.pp_point()));
89 bool TestGraphics2D::IsDCUniformColor(const pp::Graphics2D
& dc
,
90 uint32_t color
) const {
91 pp::ImageData
readback(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
93 if (readback
.is_null())
95 if (!ReadImageData(dc
, &readback
, pp::Point(0, 0)))
97 return IsSquareInImage(readback
, 0, pp::Rect(dc
.size()), color
);
100 std::string
TestGraphics2D::FlushAndWaitForDone(pp::Graphics2D
* context
) {
101 TestCompletionCallback
callback(instance_
->pp_instance(), callback_type());
102 callback
.WaitForResult(context
->Flush(callback
.GetCallback()));
103 CHECK_CALLBACK_BEHAVIOR(callback
);
104 ASSERT_EQ(PP_OK
, callback
.result());
108 void TestGraphics2D::FillRectInImage(pp::ImageData
* image
,
109 const pp::Rect
& rect
,
110 uint32_t color
) const {
111 for (int y
= rect
.y(); y
< rect
.bottom(); y
++) {
112 uint32_t* row
= image
->GetAddr32(pp::Point(rect
.x(), y
));
113 for (int pixel
= 0; pixel
< rect
.width(); pixel
++)
118 void TestGraphics2D::FillImageWithGradient(pp::ImageData
* image
) const {
119 for (int y
= 0; y
< image
->size().height(); y
++) {
120 uint32_t red
= ((y
* 256) / image
->size().height()) & 0xFF;
121 for (int x
= 0; x
< image
->size().width(); x
++) {
122 uint32_t green
= ((x
* 256) / image
->size().width()) & 0xFF;
123 uint32_t blue
= ((red
+ green
) / 2) & 0xFF;
124 uint32_t* pixel
= image
->GetAddr32(pp::Point(x
, y
));
125 *pixel
= (blue
<< 24) | (green
<< 16) | (red
<< 8);
130 bool TestGraphics2D::CompareImages(const pp::ImageData
& image1
,
131 const pp::ImageData
& image2
) {
132 return CompareImageRect(
133 image1
, pp::Rect(0, 0, image1
.size().width(), image1
.size().height()),
134 image2
, pp::Rect(0, 0, image2
.size().width(), image2
.size().height()));
137 bool TestGraphics2D::CompareImageRect(const pp::ImageData
& image1
,
139 const pp::ImageData
& image2
,
140 const pp::Rect
& rc2
) const {
141 if (rc1
.width() != rc2
.width() || rc1
.height() != rc2
.height())
144 for (int y
= 0; y
< rc1
.height(); y
++) {
145 for (int x
= 0; x
< rc1
.width(); x
++) {
146 if (*(image1
.GetAddr32(pp::Point(rc1
.x() + x
, rc1
.y() + y
))) !=
147 *(image2
.GetAddr32(pp::Point(rc2
.x() + x
, rc2
.y() + y
))))
154 bool TestGraphics2D::IsSquareInImage(const pp::ImageData
& image_data
,
155 uint32_t background_color
,
156 const pp::Rect
& square
,
157 uint32_t square_color
) const {
158 for (int y
= 0; y
< image_data
.size().height(); y
++) {
159 for (int x
= 0; x
< image_data
.size().width(); x
++) {
160 uint32_t pixel
= *image_data
.GetAddr32(pp::Point(x
, y
));
161 uint32_t desired_color
;
162 if (square
.Contains(x
, y
))
163 desired_color
= square_color
;
165 desired_color
= background_color
;
166 if (pixel
!= desired_color
)
173 bool TestGraphics2D::IsSquareInDC(const pp::Graphics2D
& dc
,
174 uint32_t background_color
,
175 const pp::Rect
& square
,
176 uint32_t square_color
) const {
177 pp::ImageData
readback(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
179 if (readback
.is_null())
181 if (!ReadImageData(dc
, &readback
, pp::Point(0, 0)))
183 return IsSquareInImage(readback
, background_color
, square
, square_color
);
187 PP_Resource
TestGraphics2D::ReplaceContentsAndReturnID(
189 const pp::Size
& size
) {
190 pp::ImageData
image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
, size
, true);
192 PP_Resource id
= image
.pp_resource();
194 dc
->ReplaceContents(&image
);
195 std::string result
= FlushAndWaitForDone(dc
);
202 // Test all the functions with an invalid handle. Most of these just check for
203 // a crash since the browser don't return a value.
204 std::string
TestGraphics2D::TestInvalidResource() {
205 pp::Graphics2D null_context
;
206 pp::ImageData
image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
207 pp::Size(16, 16), true);
212 graphics_2d_interface_
->Describe(image
.pp_resource(), &size
, &opaque
);
213 graphics_2d_interface_
->Describe(null_context
.pp_resource(),
220 graphics_2d_interface_
->PaintImageData(image
.pp_resource(),
223 graphics_2d_interface_
->PaintImageData(null_context
.pp_resource(),
231 graphics_2d_interface_
->Scroll(image
.pp_resource(), NULL
, &zero_ten
);
232 graphics_2d_interface_
->Scroll(null_context
.pp_resource(),
236 graphics_2d_interface_
->ReplaceContents(image
.pp_resource(),
237 image
.pp_resource());
238 graphics_2d_interface_
->ReplaceContents(null_context
.pp_resource(),
239 image
.pp_resource());
242 TestCompletionCallback
cb(instance_
->pp_instance(), PP_OPTIONAL
);
244 graphics_2d_interface_
->Flush(image
.pp_resource(),
245 cb
.GetCallback().pp_completion_callback()));
246 ASSERT_EQ(PP_ERROR_BADRESOURCE
, cb
.result());
248 graphics_2d_interface_
->Flush(null_context
.pp_resource(),
249 cb
.GetCallback().pp_completion_callback()));
250 ASSERT_EQ(PP_ERROR_BADRESOURCE
, cb
.result());
253 ASSERT_FALSE(testing_interface_
->ReadImageData(image
.pp_resource(),
256 ASSERT_FALSE(testing_interface_
->ReadImageData(null_context
.pp_resource(),
263 std::string
TestGraphics2D::TestInvalidSize() {
264 pp::Graphics2D
a(instance_
, pp::Size(16, 0), false);
265 ASSERT_FALSE(CanFlushContext(instance_
, &a
));
267 pp::Graphics2D
b(instance_
, pp::Size(0, 16), false);
268 ASSERT_FALSE(CanFlushContext(instance_
, &b
));
270 // Need to use the C API since pp::Size prevents negative sizes.
274 PP_Resource graphics
= graphics_2d_interface_
->Create(
275 instance_
->pp_instance(), &size
, PP_FALSE
);
276 ASSERT_FALSE(CanFlushContextC(instance_
, graphics
, graphics_2d_interface_
));
277 pp::Module::Get()->core()->ReleaseResource(graphics
);
281 graphics
= graphics_2d_interface_
->Create(
282 instance_
->pp_instance(), &size
, PP_FALSE
);
283 ASSERT_FALSE(CanFlushContextC(instance_
, graphics
, graphics_2d_interface_
));
284 pp::Module::Get()->core()->ReleaseResource(graphics
);
286 // Overflow to negative size
287 size
.width
= std::numeric_limits
<int32_t>::max();
288 size
.height
= std::numeric_limits
<int32_t>::max();
289 graphics
= graphics_2d_interface_
->Create(
290 instance_
->pp_instance(), &size
, PP_FALSE
);
291 ASSERT_FALSE(CanFlushContextC(instance_
, graphics
, graphics_2d_interface_
));
292 pp::Module::Get()->core()->ReleaseResource(graphics
);
297 std::string
TestGraphics2D::TestHumongous() {
298 pp::Graphics2D
a(instance_
, pp::Size(100000, 100000), false);
299 ASSERT_FALSE(CanFlushContext(instance_
, &a
));
303 std::string
TestGraphics2D::TestInitToZero() {
304 const int w
= 15, h
= 17;
305 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
306 ASSERT_FALSE(dc
.is_null());
308 // Make an image with nonzero data in it (so we can test that zeros were
309 // actually read versus ReadImageData being a NOP).
310 pp::ImageData
image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
311 pp::Size(w
, h
), true);
312 ASSERT_FALSE(image
.is_null());
313 ASSERT_FALSE(image
.size().IsEmpty());
314 memset(image
.data(), 0xFF, image
.stride() * image
.size().height() * 4);
316 // Read out the initial data from the device & check.
317 ASSERT_TRUE(ReadImageData(dc
, &image
, pp::Point(0, 0)));
318 ASSERT_TRUE(IsSquareInImage(image
, 0, pp::Rect(0, 0, w
, h
), 0));
323 std::string
TestGraphics2D::TestDescribe() {
324 const int w
= 15, h
= 17;
325 const bool always_opaque
= (::rand() % 2 == 1);
326 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), always_opaque
);
327 ASSERT_FALSE(dc
.is_null());
332 PP_Bool is_always_opaque
= PP_FALSE
;
333 ASSERT_TRUE(graphics_2d_interface_
->Describe(dc
.pp_resource(), &size
,
335 ASSERT_EQ(w
, size
.width
);
336 ASSERT_EQ(h
, size
.height
);
337 ASSERT_EQ(PP_FromBool(always_opaque
), is_always_opaque
);
342 std::string
TestGraphics2D::TestScale() {
343 // Tests GetScale/SetScale
344 const int w
= 20, h
= 16;
345 const float scale
= 1.0f
/2.0f
;
346 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
347 ASSERT_FALSE(dc
.is_null());
348 ASSERT_EQ(1.0, dc
.GetScale());
349 ASSERT_TRUE(dc
.SetScale(scale
));
350 ASSERT_EQ(scale
, dc
.GetScale());
351 // Try setting a few invalid scale factors. Ensure that we catch these errors
352 // and don't change the actual scale
353 ASSERT_FALSE(dc
.SetScale(-1.0f
));
354 ASSERT_FALSE(dc
.SetScale(0.0f
));
355 ASSERT_EQ(scale
, dc
.GetScale());
357 // Verify that the context has the specified number of pixels, despite the
358 // non-identity scale
362 PP_Bool is_always_opaque
= PP_FALSE
;
363 ASSERT_TRUE(graphics_2d_interface_
->Describe(dc
.pp_resource(), &size
,
365 ASSERT_EQ(w
, size
.width
);
366 ASSERT_EQ(h
, size
.height
);
367 ASSERT_EQ(PP_FALSE
, is_always_opaque
);
372 std::string
TestGraphics2D::TestPaint() {
373 const int w
= 15, h
= 17;
374 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
375 ASSERT_FALSE(dc
.is_null());
377 // Make sure the device background is 0.
378 ASSERT_TRUE(IsDCUniformColor(dc
, 0));
380 // Fill the backing store with white.
381 const uint32_t background_color
= 0xFFFFFFFF;
382 pp::ImageData
background(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
383 pp::Size(w
, h
), false);
384 FillRectInImage(&background
, pp::Rect(0, 0, w
, h
), background_color
);
385 dc
.PaintImageData(background
, pp::Point(0, 0));
386 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
388 // Make an image to paint with that's opaque white and enqueue a paint.
389 const int fill_w
= 2, fill_h
= 3;
390 pp::ImageData
fill(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
391 pp::Size(fill_w
, fill_h
), true);
392 ASSERT_FALSE(fill
.is_null());
393 FillRectInImage(&fill
, pp::Rect(fill
.size()), background_color
);
394 const int paint_x
= 4, paint_y
= 5;
395 dc
.PaintImageData(fill
, pp::Point(paint_x
, paint_y
));
397 // Validate that nothing has been actually painted.
398 ASSERT_TRUE(IsDCUniformColor(dc
, background_color
));
400 // The paint hasn't been flushed so we can still change the bitmap. Fill with
401 // 50% blue. This will also verify that the backing store is replaced
402 // with the contents rather than blended.
403 const uint32_t fill_color
= 0x80000080;
404 FillRectInImage(&fill
, pp::Rect(fill
.size()), fill_color
);
405 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
407 ASSERT_TRUE(IsSquareInDC(dc
, background_color
,
408 pp::Rect(paint_x
, paint_y
, fill_w
, fill_h
),
411 // Reset the DC to blank white & paint our image slightly off the buffer.
412 // This should succeed. We also try painting the same thing where the
413 // dirty rect falls outeside of the device, which should fail.
414 dc
.PaintImageData(background
, pp::Point(0, 0));
415 const int second_paint_x
= -1, second_paint_y
= -2;
416 dc
.PaintImageData(fill
, pp::Point(second_paint_x
, second_paint_y
));
417 dc
.PaintImageData(fill
, pp::Point(second_paint_x
, second_paint_y
),
418 pp::Rect(-second_paint_x
, -second_paint_y
, 1, 1));
419 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
421 // Now we should have a little bit of the image peeking out the top left.
422 ASSERT_TRUE(IsSquareInDC(dc
, background_color
, pp::Rect(0, 0, 1, 1),
425 // Now repaint that top left pixel by doing a subset of the source image.
426 pp::ImageData
subset(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
427 pp::Size(w
, h
), false);
428 uint32_t subset_color
= 0x80808080;
429 const int subset_x
= 2, subset_y
= 1;
430 *subset
.GetAddr32(pp::Point(subset_x
, subset_y
)) = subset_color
;
431 dc
.PaintImageData(subset
, pp::Point(-subset_x
, -subset_y
),
432 pp::Rect(subset_x
, subset_y
, 1, 1));
433 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
434 ASSERT_TRUE(IsSquareInDC(dc
, background_color
, pp::Rect(0, 0, 1, 1),
440 std::string
TestGraphics2D::TestScroll() {
441 const int w
= 115, h
= 117;
442 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
443 ASSERT_FALSE(dc
.is_null());
444 ASSERT_TRUE(instance_
->BindGraphics(dc
));
446 // Make sure the device background is 0.
447 ASSERT_TRUE(IsDCUniformColor(dc
, 0));
449 const int image_width
= 15, image_height
= 23;
450 pp::ImageData
test_image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
451 pp::Size(image_width
, image_height
), false);
452 FillImageWithGradient(&test_image
);
453 pp::ImageData
no_image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
454 pp::Size(image_width
, image_height
), false);
455 FillRectInImage(&no_image
, pp::Rect(0, 0, image_width
, image_height
), 0);
456 pp::ImageData
readback_image(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
457 pp::Size(image_width
, image_height
), false);
458 pp::ImageData
readback_scroll(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
459 pp::Size(image_width
, image_height
), false);
461 ASSERT_EQ(pp::Size(image_width
, image_height
), test_image
.size());
463 int image_x
= 51, image_y
= 72;
464 dc
.PaintImageData(test_image
, pp::Point(image_x
, image_y
));
465 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
467 // Test Case 1. Incorrect usage when scrolling image to a free space.
468 // The clip area is *not* the area to shift around within the graphics device
469 // by specified amount. It's the area to which the scroll is limited. So if
470 // the clip area is the size of the image and the amount points to free space,
471 // the scroll won't result in additional images.
472 int dx
= -40, dy
= -48;
473 int scroll_x
= image_x
+ dx
, scroll_y
= image_y
+ dy
;
474 pp::Rect
clip(image_x
, image_y
, image_width
, image_height
);
475 dc
.Scroll(clip
, pp::Point(dx
, dy
));
476 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
478 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
479 ASSERT_TRUE(CompareImages(no_image
, readback_scroll
));
482 // The amount is intended to place the image in the free space outside
483 // of the original, but the clip area extends beyond the graphics device area.
484 // This scroll is invalid and will be a noop.
485 scroll_x
= 11, scroll_y
= 24;
486 clip
= pp::Rect(0, 0, w
, h
+ 1);
487 dc
.Scroll(clip
, pp::Point(scroll_x
- image_x
, scroll_y
- image_y
));
488 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
490 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
491 ASSERT_TRUE(CompareImages(no_image
, readback_scroll
));
494 // The amount is intended to place the image in the free space outside
495 // of the original, but the clip area does not cover the image,
496 // so there is nothing to scroll.
497 scroll_x
= 11, scroll_y
= 24;
498 clip
= pp::Rect(0, 0, image_x
, image_y
);
499 dc
.Scroll(clip
, pp::Point(scroll_x
- image_x
, scroll_y
- image_y
));
500 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
502 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
503 ASSERT_TRUE(CompareImages(no_image
, readback_scroll
));
506 // Same as TC3, but the clip covers part of the image.
507 // This part will be scrolled to the intended origin.
508 int part_w
= image_width
/ 2, part_h
= image_height
/ 2;
509 clip
= pp::Rect(0, 0, image_x
+ part_w
, image_y
+ part_h
);
510 dc
.Scroll(clip
, pp::Point(scroll_x
- image_x
, scroll_y
- image_y
));
511 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
513 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
514 ASSERT_FALSE(CompareImages(test_image
, readback_scroll
));
515 pp::Rect
part_rect(part_w
, part_h
);
517 CompareImageRect(test_image
, part_rect
, readback_scroll
, part_rect
));
520 // Same as TC3, but the clip area covers the entire image.
521 // It will be scrolled to the intended origin.
522 clip
= pp::Rect(0, 0, image_x
+ image_width
, image_y
+ image_height
);
523 dc
.Scroll(clip
, pp::Point(scroll_x
- image_x
, scroll_y
- image_y
));
524 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
526 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
527 ASSERT_TRUE(CompareImages(test_image
, readback_scroll
));
529 // Note that the undefined area left by the scroll does not actually get
530 // cleared, so the original image is still there. This is not guaranteed and
531 // is not something for users to rely on, but we can test for this here, so
532 // we know when the underlying behavior changes.
533 ASSERT_TRUE(ReadImageData(dc
, &readback_image
, pp::Point(image_x
, image_y
)));
534 ASSERT_TRUE(CompareImages(test_image
, readback_image
));
537 // Scroll image to an overlapping space. The clip area is limited
538 // to the image, so this will just modify its area.
541 scroll_x
= image_x
+ dx
;
542 scroll_y
= image_y
+ dy
;
543 clip
= pp::Rect(image_x
, image_y
, image_width
, image_height
);
544 dc
.Scroll(clip
, pp::Point(dx
, dy
));
545 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
546 ASSERT_TRUE(ReadImageData(dc
, &readback_image
, pp::Point(image_x
, image_y
)));
547 ASSERT_FALSE(CompareImages(test_image
, readback_image
));
548 pp::Rect
scroll_rect(image_width
- dx
, image_height
- dy
);
550 ReadImageData(dc
, &readback_scroll
, pp::Point(scroll_x
, scroll_y
)));
552 CompareImageRect(test_image
, scroll_rect
, readback_scroll
, scroll_rect
));
557 std::string
TestGraphics2D::TestReplace() {
558 const int w
= 15, h
= 17;
559 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
560 ASSERT_FALSE(dc
.is_null());
562 // Replacing with a different size image should fail.
563 pp::ImageData
weird_size(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
564 pp::Size(w
- 1, h
), true);
565 ASSERT_FALSE(weird_size
.is_null());
566 dc
.ReplaceContents(&weird_size
);
568 // Fill the background with blue but don't flush yet.
569 const int32_t background_color
= 0xFF0000FF;
570 pp::ImageData
background(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
571 pp::Size(w
, h
), true);
572 ASSERT_FALSE(background
.is_null());
573 FillRectInImage(&background
, pp::Rect(0, 0, w
, h
), background_color
);
574 dc
.PaintImageData(background
, pp::Point(0, 0));
576 // Replace with a green background but don't flush yet.
577 const int32_t swapped_color
= 0x00FF00FF;
578 pp::ImageData
swapped(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
579 pp::Size(w
, h
), true);
580 ASSERT_FALSE(swapped
.is_null());
581 FillRectInImage(&swapped
, pp::Rect(0, 0, w
, h
), swapped_color
);
582 dc
.ReplaceContents(&swapped
);
584 // The background should be unchanged since we didn't flush yet.
585 ASSERT_TRUE(IsDCUniformColor(dc
, 0));
587 // Test the C++ wrapper. The size of the swapped image should be reset.
588 ASSERT_TRUE(!swapped
.pp_resource() && !swapped
.size().width() &&
589 !swapped
.size().height() && !swapped
.data());
591 // Painting with the swapped image should fail.
592 dc
.PaintImageData(swapped
, pp::Point(0, 0));
594 // Flush and make sure the result is correct.
595 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
597 // The background should be green from the swapped image.
598 ASSERT_TRUE(IsDCUniformColor(dc
, swapped_color
));
603 std::string
TestGraphics2D::TestFlush() {
604 // Tests that synchronous flushes (NULL callback) fail on the main thread
605 // (which is the current one).
606 const int w
= 15, h
= 17;
607 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
608 ASSERT_FALSE(dc
.is_null());
610 // Fill the background with blue but don't flush yet.
611 pp::ImageData
background(instance_
, PP_IMAGEDATAFORMAT_BGRA_PREMUL
,
612 pp::Size(w
, h
), true);
613 ASSERT_FALSE(background
.is_null());
614 dc
.PaintImageData(background
, pp::Point(0, 0));
616 int32_t rv
= dc
.Flush(pp::BlockUntilComplete());
617 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD
, rv
);
619 // Test flushing with no operations still issues a callback.
620 // (This may also hang if the browser never issues the callback).
621 pp::Graphics2D
dc_nopaints(instance_
, pp::Size(w
, h
), false);
622 ASSERT_FALSE(dc
.is_null());
623 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc_nopaints
));
625 TestCompletionCallback
callback_1(instance_
->pp_instance(), callback_type());
627 // Test that multiple flushes fail if we don't get a callback in between.
628 rv
= dc_nopaints
.Flush(callback_1
.GetCallback());
629 if (rv
== PP_OK_COMPLETIONPENDING
) {
630 // If the first flush completes asynchronously, then a second should fail.
631 TestCompletionCallback
callback_2(instance_
->pp_instance(),
633 callback_2
.WaitForResult(dc_nopaints
.Flush(callback_2
.GetCallback()));
634 CHECK_CALLBACK_BEHAVIOR(callback_2
);
635 ASSERT_EQ(PP_ERROR_INPROGRESS
, callback_2
.result());
637 callback_1
.WaitForResult(rv
);
638 ASSERT_EQ(PP_OK
, callback_1
.result());
643 void TestGraphics2D::DidChangeView(const pp::View
& view
) {
644 if (post_quit_on_view_changed_
) {
645 post_quit_on_view_changed_
= false;
646 is_view_changed_
= true;
647 testing_interface_
->QuitMessageLoop(instance_
->pp_instance());
651 void TestGraphics2D::ResetViewChangedState() {
652 is_view_changed_
= false;
655 bool TestGraphics2D::WaitUntilViewChanged() {
656 // Run a nested message loop. It will exit either on ViewChanged or if the
659 // If view changed before we have chance to run message loop, return directly.
660 if (is_view_changed_
)
663 post_quit_on_view_changed_
= true;
664 testing_interface_
->RunMessageLoop(instance_
->pp_instance());
665 post_quit_on_view_changed_
= false;
667 return is_view_changed_
;
670 std::string
TestGraphics2D::TestFlushOffscreenUpdate() {
671 // Tests that callback of offscreen updates should be delayed.
672 const PP_Time kFlushDelaySec
= 1. / 30; // 30 fps
673 const int w
= 80, h
= 80;
674 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), true);
675 ASSERT_FALSE(dc
.is_null());
676 ASSERT_TRUE(instance_
->BindGraphics(dc
));
678 // Squeeze from top until bottom half of plugin is out of screen.
679 ResetViewChangedState();
680 instance_
->EvalScript(
681 "var big = document.createElement('div');"
683 " window.innerHeight - plugin.offsetTop - plugin.offsetHeight / 2;"
684 "big.setAttribute('id', 'big-div');"
685 "big.setAttribute('style', 'height: ' + offset + '; width: 100%;');"
686 "document.body.insertBefore(big, document.body.firstChild);");
687 ASSERT_TRUE(WaitUntilViewChanged());
689 // Allocate a red image chunk
690 pp::ImageData
chunk(instance_
, PP_IMAGEDATAFORMAT_RGBA_PREMUL
,
691 pp::Size(w
/8, h
/8), true);
692 ASSERT_FALSE(chunk
.is_null());
693 const uint32_t kRed
= 0xff0000ff;
694 FillRectInImage(&chunk
, pp::Rect(chunk
.size()), kRed
);
696 // Paint a invisable chunk, expecting Flush to invoke callback slowly.
697 dc
.PaintImageData(chunk
, pp::Point(0, h
*0.75));
699 PP_Time begin
= pp::Module::Get()->core()->GetTime();
700 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc
));
701 PP_Time actual_time_elapsed
= pp::Module::Get()->core()->GetTime() - begin
;
702 // Expect actual_time_elapsed >= kFlushDelaySec, but loose a bit to avoid
704 ASSERT_GE(actual_time_elapsed
, kFlushDelaySec
* 0.9);
706 // Remove the padding on the top since test cases here isn't independent.
707 instance_
->EvalScript(
708 "var big = document.getElementById('big-div');"
709 "big.parentNode.removeChild(big);");
710 ResetViewChangedState();
711 ASSERT_TRUE(WaitUntilViewChanged());
716 std::string
TestGraphics2D::TestDev() {
717 // Tests GetScale/SetScale via the Graphics2D_Dev C++ wrapper
718 const int w
= 20, h
= 16;
719 const float scale
= 1.0f
/2.0f
;
720 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
721 ASSERT_FALSE(dc
.is_null());
722 ASSERT_EQ(1.0f
, dc
.GetScale());
723 ASSERT_TRUE(dc
.SetScale(scale
));
724 ASSERT_EQ(scale
, dc
.GetScale());
725 // Try setting a few invalid scale factors. Ensure that we catch these errors
726 // and don't change the actual scale
727 ASSERT_FALSE(dc
.SetScale(-1.0f
));
728 ASSERT_FALSE(dc
.SetScale(0.0f
));
729 ASSERT_EQ(scale
, dc
.GetScale());
731 // Verify that the context has the specified number of pixels, despite the
732 // non-identity scale
736 PP_Bool is_always_opaque
= PP_FALSE
;
737 ASSERT_TRUE(graphics_2d_interface_
->Describe(dc
.pp_resource(), &size
,
739 ASSERT_EQ(w
, size
.width
);
740 ASSERT_EQ(h
, size
.height
);
741 ASSERT_EQ(PP_FALSE
, is_always_opaque
);
746 // This test makes sure that the out-of-process image data caching works as
747 // expected. Doing ReplaceContents quickly should re-use the image data from
749 std::string
TestGraphics2D::TestReplaceContentsCaching() {
750 // The cache is only active when running in the proxy, so skip it otherwise.
751 if (!testing_interface_
->IsOutOfProcess())
754 // Here we test resource IDs as a way to determine if the resource is being
755 // cached and re-used. This is non-optimal since it's entirely possible
756 // (and maybe better) for the proxy to return new resource IDs for the
757 // re-used objects. Howevever, our current implementation does this so it is
758 // an easy thing to check for.
760 // You could check for the shared memory pointers getting re-used, but the
761 // OS is very likely to use the same memory location for a newly-mapped image
762 // if one was deleted, meaning that it could pass even if the cache is broken.
763 // This would then require that we add some address-re-use-preventing code
764 // which would be tricky.
765 std::set
<PP_Resource
> resources
;
767 pp::Size
size(16, 16);
768 pp::Graphics2D
dc(instance_
, size
, false);
770 // Do two replace contentses, adding the old resource IDs to our map.
771 PP_Resource imageres
= ReplaceContentsAndReturnID(&dc
, size
);
772 ASSERT_TRUE(imageres
);
773 resources
.insert(imageres
);
774 imageres
= ReplaceContentsAndReturnID(&dc
, size
);
775 ASSERT_TRUE(imageres
);
776 resources
.insert(imageres
);
778 // Now doing more replace contents should re-use older IDs if the cache is
780 imageres
= ReplaceContentsAndReturnID(&dc
, size
);
781 ASSERT_TRUE(resources
.find(imageres
) != resources
.end());
782 imageres
= ReplaceContentsAndReturnID(&dc
, size
);
783 ASSERT_TRUE(resources
.find(imageres
) != resources
.end());
788 std::string
TestGraphics2D::TestBindNull() {
789 // Binding a null resource is not an error, it should clear all bound
790 // resources. We can't easily test what resource is bound, but we can test
791 // that this doesn't throw an error.
792 ASSERT_TRUE(instance_
->BindGraphics(pp::Graphics2D()));
793 ASSERT_TRUE(instance_
->BindGraphics(pp::Graphics3D()));
795 const int w
= 115, h
= 117;
796 pp::Graphics2D
dc(instance_
, pp::Size(w
, h
), false);
797 ASSERT_FALSE(dc
.is_null());
798 ASSERT_TRUE(instance_
->BindGraphics(dc
));
800 ASSERT_TRUE(instance_
->BindGraphics(pp::Graphics2D()));
801 ASSERT_TRUE(instance_
->BindGraphics(pp::Graphics3D()));