Move render_view_context_menu.* and related files out of tab_contents.
[chromium-blink-merge.git] / ppapi / tests / test_graphics_2d.cc
blob5bb66d73b7497071f43e3fb041bb6fa51aff2709
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"
7 #include <stdlib.h>
8 #include <string.h>
10 #include <set>
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/dev/graphics_2d_dev.h"
16 #include "ppapi/cpp/dev/graphics_2d_dev.h"
17 #include "ppapi/cpp/graphics_2d.h"
18 #include "ppapi/cpp/graphics_3d.h"
19 #include "ppapi/cpp/image_data.h"
20 #include "ppapi/cpp/instance.h"
21 #include "ppapi/cpp/module.h"
22 #include "ppapi/cpp/rect.h"
23 #include "ppapi/tests/test_utils.h"
24 #include "ppapi/tests/testing_instance.h"
26 REGISTER_TEST_CASE(Graphics2D);
28 namespace {
30 bool CanFlushContext(pp::Instance* instance, pp::Graphics2D* context) {
31 TestCompletionCallback callback(instance->pp_instance());
32 callback.WaitForResult(context->Flush(callback.GetCallback()));
33 return (callback.result() == PP_OK);
36 bool CanFlushContextC(pp::Instance* instance, PP_Resource graphics_2d,
37 const PPB_Graphics2D_1_1* graphics_2d_if) {
38 TestCompletionCallback callback(instance->pp_instance());
39 callback.WaitForResult(graphics_2d_if->Flush(
40 graphics_2d, callback.GetCallback().pp_completion_callback()));
41 return (callback.result() == PP_OK);
44 } // namespace
46 TestGraphics2D::TestGraphics2D(TestingInstance* instance)
47 : TestCase(instance),
48 is_view_changed_(false),
49 post_quit_on_view_changed_(false) {
52 bool TestGraphics2D::Init() {
53 graphics_2d_interface_ = static_cast<const PPB_Graphics2D*>(
54 pp::Module::Get()->GetBrowserInterface(PPB_GRAPHICS_2D_INTERFACE_1_1));
55 image_data_interface_ = static_cast<const PPB_ImageData*>(
56 pp::Module::Get()->GetBrowserInterface(PPB_IMAGEDATA_INTERFACE_1_0));
57 return graphics_2d_interface_ && image_data_interface_ &&
58 CheckTestingInterface();
61 void TestGraphics2D::RunTests(const std::string& filter) {
62 RUN_TEST(InvalidResource, filter);
63 RUN_TEST(InvalidSize, filter);
64 RUN_TEST(Humongous, filter);
65 RUN_TEST(InitToZero, filter);
66 RUN_TEST(Describe, filter);
67 RUN_TEST(Scale, filter);
68 RUN_TEST_FORCEASYNC_AND_NOT(Paint, filter);
69 RUN_TEST_FORCEASYNC_AND_NOT(Scroll, filter);
70 RUN_TEST_FORCEASYNC_AND_NOT(Replace, filter);
71 RUN_TEST_FORCEASYNC_AND_NOT(Flush, filter);
72 RUN_TEST_FORCEASYNC_AND_NOT(FlushOffscreenUpdate, filter);
73 RUN_TEST(Dev, filter);
74 RUN_TEST(ReplaceContentsCaching, filter);
75 RUN_TEST(BindNull, filter);
78 void TestGraphics2D::QuitMessageLoop() {
79 testing_interface_->QuitMessageLoop(instance_->pp_instance());
82 bool TestGraphics2D::ReadImageData(const pp::Graphics2D& dc,
83 pp::ImageData* image,
84 const pp::Point& top_left) const {
85 return PP_ToBool(testing_interface_->ReadImageData(
86 dc.pp_resource(),
87 image->pp_resource(),
88 &top_left.pp_point()));
91 bool TestGraphics2D::IsDCUniformColor(const pp::Graphics2D& dc,
92 uint32_t color) const {
93 pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
94 dc.size(), false);
95 if (readback.is_null())
96 return false;
97 if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
98 return false;
99 return IsSquareInImage(readback, 0, pp::Rect(dc.size()), color);
102 std::string TestGraphics2D::FlushAndWaitForDone(pp::Graphics2D* context) {
103 TestCompletionCallback callback(instance_->pp_instance(), callback_type());
104 callback.WaitForResult(context->Flush(callback.GetCallback()));
105 CHECK_CALLBACK_BEHAVIOR(callback);
106 ASSERT_EQ(PP_OK, callback.result());
107 PASS();
110 void TestGraphics2D::FillRectInImage(pp::ImageData* image,
111 const pp::Rect& rect,
112 uint32_t color) const {
113 for (int y = rect.y(); y < rect.bottom(); y++) {
114 uint32_t* row = image->GetAddr32(pp::Point(rect.x(), y));
115 for (int pixel = 0; pixel < rect.width(); pixel++)
116 row[pixel] = color;
120 void TestGraphics2D::FillImageWithGradient(pp::ImageData* image) const {
121 for (int y = 0; y < image->size().height(); y++) {
122 uint32_t red = ((y * 256) / image->size().height()) & 0xFF;
123 for (int x = 0; x < image->size().width(); x++) {
124 uint32_t green = ((x * 256) / image->size().width()) & 0xFF;
125 uint32_t blue = ((red + green) / 2) & 0xFF;
126 uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
127 *pixel = (blue << 24) | (green << 16) | (red << 8);
132 bool TestGraphics2D::CompareImages(const pp::ImageData& image1,
133 const pp::ImageData& image2) {
134 return CompareImageRect(
135 image1, pp::Rect(0, 0, image1.size().width(), image1.size().height()),
136 image2, pp::Rect(0, 0, image2.size().width(), image2.size().height()));
139 bool TestGraphics2D::CompareImageRect(const pp::ImageData& image1,
140 const pp::Rect& rc1,
141 const pp::ImageData& image2,
142 const pp::Rect& rc2) const {
143 if (rc1.width() != rc2.width() || rc1.height() != rc2.height())
144 return false;
146 for (int y = 0; y < rc1.height(); y++) {
147 for (int x = 0; x < rc1.width(); x++) {
148 if (*(image1.GetAddr32(pp::Point(rc1.x() + x, rc1.y() + y))) !=
149 *(image2.GetAddr32(pp::Point(rc2.x() + x, rc2.y() + y))))
150 return false;
153 return true;
156 bool TestGraphics2D::IsSquareInImage(const pp::ImageData& image_data,
157 uint32_t background_color,
158 const pp::Rect& square,
159 uint32_t square_color) const {
160 for (int y = 0; y < image_data.size().height(); y++) {
161 for (int x = 0; x < image_data.size().width(); x++) {
162 uint32_t pixel = *image_data.GetAddr32(pp::Point(x, y));
163 uint32_t desired_color;
164 if (square.Contains(x, y))
165 desired_color = square_color;
166 else
167 desired_color = background_color;
168 if (pixel != desired_color)
169 return false;
172 return true;
175 bool TestGraphics2D::IsSquareInDC(const pp::Graphics2D& dc,
176 uint32_t background_color,
177 const pp::Rect& square,
178 uint32_t square_color) const {
179 pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
180 dc.size(), false);
181 if (readback.is_null())
182 return false;
183 if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
184 return false;
185 return IsSquareInImage(readback, background_color, square, square_color);
189 PP_Resource TestGraphics2D::ReplaceContentsAndReturnID(
190 pp::Graphics2D* dc,
191 const pp::Size& size) {
192 pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, true);
194 PP_Resource id = image.pp_resource();
196 dc->ReplaceContents(&image);
197 std::string result = FlushAndWaitForDone(dc);
198 if (!result.empty())
199 return 0;
201 return id;
204 // Test all the functions with an invalid handle. Most of these just check for
205 // a crash since the browser don't return a value.
206 std::string TestGraphics2D::TestInvalidResource() {
207 pp::Graphics2D null_context;
208 pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
209 pp::Size(16, 16), true);
211 // Describe.
212 PP_Size size;
213 PP_Bool opaque;
214 graphics_2d_interface_->Describe(image.pp_resource(), &size, &opaque);
215 graphics_2d_interface_->Describe(null_context.pp_resource(),
216 &size, &opaque);
218 // PaintImageData.
219 PP_Point zero_zero;
220 zero_zero.x = 0;
221 zero_zero.y = 0;
222 graphics_2d_interface_->PaintImageData(image.pp_resource(),
223 image.pp_resource(),
224 &zero_zero, NULL);
225 graphics_2d_interface_->PaintImageData(null_context.pp_resource(),
226 image.pp_resource(),
227 &zero_zero, NULL);
229 // Scroll.
230 PP_Point zero_ten;
231 zero_ten.x = 0;
232 zero_ten.y = 10;
233 graphics_2d_interface_->Scroll(image.pp_resource(), NULL, &zero_ten);
234 graphics_2d_interface_->Scroll(null_context.pp_resource(),
235 NULL, &zero_ten);
237 // ReplaceContents.
238 graphics_2d_interface_->ReplaceContents(image.pp_resource(),
239 image.pp_resource());
240 graphics_2d_interface_->ReplaceContents(null_context.pp_resource(),
241 image.pp_resource());
243 // Flush.
244 TestCompletionCallback cb(instance_->pp_instance(), PP_OPTIONAL);
245 cb.WaitForResult(
246 graphics_2d_interface_->Flush(image.pp_resource(),
247 cb.GetCallback().pp_completion_callback()));
248 ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
249 cb.WaitForResult(
250 graphics_2d_interface_->Flush(null_context.pp_resource(),
251 cb.GetCallback().pp_completion_callback()));
252 ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
254 // ReadImageData.
255 ASSERT_FALSE(testing_interface_->ReadImageData(image.pp_resource(),
256 image.pp_resource(),
257 &zero_zero));
258 ASSERT_FALSE(testing_interface_->ReadImageData(null_context.pp_resource(),
259 image.pp_resource(),
260 &zero_zero));
262 PASS();
265 std::string TestGraphics2D::TestInvalidSize() {
266 pp::Graphics2D a(instance_, pp::Size(16, 0), false);
267 ASSERT_FALSE(CanFlushContext(instance_, &a));
269 pp::Graphics2D b(instance_, pp::Size(0, 16), false);
270 ASSERT_FALSE(CanFlushContext(instance_, &b));
272 // Need to use the C API since pp::Size prevents negative sizes.
273 PP_Size size;
274 size.width = 16;
275 size.height = -16;
276 PP_Resource graphics = graphics_2d_interface_->Create(
277 instance_->pp_instance(), &size, PP_FALSE);
278 ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
279 pp::Module::Get()->core()->ReleaseResource(graphics);
281 size.width = -16;
282 size.height = 16;
283 graphics = graphics_2d_interface_->Create(
284 instance_->pp_instance(), &size, PP_FALSE);
285 ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
286 pp::Module::Get()->core()->ReleaseResource(graphics);
288 // Overflow to negative size
289 size.width = std::numeric_limits<int32_t>::max();
290 size.height = std::numeric_limits<int32_t>::max();
291 graphics = graphics_2d_interface_->Create(
292 instance_->pp_instance(), &size, PP_FALSE);
293 ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
294 pp::Module::Get()->core()->ReleaseResource(graphics);
296 PASS();
299 std::string TestGraphics2D::TestHumongous() {
300 pp::Graphics2D a(instance_, pp::Size(100000, 100000), false);
301 ASSERT_FALSE(CanFlushContext(instance_, &a));
302 PASS();
305 std::string TestGraphics2D::TestInitToZero() {
306 const int w = 15, h = 17;
307 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
308 ASSERT_FALSE(dc.is_null());
310 // Make an image with nonzero data in it (so we can test that zeros were
311 // actually read versus ReadImageData being a NOP).
312 pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
313 pp::Size(w, h), true);
314 ASSERT_FALSE(image.is_null());
315 ASSERT_FALSE(image.size().IsEmpty());
316 memset(image.data(), 0xFF, image.stride() * image.size().height() * 4);
318 // Read out the initial data from the device & check.
319 ASSERT_TRUE(ReadImageData(dc, &image, pp::Point(0, 0)));
320 ASSERT_TRUE(IsSquareInImage(image, 0, pp::Rect(0, 0, w, h), 0));
322 PASS();
325 std::string TestGraphics2D::TestDescribe() {
326 const int w = 15, h = 17;
327 const bool always_opaque = (::rand() % 2 == 1);
328 pp::Graphics2D dc(instance_, pp::Size(w, h), always_opaque);
329 ASSERT_FALSE(dc.is_null());
331 PP_Size size;
332 size.width = -1;
333 size.height = -1;
334 PP_Bool is_always_opaque = PP_FALSE;
335 ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
336 &is_always_opaque));
337 ASSERT_EQ(w, size.width);
338 ASSERT_EQ(h, size.height);
339 ASSERT_EQ(PP_FromBool(always_opaque), is_always_opaque);
341 PASS();
344 std::string TestGraphics2D::TestScale() {
345 // Tests GetScale/SetScale
346 const int w = 20, h = 16;
347 const float scale = 1.0f/2.0f;
348 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
349 ASSERT_FALSE(dc.is_null());
350 ASSERT_EQ(1.0, dc.GetScale());
351 ASSERT_TRUE(dc.SetScale(scale));
352 ASSERT_EQ(scale, dc.GetScale());
353 // Try setting a few invalid scale factors. Ensure that we catch these errors
354 // and don't change the actual scale
355 ASSERT_FALSE(dc.SetScale(-1.0f));
356 ASSERT_FALSE(dc.SetScale(0.0f));
357 ASSERT_EQ(scale, dc.GetScale());
359 // Verify that the context has the specified number of pixels, despite the
360 // non-identity scale
361 PP_Size size;
362 size.width = -1;
363 size.height = -1;
364 PP_Bool is_always_opaque = PP_FALSE;
365 ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
366 &is_always_opaque));
367 ASSERT_EQ(w, size.width);
368 ASSERT_EQ(h, size.height);
369 ASSERT_EQ(PP_FALSE, is_always_opaque);
371 PASS();
374 std::string TestGraphics2D::TestPaint() {
375 const int w = 15, h = 17;
376 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
377 ASSERT_FALSE(dc.is_null());
379 // Make sure the device background is 0.
380 ASSERT_TRUE(IsDCUniformColor(dc, 0));
382 // Fill the backing store with white.
383 const uint32_t background_color = 0xFFFFFFFF;
384 pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
385 pp::Size(w, h), false);
386 FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
387 dc.PaintImageData(background, pp::Point(0, 0));
388 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
390 // Make an image to paint with that's opaque white and enqueue a paint.
391 const int fill_w = 2, fill_h = 3;
392 pp::ImageData fill(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
393 pp::Size(fill_w, fill_h), true);
394 ASSERT_FALSE(fill.is_null());
395 FillRectInImage(&fill, pp::Rect(fill.size()), background_color);
396 const int paint_x = 4, paint_y = 5;
397 dc.PaintImageData(fill, pp::Point(paint_x, paint_y));
399 // Validate that nothing has been actually painted.
400 ASSERT_TRUE(IsDCUniformColor(dc, background_color));
402 // The paint hasn't been flushed so we can still change the bitmap. Fill with
403 // 50% blue. This will also verify that the backing store is replaced
404 // with the contents rather than blended.
405 const uint32_t fill_color = 0x80000080;
406 FillRectInImage(&fill, pp::Rect(fill.size()), fill_color);
407 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
409 ASSERT_TRUE(IsSquareInDC(dc, background_color,
410 pp::Rect(paint_x, paint_y, fill_w, fill_h),
411 fill_color));
413 // Reset the DC to blank white & paint our image slightly off the buffer.
414 // This should succeed. We also try painting the same thing where the
415 // dirty rect falls outeside of the device, which should fail.
416 dc.PaintImageData(background, pp::Point(0, 0));
417 const int second_paint_x = -1, second_paint_y = -2;
418 dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y));
419 dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y),
420 pp::Rect(-second_paint_x, -second_paint_y, 1, 1));
421 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
423 // Now we should have a little bit of the image peeking out the top left.
424 ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
425 fill_color));
427 // Now repaint that top left pixel by doing a subset of the source image.
428 pp::ImageData subset(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
429 pp::Size(w, h), false);
430 uint32_t subset_color = 0x80808080;
431 const int subset_x = 2, subset_y = 1;
432 *subset.GetAddr32(pp::Point(subset_x, subset_y)) = subset_color;
433 dc.PaintImageData(subset, pp::Point(-subset_x, -subset_y),
434 pp::Rect(subset_x, subset_y, 1, 1));
435 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
436 ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
437 subset_color));
439 PASS();
442 std::string TestGraphics2D::TestScroll() {
443 const int w = 115, h = 117;
444 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
445 ASSERT_FALSE(dc.is_null());
446 ASSERT_TRUE(instance_->BindGraphics(dc));
448 // Make sure the device background is 0.
449 ASSERT_TRUE(IsDCUniformColor(dc, 0));
451 const int image_width = 15, image_height = 23;
452 pp::ImageData test_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
453 pp::Size(image_width, image_height), false);
454 FillImageWithGradient(&test_image);
455 pp::ImageData no_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
456 pp::Size(image_width, image_height), false);
457 FillRectInImage(&no_image, pp::Rect(0, 0, image_width, image_height), 0);
458 pp::ImageData readback_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
459 pp::Size(image_width, image_height), false);
460 pp::ImageData readback_scroll(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
461 pp::Size(image_width, image_height), false);
463 ASSERT_EQ(pp::Size(image_width, image_height), test_image.size());
465 int image_x = 51, image_y = 72;
466 dc.PaintImageData(test_image, pp::Point(image_x, image_y));
467 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
469 // Test Case 1. Incorrect usage when scrolling image to a free space.
470 // The clip area is *not* the area to shift around within the graphics device
471 // by specified amount. It's the area to which the scroll is limited. So if
472 // the clip area is the size of the image and the amount points to free space,
473 // the scroll won't result in additional images.
474 int dx = -40, dy = -48;
475 int scroll_x = image_x + dx, scroll_y = image_y + dy;
476 pp::Rect clip(image_x, image_y, image_width, image_height);
477 dc.Scroll(clip, pp::Point(dx, dy));
478 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
479 ASSERT_TRUE(
480 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
481 ASSERT_TRUE(CompareImages(no_image, readback_scroll));
483 // Test Case 2.
484 // The amount is intended to place the image in the free space outside
485 // of the original, but the clip area extends beyond the graphics device area.
486 // This scroll is invalid and will be a noop.
487 scroll_x = 11, scroll_y = 24;
488 clip = pp::Rect(0, 0, w, h + 1);
489 dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
490 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
491 ASSERT_TRUE(
492 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
493 ASSERT_TRUE(CompareImages(no_image, readback_scroll));
495 // Test Case 3.
496 // The amount is intended to place the image in the free space outside
497 // of the original, but the clip area does not cover the image,
498 // so there is nothing to scroll.
499 scroll_x = 11, scroll_y = 24;
500 clip = pp::Rect(0, 0, image_x, image_y);
501 dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
502 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
503 ASSERT_TRUE(
504 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
505 ASSERT_TRUE(CompareImages(no_image, readback_scroll));
507 // Test Case 4.
508 // Same as TC3, but the clip covers part of the image.
509 // This part will be scrolled to the intended origin.
510 int part_w = image_width / 2, part_h = image_height / 2;
511 clip = pp::Rect(0, 0, image_x + part_w, image_y + part_h);
512 dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
513 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
514 ASSERT_TRUE(
515 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
516 ASSERT_FALSE(CompareImages(test_image, readback_scroll));
517 pp::Rect part_rect(part_w, part_h);
518 ASSERT_TRUE(
519 CompareImageRect(test_image, part_rect, readback_scroll, part_rect));
521 // Test Case 5
522 // Same as TC3, but the clip area covers the entire image.
523 // It will be scrolled to the intended origin.
524 clip = pp::Rect(0, 0, image_x + image_width, image_y + image_height);
525 dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
526 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
527 ASSERT_TRUE(
528 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
529 ASSERT_TRUE(CompareImages(test_image, readback_scroll));
531 // Note that the undefined area left by the scroll does not actually get
532 // cleared, so the original image is still there. This is not guaranteed and
533 // is not something for users to rely on, but we can test for this here, so
534 // we know when the underlying behavior changes.
535 ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
536 ASSERT_TRUE(CompareImages(test_image, readback_image));
538 // Test Case 6.
539 // Scroll image to an overlapping space. The clip area is limited
540 // to the image, so this will just modify its area.
541 dx = 6;
542 dy = 9;
543 scroll_x = image_x + dx;
544 scroll_y = image_y + dy;
545 clip = pp::Rect(image_x, image_y, image_width, image_height);
546 dc.Scroll(clip, pp::Point(dx, dy));
547 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
548 ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
549 ASSERT_FALSE(CompareImages(test_image, readback_image));
550 pp::Rect scroll_rect(image_width - dx, image_height - dy);
551 ASSERT_TRUE(
552 ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
553 ASSERT_TRUE(
554 CompareImageRect(test_image, scroll_rect, readback_scroll, scroll_rect));
556 PASS();
559 std::string TestGraphics2D::TestReplace() {
560 const int w = 15, h = 17;
561 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
562 ASSERT_FALSE(dc.is_null());
564 // Replacing with a different size image should fail.
565 pp::ImageData weird_size(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
566 pp::Size(w - 1, h), true);
567 ASSERT_FALSE(weird_size.is_null());
568 dc.ReplaceContents(&weird_size);
570 // Fill the background with blue but don't flush yet.
571 const int32_t background_color = 0xFF0000FF;
572 pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
573 pp::Size(w, h), true);
574 ASSERT_FALSE(background.is_null());
575 FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
576 dc.PaintImageData(background, pp::Point(0, 0));
578 // Replace with a green background but don't flush yet.
579 const int32_t swapped_color = 0x00FF00FF;
580 pp::ImageData swapped(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
581 pp::Size(w, h), true);
582 ASSERT_FALSE(swapped.is_null());
583 FillRectInImage(&swapped, pp::Rect(0, 0, w, h), swapped_color);
584 dc.ReplaceContents(&swapped);
586 // The background should be unchanged since we didn't flush yet.
587 ASSERT_TRUE(IsDCUniformColor(dc, 0));
589 // Test the C++ wrapper. The size of the swapped image should be reset.
590 ASSERT_TRUE(!swapped.pp_resource() && !swapped.size().width() &&
591 !swapped.size().height() && !swapped.data());
593 // Painting with the swapped image should fail.
594 dc.PaintImageData(swapped, pp::Point(0, 0));
596 // Flush and make sure the result is correct.
597 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
599 // The background should be green from the swapped image.
600 ASSERT_TRUE(IsDCUniformColor(dc, swapped_color));
602 PASS();
605 std::string TestGraphics2D::TestFlush() {
606 // Tests that synchronous flushes (NULL callback) fail on the main thread
607 // (which is the current one).
608 const int w = 15, h = 17;
609 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
610 ASSERT_FALSE(dc.is_null());
612 // Fill the background with blue but don't flush yet.
613 pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
614 pp::Size(w, h), true);
615 ASSERT_FALSE(background.is_null());
616 dc.PaintImageData(background, pp::Point(0, 0));
618 int32_t rv = dc.Flush(pp::BlockUntilComplete());
619 ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, rv);
621 // Test flushing with no operations still issues a callback.
622 // (This may also hang if the browser never issues the callback).
623 pp::Graphics2D dc_nopaints(instance_, pp::Size(w, h), false);
624 ASSERT_FALSE(dc.is_null());
625 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc_nopaints));
627 TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
629 // Test that multiple flushes fail if we don't get a callback in between.
630 rv = dc_nopaints.Flush(callback_1.GetCallback());
631 if (rv == PP_OK_COMPLETIONPENDING) {
632 // If the first flush completes asynchronously, then a second should fail.
633 TestCompletionCallback callback_2(instance_->pp_instance(),
634 callback_type());
635 callback_2.WaitForResult(dc_nopaints.Flush(callback_2.GetCallback()));
636 CHECK_CALLBACK_BEHAVIOR(callback_2);
637 ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
639 callback_1.WaitForResult(rv);
640 ASSERT_EQ(PP_OK, callback_1.result());
642 PASS();
645 void TestGraphics2D::DidChangeView(const pp::View& view) {
646 if (post_quit_on_view_changed_) {
647 post_quit_on_view_changed_ = false;
648 is_view_changed_ = true;
649 testing_interface_->QuitMessageLoop(instance_->pp_instance());
653 void TestGraphics2D::ResetViewChangedState() {
654 is_view_changed_ = false;
657 bool TestGraphics2D::WaitUntilViewChanged() {
658 // Run a nested message loop. It will exit either on ViewChanged or if the
659 // timeout happens.
661 // If view changed before we have chance to run message loop, return directly.
662 if (is_view_changed_)
663 return true;
665 post_quit_on_view_changed_ = true;
666 testing_interface_->RunMessageLoop(instance_->pp_instance());
667 post_quit_on_view_changed_ = false;
669 return is_view_changed_;
672 std::string TestGraphics2D::TestFlushOffscreenUpdate() {
673 // Tests that callback of offscreen updates should be delayed.
674 const PP_Time kFlushDelaySec = 1. / 30; // 30 fps
675 const int w = 80, h = 80;
676 pp::Graphics2D dc(instance_, pp::Size(w, h), true);
677 ASSERT_FALSE(dc.is_null());
678 ASSERT_TRUE(instance_->BindGraphics(dc));
680 // Squeeze from top until bottom half of plugin is out of screen.
681 ResetViewChangedState();
682 instance_->EvalScript(
683 "var big = document.createElement('div');"
684 "var offset = "
685 " window.innerHeight - plugin.offsetTop - plugin.offsetHeight / 2;"
686 "big.setAttribute('id', 'big-div');"
687 "big.setAttribute('style', 'height: ' + offset + '; width: 100%;');"
688 "document.body.insertBefore(big, document.body.firstChild);");
689 ASSERT_TRUE(WaitUntilViewChanged());
691 // Allocate a red image chunk
692 pp::ImageData chunk(instance_, PP_IMAGEDATAFORMAT_RGBA_PREMUL,
693 pp::Size(w/8, h/8), true);
694 ASSERT_FALSE(chunk.is_null());
695 const uint32_t kRed = 0xff0000ff;
696 FillRectInImage(&chunk, pp::Rect(chunk.size()), kRed);
698 // Paint a invisable chunk, expecting Flush to invoke callback slowly.
699 dc.PaintImageData(chunk, pp::Point(0, h*0.75));
701 PP_Time begin = pp::Module::Get()->core()->GetTime();
702 ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
703 PP_Time actual_time_elapsed = pp::Module::Get()->core()->GetTime() - begin;
704 // Expect actual_time_elapsed >= kFlushDelaySec, but loose a bit to avoid
705 // precision issue.
706 ASSERT_GE(actual_time_elapsed, kFlushDelaySec * 0.9);
708 // Remove the padding on the top since test cases here isn't independent.
709 instance_->EvalScript(
710 "var big = document.getElementById('big-div');"
711 "big.parentNode.removeChild(big);");
712 ResetViewChangedState();
713 ASSERT_TRUE(WaitUntilViewChanged());
715 PASS();
718 std::string TestGraphics2D::TestDev() {
719 // Tests GetScale/SetScale via the Graphics2D_Dev C++ wrapper
720 const int w = 20, h = 16;
721 const float scale = 1.0f/2.0f;
722 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
723 ASSERT_FALSE(dc.is_null());
724 pp::Graphics2D_Dev dc_dev(dc);
725 ASSERT_EQ(1.0f, dc_dev.GetScale());
726 ASSERT_TRUE(dc_dev.SetScale(scale));
727 ASSERT_EQ(scale, dc_dev.GetScale());
728 // Try setting a few invalid scale factors. Ensure that we catch these errors
729 // and don't change the actual scale
730 ASSERT_FALSE(dc_dev.SetScale(-1.0f));
731 ASSERT_FALSE(dc_dev.SetScale(0.0f));
732 ASSERT_EQ(scale, dc_dev.GetScale());
734 // Verify that the context has the specified number of pixels, despite the
735 // non-identity scale
736 PP_Size size;
737 size.width = -1;
738 size.height = -1;
739 PP_Bool is_always_opaque = PP_FALSE;
740 ASSERT_TRUE(graphics_2d_interface_->Describe(dc_dev.pp_resource(), &size,
741 &is_always_opaque));
742 ASSERT_EQ(w, size.width);
743 ASSERT_EQ(h, size.height);
744 ASSERT_EQ(PP_FALSE, is_always_opaque);
746 PASS();
749 // This test makes sure that the out-of-process image data caching works as
750 // expected. Doing ReplaceContents quickly should re-use the image data from
751 // older ones.
752 std::string TestGraphics2D::TestReplaceContentsCaching() {
753 // The cache is only active when running in the proxy, so skip it otherwise.
754 if (!testing_interface_->IsOutOfProcess())
755 PASS();
757 // Here we test resource IDs as a way to determine if the resource is being
758 // cached and re-used. This is non-optimal since it's entirely possible
759 // (and maybe better) for the proxy to return new resource IDs for the
760 // re-used objects. Howevever, our current implementation does this so it is
761 // an easy thing to check for.
763 // You could check for the shared memory pointers getting re-used, but the
764 // OS is very likely to use the same memory location for a newly-mapped image
765 // if one was deleted, meaning that it could pass even if the cache is broken.
766 // This would then require that we add some address-re-use-preventing code
767 // which would be tricky.
768 std::set<PP_Resource> resources;
770 pp::Size size(16, 16);
771 pp::Graphics2D dc(instance_, size, false);
773 // Do two replace contentses, adding the old resource IDs to our map.
774 PP_Resource imageres = ReplaceContentsAndReturnID(&dc, size);
775 ASSERT_TRUE(imageres);
776 resources.insert(imageres);
777 imageres = ReplaceContentsAndReturnID(&dc, size);
778 ASSERT_TRUE(imageres);
779 resources.insert(imageres);
781 // Now doing more replace contents should re-use older IDs if the cache is
782 // working.
783 imageres = ReplaceContentsAndReturnID(&dc, size);
784 ASSERT_TRUE(resources.find(imageres) != resources.end());
785 imageres = ReplaceContentsAndReturnID(&dc, size);
786 ASSERT_TRUE(resources.find(imageres) != resources.end());
788 PASS();
791 std::string TestGraphics2D::TestBindNull() {
792 // Binding a null resource is not an error, it should clear all bound
793 // resources. We can't easily test what resource is bound, but we can test
794 // that this doesn't throw an error.
795 ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
796 ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
798 const int w = 115, h = 117;
799 pp::Graphics2D dc(instance_, pp::Size(w, h), false);
800 ASSERT_FALSE(dc.is_null());
801 ASSERT_TRUE(instance_->BindGraphics(dc));
803 ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
804 ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
806 PASS();