123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ppapi/tests/test_graphics_2d.h"
- #include <stdlib.h>
- #include <string.h>
- #include <set>
- #include "ppapi/c/pp_errors.h"
- #include "ppapi/c/ppb_graphics_2d.h"
- #include "ppapi/cpp/completion_callback.h"
- #include "ppapi/cpp/graphics_2d.h"
- #include "ppapi/cpp/graphics_3d.h"
- #include "ppapi/cpp/image_data.h"
- #include "ppapi/cpp/instance.h"
- #include "ppapi/cpp/module.h"
- #include "ppapi/cpp/rect.h"
- #include "ppapi/tests/test_utils.h"
- #include "ppapi/tests/testing_instance.h"
- REGISTER_TEST_CASE(Graphics2D);
- namespace {
- bool CanFlushContext(pp::Instance* instance, pp::Graphics2D* context) {
- TestCompletionCallback callback(instance->pp_instance());
- callback.WaitForResult(context->Flush(callback.GetCallback()));
- return (callback.result() == PP_OK);
- }
- bool CanFlushContextC(pp::Instance* instance, PP_Resource graphics_2d,
- const PPB_Graphics2D_1_2* graphics_2d_if) {
- TestCompletionCallback callback(instance->pp_instance());
- callback.WaitForResult(graphics_2d_if->Flush(
- graphics_2d, callback.GetCallback().pp_completion_callback()));
- return (callback.result() == PP_OK);
- }
- } // namespace
- TestGraphics2D::TestGraphics2D(TestingInstance* instance)
- : TestCase(instance),
- is_view_changed_(false),
- post_quit_on_view_changed_(false) {
- }
- bool TestGraphics2D::Init() {
- graphics_2d_interface_ = static_cast<const PPB_Graphics2D*>(
- pp::Module::Get()->GetBrowserInterface(PPB_GRAPHICS_2D_INTERFACE_1_2));
- image_data_interface_ = static_cast<const PPB_ImageData*>(
- pp::Module::Get()->GetBrowserInterface(PPB_IMAGEDATA_INTERFACE_1_0));
- return graphics_2d_interface_ && image_data_interface_ &&
- CheckTestingInterface();
- }
- void TestGraphics2D::RunTests(const std::string& filter) {
- RUN_TEST(InvalidResource, filter);
- RUN_TEST(InvalidSize, filter);
- RUN_TEST(Humongous, filter);
- RUN_TEST(InitToZero, filter);
- RUN_TEST(Describe, filter);
- RUN_TEST(Scale, filter);
- RUN_TEST_FORCEASYNC_AND_NOT(Paint, filter);
- RUN_TEST_FORCEASYNC_AND_NOT(Scroll, filter);
- RUN_TEST_FORCEASYNC_AND_NOT(Replace, filter);
- RUN_TEST_FORCEASYNC_AND_NOT(Flush, filter);
- RUN_TEST_FORCEASYNC_AND_NOT(FlushOffscreenUpdate, filter);
- RUN_TEST(Dev, filter);
- RUN_TEST(ReplaceContentsCaching, filter);
- RUN_TEST(BindNull, filter);
- }
- void TestGraphics2D::QuitMessageLoop() {
- testing_interface_->QuitMessageLoop(instance_->pp_instance());
- }
- bool TestGraphics2D::ReadImageData(const pp::Graphics2D& dc,
- pp::ImageData* image,
- const pp::Point& top_left) const {
- return PP_ToBool(testing_interface_->ReadImageData(
- dc.pp_resource(),
- image->pp_resource(),
- &top_left.pp_point()));
- }
- bool TestGraphics2D::IsDCUniformColor(const pp::Graphics2D& dc,
- uint32_t color) const {
- pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- dc.size(), false);
- if (readback.is_null())
- return false;
- if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
- return false;
- return IsSquareInImage(readback, 0, pp::Rect(dc.size()), color);
- }
- std::string TestGraphics2D::FlushAndWaitForDone(pp::Graphics2D* context) {
- TestCompletionCallback callback(instance_->pp_instance(), callback_type());
- callback.WaitForResult(context->Flush(callback.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback);
- ASSERT_EQ(PP_OK, callback.result());
- PASS();
- }
- void TestGraphics2D::FillRectInImage(pp::ImageData* image,
- const pp::Rect& rect,
- uint32_t color) const {
- for (int y = rect.y(); y < rect.bottom(); y++) {
- uint32_t* row = image->GetAddr32(pp::Point(rect.x(), y));
- for (int pixel = 0; pixel < rect.width(); pixel++)
- row[pixel] = color;
- }
- }
- void TestGraphics2D::FillImageWithGradient(pp::ImageData* image) const {
- for (int y = 0; y < image->size().height(); y++) {
- uint32_t red = ((y * 256) / image->size().height()) & 0xFF;
- for (int x = 0; x < image->size().width(); x++) {
- uint32_t green = ((x * 256) / image->size().width()) & 0xFF;
- uint32_t blue = ((red + green) / 2) & 0xFF;
- uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
- *pixel = (blue << 24) | (green << 16) | (red << 8);
- }
- }
- }
- bool TestGraphics2D::CompareImages(const pp::ImageData& image1,
- const pp::ImageData& image2) {
- return CompareImageRect(
- image1, pp::Rect(0, 0, image1.size().width(), image1.size().height()),
- image2, pp::Rect(0, 0, image2.size().width(), image2.size().height()));
- }
- bool TestGraphics2D::CompareImageRect(const pp::ImageData& image1,
- const pp::Rect& rc1,
- const pp::ImageData& image2,
- const pp::Rect& rc2) const {
- if (rc1.width() != rc2.width() || rc1.height() != rc2.height())
- return false;
- for (int y = 0; y < rc1.height(); y++) {
- for (int x = 0; x < rc1.width(); x++) {
- if (*(image1.GetAddr32(pp::Point(rc1.x() + x, rc1.y() + y))) !=
- *(image2.GetAddr32(pp::Point(rc2.x() + x, rc2.y() + y))))
- return false;
- }
- }
- return true;
- }
- bool TestGraphics2D::IsSquareInImage(const pp::ImageData& image_data,
- uint32_t background_color,
- const pp::Rect& square,
- uint32_t square_color) const {
- for (int y = 0; y < image_data.size().height(); y++) {
- for (int x = 0; x < image_data.size().width(); x++) {
- uint32_t pixel = *image_data.GetAddr32(pp::Point(x, y));
- uint32_t desired_color;
- if (square.Contains(x, y))
- desired_color = square_color;
- else
- desired_color = background_color;
- if (pixel != desired_color)
- return false;
- }
- }
- return true;
- }
- bool TestGraphics2D::IsSquareInDC(const pp::Graphics2D& dc,
- uint32_t background_color,
- const pp::Rect& square,
- uint32_t square_color) const {
- pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- dc.size(), false);
- if (readback.is_null())
- return false;
- if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
- return false;
- return IsSquareInImage(readback, background_color, square, square_color);
- }
- PP_Resource TestGraphics2D::ReplaceContentsAndReturnID(
- pp::Graphics2D* dc,
- const pp::Size& size) {
- pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, true);
- PP_Resource id = image.pp_resource();
- dc->ReplaceContents(&image);
- std::string result = FlushAndWaitForDone(dc);
- if (!result.empty())
- return 0;
- return id;
- }
- // Test all the functions with an invalid handle. Most of these just check for
- // a crash since the browser don't return a value.
- std::string TestGraphics2D::TestInvalidResource() {
- pp::Graphics2D null_context;
- pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(16, 16), true);
- // Describe.
- PP_Size size;
- PP_Bool opaque;
- graphics_2d_interface_->Describe(image.pp_resource(), &size, &opaque);
- graphics_2d_interface_->Describe(null_context.pp_resource(),
- &size, &opaque);
- // PaintImageData.
- PP_Point zero_zero;
- zero_zero.x = 0;
- zero_zero.y = 0;
- graphics_2d_interface_->PaintImageData(image.pp_resource(),
- image.pp_resource(),
- &zero_zero, NULL);
- graphics_2d_interface_->PaintImageData(null_context.pp_resource(),
- image.pp_resource(),
- &zero_zero, NULL);
- // Scroll.
- PP_Point zero_ten;
- zero_ten.x = 0;
- zero_ten.y = 10;
- graphics_2d_interface_->Scroll(image.pp_resource(), NULL, &zero_ten);
- graphics_2d_interface_->Scroll(null_context.pp_resource(),
- NULL, &zero_ten);
- // ReplaceContents.
- graphics_2d_interface_->ReplaceContents(image.pp_resource(),
- image.pp_resource());
- graphics_2d_interface_->ReplaceContents(null_context.pp_resource(),
- image.pp_resource());
- // Flush.
- TestCompletionCallback cb(instance_->pp_instance(), PP_OPTIONAL);
- cb.WaitForResult(
- graphics_2d_interface_->Flush(image.pp_resource(),
- cb.GetCallback().pp_completion_callback()));
- ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
- cb.WaitForResult(
- graphics_2d_interface_->Flush(null_context.pp_resource(),
- cb.GetCallback().pp_completion_callback()));
- ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
- // ReadImageData.
- ASSERT_FALSE(testing_interface_->ReadImageData(image.pp_resource(),
- image.pp_resource(),
- &zero_zero));
- ASSERT_FALSE(testing_interface_->ReadImageData(null_context.pp_resource(),
- image.pp_resource(),
- &zero_zero));
- PASS();
- }
- std::string TestGraphics2D::TestInvalidSize() {
- pp::Graphics2D a(instance_, pp::Size(16, 0), false);
- ASSERT_FALSE(CanFlushContext(instance_, &a));
- pp::Graphics2D b(instance_, pp::Size(0, 16), false);
- ASSERT_FALSE(CanFlushContext(instance_, &b));
- // Need to use the C API since pp::Size prevents negative sizes.
- PP_Size size;
- size.width = 16;
- size.height = -16;
- PP_Resource graphics = graphics_2d_interface_->Create(
- instance_->pp_instance(), &size, PP_FALSE);
- ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
- pp::Module::Get()->core()->ReleaseResource(graphics);
- size.width = -16;
- size.height = 16;
- graphics = graphics_2d_interface_->Create(
- instance_->pp_instance(), &size, PP_FALSE);
- ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
- pp::Module::Get()->core()->ReleaseResource(graphics);
- // Overflow to negative size
- size.width = std::numeric_limits<int32_t>::max();
- size.height = std::numeric_limits<int32_t>::max();
- graphics = graphics_2d_interface_->Create(
- instance_->pp_instance(), &size, PP_FALSE);
- ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
- pp::Module::Get()->core()->ReleaseResource(graphics);
- PASS();
- }
- std::string TestGraphics2D::TestHumongous() {
- pp::Graphics2D a(instance_, pp::Size(100000, 100000), false);
- ASSERT_FALSE(CanFlushContext(instance_, &a));
- PASS();
- }
- std::string TestGraphics2D::TestInitToZero() {
- const int w = 15, h = 17;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- // Make an image with nonzero data in it (so we can test that zeros were
- // actually read versus ReadImageData being a NOP).
- pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), true);
- ASSERT_FALSE(image.is_null());
- ASSERT_FALSE(image.size().IsEmpty());
- memset(image.data(), 0xFF, image.stride() * image.size().height() * 4);
- // Read out the initial data from the device & check.
- ASSERT_TRUE(ReadImageData(dc, &image, pp::Point(0, 0)));
- ASSERT_TRUE(IsSquareInImage(image, 0, pp::Rect(0, 0, w, h), 0));
- PASS();
- }
- std::string TestGraphics2D::TestDescribe() {
- const int w = 15, h = 17;
- const bool always_opaque = (::rand() % 2 == 1);
- pp::Graphics2D dc(instance_, pp::Size(w, h), always_opaque);
- ASSERT_FALSE(dc.is_null());
- PP_Size size;
- size.width = -1;
- size.height = -1;
- PP_Bool is_always_opaque = PP_FALSE;
- ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
- &is_always_opaque));
- ASSERT_EQ(w, size.width);
- ASSERT_EQ(h, size.height);
- ASSERT_EQ(PP_FromBool(always_opaque), is_always_opaque);
- PASS();
- }
- std::string TestGraphics2D::TestScale() {
- // Tests GetScale/SetScale
- const int w = 20, h = 16;
- const float scale = 1.0f/2.0f;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- ASSERT_EQ(1.0, dc.GetScale());
- ASSERT_TRUE(dc.SetScale(scale));
- ASSERT_EQ(scale, dc.GetScale());
- // Try setting a few invalid scale factors. Ensure that we catch these errors
- // and don't change the actual scale
- ASSERT_FALSE(dc.SetScale(-1.0f));
- ASSERT_FALSE(dc.SetScale(0.0f));
- ASSERT_EQ(scale, dc.GetScale());
- // Verify that the context has the specified number of pixels, despite the
- // non-identity scale
- PP_Size size;
- size.width = -1;
- size.height = -1;
- PP_Bool is_always_opaque = PP_FALSE;
- ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
- &is_always_opaque));
- ASSERT_EQ(w, size.width);
- ASSERT_EQ(h, size.height);
- ASSERT_EQ(PP_FALSE, is_always_opaque);
- PASS();
- }
- std::string TestGraphics2D::TestPaint() {
- const int w = 15, h = 17;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- // Make sure the device background is 0.
- ASSERT_TRUE(IsDCUniformColor(dc, 0));
- // Fill the backing store with white.
- const uint32_t background_color = 0xFFFFFFFF;
- pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), false);
- FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
- dc.PaintImageData(background, pp::Point(0, 0));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- // Make an image to paint with that's opaque white and enqueue a paint.
- const int fill_w = 2, fill_h = 3;
- pp::ImageData fill(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(fill_w, fill_h), true);
- ASSERT_FALSE(fill.is_null());
- FillRectInImage(&fill, pp::Rect(fill.size()), background_color);
- const int paint_x = 4, paint_y = 5;
- dc.PaintImageData(fill, pp::Point(paint_x, paint_y));
- // Validate that nothing has been actually painted.
- ASSERT_TRUE(IsDCUniformColor(dc, background_color));
- // The paint hasn't been flushed so we can still change the bitmap. Fill with
- // 50% blue. This will also verify that the backing store is replaced
- // with the contents rather than blended.
- const uint32_t fill_color = 0x80000080;
- FillRectInImage(&fill, pp::Rect(fill.size()), fill_color);
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(IsSquareInDC(dc, background_color,
- pp::Rect(paint_x, paint_y, fill_w, fill_h),
- fill_color));
- // Reset the DC to blank white & paint our image slightly off the buffer.
- // This should succeed. We also try painting the same thing where the
- // dirty rect falls outeside of the device, which should fail.
- dc.PaintImageData(background, pp::Point(0, 0));
- const int second_paint_x = -1, second_paint_y = -2;
- dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y));
- dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y),
- pp::Rect(-second_paint_x, -second_paint_y, 1, 1));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- // Now we should have a little bit of the image peeking out the top left.
- ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
- fill_color));
- // Now repaint that top left pixel by doing a subset of the source image.
- pp::ImageData subset(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), false);
- uint32_t subset_color = 0x80808080;
- const int subset_x = 2, subset_y = 1;
- *subset.GetAddr32(pp::Point(subset_x, subset_y)) = subset_color;
- dc.PaintImageData(subset, pp::Point(-subset_x, -subset_y),
- pp::Rect(subset_x, subset_y, 1, 1));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
- subset_color));
- PASS();
- }
- std::string TestGraphics2D::TestScroll() {
- const int w = 115, h = 117;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- ASSERT_TRUE(instance_->BindGraphics(dc));
- // Make sure the device background is 0.
- ASSERT_TRUE(IsDCUniformColor(dc, 0));
- const int image_width = 15, image_height = 23;
- pp::ImageData test_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(image_width, image_height), false);
- FillImageWithGradient(&test_image);
- pp::ImageData no_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(image_width, image_height), false);
- FillRectInImage(&no_image, pp::Rect(0, 0, image_width, image_height), 0);
- pp::ImageData readback_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(image_width, image_height), false);
- pp::ImageData readback_scroll(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(image_width, image_height), false);
- ASSERT_EQ(pp::Size(image_width, image_height), test_image.size());
- int image_x = 51, image_y = 72;
- dc.PaintImageData(test_image, pp::Point(image_x, image_y));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- // Test Case 1. Incorrect usage when scrolling image to a free space.
- // The clip area is *not* the area to shift around within the graphics device
- // by specified amount. It's the area to which the scroll is limited. So if
- // the clip area is the size of the image and the amount points to free space,
- // the scroll won't result in additional images.
- int dx = -40, dy = -48;
- int scroll_x = image_x + dx, scroll_y = image_y + dy;
- pp::Rect clip(image_x, image_y, image_width, image_height);
- dc.Scroll(clip, pp::Point(dx, dy));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_TRUE(CompareImages(no_image, readback_scroll));
- // Test Case 2.
- // The amount is intended to place the image in the free space outside
- // of the original, but the clip area extends beyond the graphics device area.
- // This scroll is invalid and will be a noop.
- scroll_x = 11, scroll_y = 24;
- clip = pp::Rect(0, 0, w, h + 1);
- dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_TRUE(CompareImages(no_image, readback_scroll));
- // Test Case 3.
- // The amount is intended to place the image in the free space outside
- // of the original, but the clip area does not cover the image,
- // so there is nothing to scroll.
- scroll_x = 11, scroll_y = 24;
- clip = pp::Rect(0, 0, image_x, image_y);
- dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_TRUE(CompareImages(no_image, readback_scroll));
- // Test Case 4.
- // Same as TC3, but the clip covers part of the image.
- // This part will be scrolled to the intended origin.
- int part_w = image_width / 2, part_h = image_height / 2;
- clip = pp::Rect(0, 0, image_x + part_w, image_y + part_h);
- dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_FALSE(CompareImages(test_image, readback_scroll));
- pp::Rect part_rect(part_w, part_h);
- ASSERT_TRUE(
- CompareImageRect(test_image, part_rect, readback_scroll, part_rect));
- // Test Case 5
- // Same as TC3, but the clip area covers the entire image.
- // It will be scrolled to the intended origin.
- clip = pp::Rect(0, 0, image_x + image_width, image_y + image_height);
- dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_TRUE(CompareImages(test_image, readback_scroll));
- // Note that the undefined area left by the scroll does not actually get
- // cleared, so the original image is still there. This is not guaranteed and
- // is not something for users to rely on, but we can test for this here, so
- // we know when the underlying behavior changes.
- ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
- ASSERT_TRUE(CompareImages(test_image, readback_image));
- // Test Case 6.
- // Scroll image to an overlapping space. The clip area is limited
- // to the image, so this will just modify its area.
- dx = 6;
- dy = 9;
- scroll_x = image_x + dx;
- scroll_y = image_y + dy;
- clip = pp::Rect(image_x, image_y, image_width, image_height);
- dc.Scroll(clip, pp::Point(dx, dy));
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
- ASSERT_FALSE(CompareImages(test_image, readback_image));
- pp::Rect scroll_rect(image_width - dx, image_height - dy);
- ASSERT_TRUE(
- ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
- ASSERT_TRUE(
- CompareImageRect(test_image, scroll_rect, readback_scroll, scroll_rect));
- PASS();
- }
- std::string TestGraphics2D::TestReplace() {
- const int w = 15, h = 17;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- // Replacing with a different size image should fail.
- pp::ImageData weird_size(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w - 1, h), true);
- ASSERT_FALSE(weird_size.is_null());
- dc.ReplaceContents(&weird_size);
- // Fill the background with blue but don't flush yet.
- const uint32_t background_color = 0xFF0000FF;
- pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), true);
- ASSERT_FALSE(background.is_null());
- FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
- dc.PaintImageData(background, pp::Point(0, 0));
- // Replace with a green background but don't flush yet.
- const int32_t swapped_color = 0x00FF00FF;
- pp::ImageData swapped(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), true);
- ASSERT_FALSE(swapped.is_null());
- FillRectInImage(&swapped, pp::Rect(0, 0, w, h), swapped_color);
- dc.ReplaceContents(&swapped);
- // The background should be unchanged since we didn't flush yet.
- ASSERT_TRUE(IsDCUniformColor(dc, 0));
- // Test the C++ wrapper. The size of the swapped image should be reset.
- ASSERT_TRUE(!swapped.pp_resource() && !swapped.size().width() &&
- !swapped.size().height() && !swapped.data());
- // Painting with the swapped image should fail.
- dc.PaintImageData(swapped, pp::Point(0, 0));
- // Flush and make sure the result is correct.
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- // The background should be green from the swapped image.
- ASSERT_TRUE(IsDCUniformColor(dc, swapped_color));
- PASS();
- }
- std::string TestGraphics2D::TestFlush() {
- // Tests that synchronous flushes (NULL callback) fail on the main thread
- // (which is the current one).
- const int w = 15, h = 17;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- // Fill the background with blue but don't flush yet.
- pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
- pp::Size(w, h), true);
- ASSERT_FALSE(background.is_null());
- dc.PaintImageData(background, pp::Point(0, 0));
- int32_t rv = dc.Flush(pp::BlockUntilComplete());
- ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, rv);
- // Test flushing with no operations still issues a callback.
- // (This may also hang if the browser never issues the callback).
- pp::Graphics2D dc_nopaints(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc_nopaints));
- TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
- // Test that multiple flushes fail if we don't get a callback in between.
- rv = dc_nopaints.Flush(callback_1.GetCallback());
- if (rv == PP_OK_COMPLETIONPENDING) {
- // If the first flush completes asynchronously, then a second should fail.
- TestCompletionCallback callback_2(instance_->pp_instance(),
- callback_type());
- callback_2.WaitForResult(dc_nopaints.Flush(callback_2.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(callback_2);
- ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
- }
- callback_1.WaitForResult(rv);
- ASSERT_EQ(PP_OK, callback_1.result());
- PASS();
- }
- void TestGraphics2D::DidChangeView(const pp::View& view) {
- if (post_quit_on_view_changed_) {
- post_quit_on_view_changed_ = false;
- is_view_changed_ = true;
- testing_interface_->QuitMessageLoop(instance_->pp_instance());
- }
- }
- void TestGraphics2D::ResetViewChangedState() {
- is_view_changed_ = false;
- }
- bool TestGraphics2D::WaitUntilViewChanged() {
- // Run a nested run loop. It will exit either on ViewChanged or if the
- // timeout happens.
- // If view changed before we have chance to run message loop, return directly.
- if (is_view_changed_)
- return true;
- post_quit_on_view_changed_ = true;
- testing_interface_->RunMessageLoop(instance_->pp_instance());
- post_quit_on_view_changed_ = false;
- return is_view_changed_;
- }
- std::string TestGraphics2D::TestFlushOffscreenUpdate() {
- // Tests that callback of offscreen updates should be delayed.
- const PP_Time kFlushDelaySec = 1. / 30; // 30 fps
- const int w = 80, h = 80;
- pp::Graphics2D dc(instance_, pp::Size(w, h), true);
- ASSERT_FALSE(dc.is_null());
- ASSERT_TRUE(instance_->BindGraphics(dc));
- // Squeeze from top until bottom half of plugin is out of screen.
- ResetViewChangedState();
- instance_->EvalScript(
- "var big = document.createElement('div');"
- "var offset = "
- " window.innerHeight - plugin.offsetTop - plugin.offsetHeight / 2;"
- "big.setAttribute('id', 'big-div');"
- "big.setAttribute('style', 'height: ' + offset + '; width: 100%;');"
- "document.body.insertBefore(big, document.body.firstChild);");
- ASSERT_TRUE(WaitUntilViewChanged());
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- // Allocate a red image chunk
- pp::ImageData chunk(instance_, PP_IMAGEDATAFORMAT_RGBA_PREMUL,
- pp::Size(w/8, h/8), true);
- ASSERT_FALSE(chunk.is_null());
- const uint32_t kRed = 0xff0000ff;
- FillRectInImage(&chunk, pp::Rect(chunk.size()), kRed);
- // Paint a invisable chunk, expecting Flush to invoke callback slowly.
- dc.PaintImageData(chunk, pp::Point(0, h*0.75));
- PP_Time begin = pp::Module::Get()->core()->GetTime();
- ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
- PP_Time actual_time_elapsed = pp::Module::Get()->core()->GetTime() - begin;
- // Expect actual_time_elapsed >= kFlushDelaySec, but loose a bit to avoid
- // precision issue.
- ASSERT_GE(actual_time_elapsed, kFlushDelaySec * 0.9);
- // Remove the padding on the top since test cases here isn't independent.
- instance_->EvalScript(
- "var big = document.getElementById('big-div');"
- "big.parentNode.removeChild(big);");
- ResetViewChangedState();
- ASSERT_TRUE(WaitUntilViewChanged());
- PASS();
- }
- std::string TestGraphics2D::TestDev() {
- // Tests GetScale/SetScale via the Graphics2D_Dev C++ wrapper
- const int w = 20, h = 16;
- const float scale = 1.0f/2.0f;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- ASSERT_EQ(1.0f, dc.GetScale());
- ASSERT_TRUE(dc.SetScale(scale));
- ASSERT_EQ(scale, dc.GetScale());
- // Try setting a few invalid scale factors. Ensure that we catch these errors
- // and don't change the actual scale
- ASSERT_FALSE(dc.SetScale(-1.0f));
- ASSERT_FALSE(dc.SetScale(0.0f));
- ASSERT_EQ(scale, dc.GetScale());
- // Verify that the context has the specified number of pixels, despite the
- // non-identity scale
- PP_Size size;
- size.width = -1;
- size.height = -1;
- PP_Bool is_always_opaque = PP_FALSE;
- ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
- &is_always_opaque));
- ASSERT_EQ(w, size.width);
- ASSERT_EQ(h, size.height);
- ASSERT_EQ(PP_FALSE, is_always_opaque);
- PASS();
- }
- // This test makes sure that the out-of-process image data caching works as
- // expected. Doing ReplaceContents quickly should re-use the image data from
- // older ones.
- std::string TestGraphics2D::TestReplaceContentsCaching() {
- // The cache is only active when running in the proxy, so skip it otherwise.
- if (!testing_interface_->IsOutOfProcess())
- PASS();
- // Here we test resource IDs as a way to determine if the resource is being
- // cached and re-used. This is non-optimal since it's entirely possible
- // (and maybe better) for the proxy to return new resource IDs for the
- // re-used objects. Howevever, our current implementation does this so it is
- // an easy thing to check for.
- //
- // You could check for the shared memory pointers getting re-used, but the
- // OS is very likely to use the same memory location for a newly-mapped image
- // if one was deleted, meaning that it could pass even if the cache is broken.
- // This would then require that we add some address-re-use-preventing code
- // which would be tricky.
- std::set<PP_Resource> resources;
- pp::Size size(16, 16);
- pp::Graphics2D dc(instance_, size, false);
- // Do two replace contentses, adding the old resource IDs to our map.
- PP_Resource imageres = ReplaceContentsAndReturnID(&dc, size);
- ASSERT_TRUE(imageres);
- resources.insert(imageres);
- imageres = ReplaceContentsAndReturnID(&dc, size);
- ASSERT_TRUE(imageres);
- resources.insert(imageres);
- // Now doing more replace contents should re-use older IDs if the cache is
- // working.
- imageres = ReplaceContentsAndReturnID(&dc, size);
- ASSERT_TRUE(resources.find(imageres) != resources.end());
- imageres = ReplaceContentsAndReturnID(&dc, size);
- ASSERT_TRUE(resources.find(imageres) != resources.end());
- PASS();
- }
- std::string TestGraphics2D::TestBindNull() {
- // Binding a null resource is not an error, it should clear all bound
- // resources. We can't easily test what resource is bound, but we can test
- // that this doesn't throw an error.
- ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
- ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
- const int w = 115, h = 117;
- pp::Graphics2D dc(instance_, pp::Size(w, h), false);
- ASSERT_FALSE(dc.is_null());
- ASSERT_TRUE(instance_->BindGraphics(dc));
- ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
- ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
- PASS();
- }
|