15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/tests/test_graphics_2d.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/dev/ppb_testing_dev.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/pp_errors.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/ppb_graphics_2d.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/completion_callback.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/dev/graphics_2d_dev.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/cpp/dev/graphics_2d_dev.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/graphics_2d.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/cpp/graphics_3d.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/image_data.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/instance.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/rect.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ppapi/tests/test_utils.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/tests/testing_instance.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)REGISTER_TEST_CASE(Graphics2D);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A NOP flush callback for use in various tests.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FlushCallbackNOP(void* data, int32_t result) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FlushCallbackQuitMessageLoop(void* data, int32_t result) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static_cast<TestGraphics2D*>(data)->QuitMessageLoop();
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CanFlushContext(pp::Instance* instance, pp::Graphics2D* context) {
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestCompletionCallback callback(instance->pp_instance());
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.WaitForResult(context->Flush(callback.GetCallback()));
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (callback.result() == PP_OK);
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool CanFlushContextC(pp::Instance* instance, PP_Resource graphics_2d,
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      const PPB_Graphics2D_1_1* graphics_2d_if) {
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestCompletionCallback callback(instance->pp_instance());
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback.WaitForResult(graphics_2d_if->Flush(
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      graphics_2d, callback.GetCallback().pp_completion_callback()));
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return (callback.result() == PP_OK);
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TestGraphics2D::TestGraphics2D(TestingInstance* instance)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  : TestCase(instance),
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_view_changed_(false),
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    post_quit_on_view_changed_(false) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::Init() {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_ = static_cast<const PPB_Graphics2D*>(
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pp::Module::Get()->GetBrowserInterface(PPB_GRAPHICS_2D_INTERFACE_1_1));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  image_data_interface_ = static_cast<const PPB_ImageData*>(
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      pp::Module::Get()->GetBrowserInterface(PPB_IMAGEDATA_INTERFACE_1_0));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return graphics_2d_interface_ && image_data_interface_ &&
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         CheckTestingInterface();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::RunTests(const std::string& filter) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(InvalidResource, filter);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(InvalidSize, filter);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(Humongous, filter);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(InitToZero, filter);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(Describe, filter);
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RUN_TEST(Scale, filter);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST_FORCEASYNC_AND_NOT(Paint, filter);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST_FORCEASYNC_AND_NOT(Scroll, filter);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST_FORCEASYNC_AND_NOT(Replace, filter);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST_FORCEASYNC_AND_NOT(Flush, filter);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST_FORCEASYNC_AND_NOT(FlushOffscreenUpdate, filter);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(Dev, filter);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RUN_TEST(ReplaceContentsCaching, filter);
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RUN_TEST(BindNull, filter);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::QuitMessageLoop() {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testing_interface_->QuitMessageLoop(instance_->pp_instance());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::ReadImageData(const pp::Graphics2D& dc,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   pp::ImageData* image,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const pp::Point& top_left) const {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PP_ToBool(testing_interface_->ReadImageData(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dc.pp_resource(),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image->pp_resource(),
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &top_left.pp_point()));
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::IsDCUniformColor(const pp::Graphics2D& dc,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      uint32_t color) const {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         dc.size(), false);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (readback.is_null())
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsSquareInImage(readback, 0, pp::Rect(dc.size()), color);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string TestGraphics2D::FlushAndWaitForDone(pp::Graphics2D* context) {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestCompletionCallback callback(instance_->pp_instance(), callback_type());
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.WaitForResult(context->Flush(callback.GetCallback()));
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK_CALLBACK_BEHAVIOR(callback);
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_OK, callback.result());
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PASS();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::FillRectInImage(pp::ImageData* image,
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const pp::Rect& rect,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     uint32_t color) const {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = rect.y(); y < rect.bottom(); y++) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* row = image->GetAddr32(pp::Point(rect.x(), y));
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int pixel = 0; pixel < rect.width(); pixel++)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      row[pixel] = color;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::FillImageWithGradient(pp::ImageData* image) const {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = 0; y < image->size().height(); y++) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t red = ((y * 256) / image->size().height()) & 0xFF;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = 0; x < image->size().width(); x++) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32_t green = ((x * 256) / image->size().width()) & 0xFF;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32_t blue = ((red + green) / 2) & 0xFF;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32_t* pixel = image->GetAddr32(pp::Point(x, y));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *pixel = (blue << 24) | (green << 16) | (red << 8);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::CompareImages(const pp::ImageData& image1,
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   const pp::ImageData& image2) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CompareImageRect(
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image1, pp::Rect(0, 0, image1.size().width(), image1.size().height()),
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      image2, pp::Rect(0, 0, image2.size().width(), image2.size().height()));
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::CompareImageRect(const pp::ImageData& image1,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const pp::Rect& rc1,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const pp::ImageData& image2,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const pp::Rect& rc2) const {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rc1.width() != rc2.width() || rc1.height() != rc2.height())
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = 0; y < rc1.height(); y++) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = 0; x < rc1.width(); x++) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (*(image1.GetAddr32(pp::Point(rc1.x() + x, rc1.y() + y))) !=
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          *(image2.GetAddr32(pp::Point(rc2.x() + x, rc2.y() + y))))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::IsSquareInImage(const pp::ImageData& image_data,
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     uint32_t background_color,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     const pp::Rect& square,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     uint32_t square_color) const {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int y = 0; y < image_data.size().height(); y++) {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (int x = 0; x < image_data.size().width(); x++) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32_t pixel = *image_data.GetAddr32(pp::Point(x, y));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      uint32_t desired_color;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (square.Contains(x, y))
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        desired_color = square_color;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        desired_color = background_color;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (pixel != desired_color)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::IsSquareInDC(const pp::Graphics2D& dc,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  uint32_t background_color,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const pp::Rect& square,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  uint32_t square_color) const {
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData readback(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         dc.size(), false);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (readback.is_null())
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadImageData(dc, &readback, pp::Point(0, 0)))
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsSquareInImage(readback, background_color, square, square_color);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PP_Resource TestGraphics2D::ReplaceContentsAndReturnID(
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pp::Graphics2D* dc,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const pp::Size& size) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, true);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Resource id = image.pp_resource();
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc->ReplaceContents(&image);
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string result = FlushAndWaitForDone(dc);
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!result.empty())
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Test all the functions with an invalid handle. Most of these just check for
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a crash since the browser don't return a value.
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestInvalidResource() {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D null_context;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      pp::Size(16, 16), true);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Describe.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Size size;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Bool opaque;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->Describe(image.pp_resource(), &size, &opaque);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->Describe(null_context.pp_resource(),
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   &size, &opaque);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PaintImageData.
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Point zero_zero;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zero_zero.x = 0;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zero_zero.y = 0;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->PaintImageData(image.pp_resource(),
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         image.pp_resource(),
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &zero_zero, NULL);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->PaintImageData(null_context.pp_resource(),
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         image.pp_resource(),
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         &zero_zero, NULL);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Scroll.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Point zero_ten;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zero_ten.x = 0;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zero_ten.y = 10;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->Scroll(image.pp_resource(), NULL, &zero_ten);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->Scroll(null_context.pp_resource(),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 NULL, &zero_ten);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ReplaceContents.
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->ReplaceContents(image.pp_resource(),
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          image.pp_resource());
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  graphics_2d_interface_->ReplaceContents(null_context.pp_resource(),
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          image.pp_resource());
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush.
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestCompletionCallback cb(instance_->pp_instance(), PP_OPTIONAL);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cb.WaitForResult(
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      graphics_2d_interface_->Flush(image.pp_resource(),
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    cb.GetCallback().pp_completion_callback()));
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  cb.WaitForResult(
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      graphics_2d_interface_->Flush(null_context.pp_resource(),
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    cb.GetCallback().pp_completion_callback()));
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_ERROR_BADRESOURCE, cb.result());
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ReadImageData.
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(testing_interface_->ReadImageData(image.pp_resource(),
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 image.pp_resource(),
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 &zero_zero));
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(testing_interface_->ReadImageData(null_context.pp_resource(),
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 image.pp_resource(),
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 &zero_zero));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestInvalidSize() {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D a(instance_, pp::Size(16, 0), false);
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContext(instance_, &a));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D b(instance_, pp::Size(0, 16), false);
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContext(instance_, &b));
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Need to use the C API since pp::Size prevents negative sizes.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Size size;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.width = 16;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.height = -16;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PP_Resource graphics = graphics_2d_interface_->Create(
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      instance_->pp_instance(), &size, PP_FALSE);
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Module::Get()->core()->ReleaseResource(graphics);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.width = -16;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.height = 16;
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  graphics = graphics_2d_interface_->Create(
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      instance_->pp_instance(), &size, PP_FALSE);
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Module::Get()->core()->ReleaseResource(graphics);
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Overflow to negative size
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size.width = std::numeric_limits<int32_t>::max();
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size.height = std::numeric_limits<int32_t>::max();
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  graphics = graphics_2d_interface_->Create(
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      instance_->pp_instance(), &size, PP_FALSE);
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContextC(instance_, graphics, graphics_2d_interface_));
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Module::Get()->core()->ReleaseResource(graphics);
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestHumongous() {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D a(instance_, pp::Size(100000, 100000), false);
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CanFlushContext(instance_, &a));
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestInitToZero() {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 15, h = 17;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make an image with nonzero data in it (so we can test that zeros were
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // actually read versus ReadImageData being a NOP).
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      pp::Size(w, h), true);
323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(image.is_null());
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(image.size().IsEmpty());
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(image.data(), 0xFF, image.stride() * image.size().height() * 4);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read out the initial data from the device & check.
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(ReadImageData(dc, &image, pp::Point(0, 0)));
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsSquareInImage(image, 0, pp::Rect(0, 0, w, h), 0));
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestDescribe() {
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 15, h = 17;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool always_opaque = (::rand() % 2 == 1);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), always_opaque);
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Size size;
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.width = -1;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.height = -1;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Bool is_always_opaque = PP_FALSE;
344c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               &is_always_opaque));
346c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(w, size.width);
347c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(h, size.height);
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_FromBool(always_opaque), is_always_opaque);
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
350c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PASS();
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string TestGraphics2D::TestScale() {
354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Tests GetScale/SetScale
355c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const int w = 20, h = 16;
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const float scale = 1.0f/2.0f;
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(1.0,  dc.GetScale());
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(dc.SetScale(scale));
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(scale, dc.GetScale());
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Try setting a few invalid scale factors. Ensure that we catch these errors
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // and don't change the actual scale
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.SetScale(-1.0f));
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.SetScale(0.0f));
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(scale, dc.GetScale());
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Verify that the context has the specified number of pixels, despite the
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // non-identity scale
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PP_Size size;
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size.width = -1;
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size.height = -1;
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PP_Bool is_always_opaque = PP_FALSE;
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(graphics_2d_interface_->Describe(dc.pp_resource(), &size,
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               &is_always_opaque));
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(w, size.width);
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(h, size.height);
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_FALSE, is_always_opaque);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestPaint() {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 15, h = 17;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the device background is 0.
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsDCUniformColor(dc, 0));
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the backing store with white.
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint32_t background_color = 0xFFFFFFFF;
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           pp::Size(w, h), false);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(background, pp::Point(0, 0));
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make an image to paint with that's opaque white and enqueue a paint.
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int fill_w = 2, fill_h = 3;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData fill(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     pp::Size(fill_w, fill_h), true);
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(fill.is_null());
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&fill, pp::Rect(fill.size()), background_color);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int paint_x = 4, paint_y = 5;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(fill, pp::Point(paint_x, paint_y));
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate that nothing has been actually painted.
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsDCUniformColor(dc, background_color));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The paint hasn't been flushed so we can still change the bitmap. Fill with
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 50% blue. This will also verify that the backing store is replaced
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // with the contents rather than blended.
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint32_t fill_color = 0x80000080;
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&fill, pp::Rect(fill.size()), fill_color);
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsSquareInDC(dc, background_color,
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           pp::Rect(paint_x, paint_y, fill_w, fill_h),
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           fill_color));
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset the DC to blank white & paint our image slightly off the buffer.
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This should succeed. We also try painting the same thing where the
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // dirty rect falls outeside of the device, which should fail.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(background, pp::Point(0, 0));
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int second_paint_x = -1, second_paint_y = -2;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y));
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(fill, pp::Point(second_paint_x, second_paint_y),
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    pp::Rect(-second_paint_x, -second_paint_y, 1, 1));
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we should have a little bit of the image peeking out the top left.
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           fill_color));
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now repaint that top left pixel by doing a subset of the source image.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData subset(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       pp::Size(w, h), false);
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32_t subset_color = 0x80808080;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int subset_x = 2, subset_y = 1;
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *subset.GetAddr32(pp::Point(subset_x, subset_y)) = subset_color;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(subset, pp::Point(-subset_x, -subset_y),
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    pp::Rect(subset_x, subset_y, 1, 1));
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsSquareInDC(dc, background_color, pp::Rect(0, 0, 1, 1),
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           subset_color));
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestScroll() {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 115, h = 117;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(dc));
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure the device background is 0.
458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsDCUniformColor(dc, 0));
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int image_width = 15, image_height = 23;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData test_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           pp::Size(image_width, image_height), false);
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillImageWithGradient(&test_image);
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData no_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         pp::Size(image_width, image_height), false);
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&no_image, pp::Rect(0, 0, image_width, image_height), 0);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData readback_image(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               pp::Size(image_width, image_height), false);
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData readback_scroll(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                pp::Size(image_width, image_height), false);
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(pp::Size(image_width, image_height), test_image.size());
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int image_x = 51, image_y = 72;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(test_image, pp::Point(image_x, image_y));
476c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 1. Incorrect usage when scrolling image to a free space.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The clip area is *not* the area to shift around within the graphics device
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // by specified amount. It's the area to which the scroll is limited. So if
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the clip area is the size of the image and the amount points to free space,
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the scroll won't result in additional images.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int dx = -40, dy = -48;
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int scroll_x = image_x + dx, scroll_y = image_y + dy;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Rect clip(image_x, image_y, image_width, image_height);
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(dx, dy));
487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
488c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CompareImages(no_image, readback_scroll));
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 2.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The amount is intended to place the image in the free space outside
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the original, but the clip area extends beyond the graphics device area.
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This scroll is invalid and will be a noop.
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_x = 11, scroll_y = 24;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip = pp::Rect(0, 0, w, h + 1);
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
499c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
501c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
502c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CompareImages(no_image, readback_scroll));
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 3.
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The amount is intended to place the image in the free space outside
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the original, but the clip area does not cover the image,
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so there is nothing to scroll.
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_x = 11, scroll_y = 24;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip = pp::Rect(0, 0, image_x, image_y);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
514c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CompareImages(no_image, readback_scroll));
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 4.
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Same as TC3, but the clip covers part of the image.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This part will be scrolled to the intended origin.
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int part_w = image_width / 2, part_h = image_height / 2;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip = pp::Rect(0, 0, image_x + part_w, image_y + part_h);
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
522c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
523c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
524c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CompareImages(test_image, readback_scroll));
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Rect part_rect(part_w, part_h);
527c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
528c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompareImageRect(test_image, part_rect, readback_scroll, part_rect));
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 5
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Same as TC3, but the clip area covers the entire image.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It will be scrolled to the intended origin.
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip = pp::Rect(0, 0, image_x + image_width, image_y + image_height);
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(scroll_x - image_x, scroll_y - image_y));
535c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
536c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
538c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CompareImages(test_image, readback_scroll));
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that the undefined area left by the scroll does not actually get
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cleared, so the original image is still there. This is not guaranteed and
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is not something for users to rely on, but we can test for this here, so
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we know when the underlying behavior changes.
544c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
545c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(CompareImages(test_image, readback_image));
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test Case 6.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Scroll image to an overlapping space. The clip area is limited
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the image, so this will just modify its area.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dx = 6;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dy = 9;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_x = image_x + dx;
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scroll_y = image_y + dy;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clip = pp::Rect(image_x, image_y, image_width, image_height);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.Scroll(clip, pp::Point(dx, dy));
556c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
557c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(ReadImageData(dc, &readback_image, pp::Point(image_x, image_y)));
558c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(CompareImages(test_image, readback_image));
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Rect scroll_rect(image_width - dx, image_height - dy);
560c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
561c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReadImageData(dc, &readback_scroll, pp::Point(scroll_x, scroll_y)));
562c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(
563c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CompareImageRect(test_image, scroll_rect, readback_scroll, scroll_rect));
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestReplace() {
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 15, h = 17;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
571c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replacing with a different size image should fail.
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData weird_size(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           pp::Size(w - 1, h), true);
576c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(weird_size.is_null());
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.ReplaceContents(&weird_size);
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the background with blue but don't flush yet.
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int32_t background_color = 0xFF0000FF;
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           pp::Size(w, h), true);
583c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(background.is_null());
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&background, pp::Rect(0, 0, w, h), background_color);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(background, pp::Point(0, 0));
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Replace with a green background but don't flush yet.
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int32_t swapped_color = 0x00FF00FF;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData swapped(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        pp::Size(w, h), true);
591c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(swapped.is_null());
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&swapped, pp::Rect(0, 0, w, h), swapped_color);
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.ReplaceContents(&swapped);
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The background should be unchanged since we didn't flush yet.
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsDCUniformColor(dc, 0));
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test the C++ wrapper. The size of the swapped image should be reset.
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(!swapped.pp_resource() && !swapped.size().width() &&
600c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)              !swapped.size().height() && !swapped.data());
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Painting with the swapped image should fail.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(swapped, pp::Point(0, 0));
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Flush and make sure the result is correct.
606c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The background should be green from the swapped image.
609c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(IsDCUniformColor(dc, swapped_color));
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestFlush() {
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tests that synchronous flushes (NULL callback) fail on the main thread
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (which is the current one).
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 15, h = 17;
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
619c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fill the background with blue but don't flush yet.
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData background(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           pp::Size(w, h), true);
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(background.is_null());
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(background, pp::Point(0, 0));
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int32_t rv = dc.Flush(pp::BlockUntilComplete());
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_ERROR_BLOCKS_MAIN_THREAD, rv);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test flushing with no operations still issues a callback.
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (This may also hang if the browser never issues the callback).
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc_nopaints(instance_, pp::Size(w, h), false);
633c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
634c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc_nopaints));
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
636c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestCompletionCallback callback_1(instance_->pp_instance(), callback_type());
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test that multiple flushes fail if we don't get a callback in between.
639c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  rv = dc_nopaints.Flush(callback_1.GetCallback());
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv == PP_OK_COMPLETIONPENDING) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the first flush completes asynchronously, then a second should fail.
642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    TestCompletionCallback callback_2(instance_->pp_instance(),
643c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                      callback_type());
644c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    callback_2.WaitForResult(dc_nopaints.Flush(callback_2.GetCallback()));
645c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CHECK_CALLBACK_BEHAVIOR(callback_2);
646c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ASSERT_EQ(PP_ERROR_INPROGRESS, callback_2.result());
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  callback_1.WaitForResult(rv);
649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_OK, callback_1.result());
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::DidChangeView(const pp::View& view) {
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (post_quit_on_view_changed_) {
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    post_quit_on_view_changed_ = false;
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    is_view_changed_ = true;
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    testing_interface_->QuitMessageLoop(instance_->pp_instance());
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestGraphics2D::ResetViewChangedState() {
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_view_changed_ = false;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool TestGraphics2D::WaitUntilViewChanged() {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Run a nested message loop. It will exit either on ViewChanged or if the
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // timeout happens.
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If view changed before we have chance to run message loop, return directly.
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_view_changed_)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  post_quit_on_view_changed_ = true;
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  testing_interface_->RunMessageLoop(instance_->pp_instance());
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  post_quit_on_view_changed_ = false;
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return is_view_changed_;
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestFlushOffscreenUpdate() {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tests that callback of offscreen updates should be delayed.
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PP_Time kFlushDelaySec = 1. / 30;  // 30 fps
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 80, h = 80;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), true);
686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
687c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(dc));
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Squeeze from top until bottom half of plugin is out of screen.
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetViewChangedState();
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instance_->EvalScript(
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "var big = document.createElement('div');"
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "var offset = "
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "    window.innerHeight - plugin.offsetTop - plugin.offsetHeight / 2;"
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "big.setAttribute('id', 'big-div');"
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "big.setAttribute('style', 'height: ' + offset + '; width: 100%;');"
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "document.body.insertBefore(big, document.body.firstChild);");
698c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(WaitUntilViewChanged());
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate a red image chunk
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::ImageData chunk(instance_, PP_IMAGEDATAFORMAT_RGBA_PREMUL,
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      pp::Size(w/8, h/8), true);
703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(chunk.is_null());
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint32_t kRed = 0xff0000ff;
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillRectInImage(&chunk, pp::Rect(chunk.size()), kRed);
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Paint a invisable chunk, expecting Flush to invoke callback slowly.
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dc.PaintImageData(chunk, pp::Point(0, h*0.75));
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Time begin = pp::Module::Get()->core()->GetTime();
711c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_SUBTEST_SUCCESS(FlushAndWaitForDone(&dc));
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Time actual_time_elapsed = pp::Module::Get()->core()->GetTime() - begin;
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Expect actual_time_elapsed >= kFlushDelaySec, but loose a bit to avoid
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // precision issue.
715c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_GE(actual_time_elapsed, kFlushDelaySec * 0.9);
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove the padding on the top since test cases here isn't independent.
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instance_->EvalScript(
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "var big = document.getElementById('big-div');"
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "big.parentNode.removeChild(big);");
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetViewChangedState();
722c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(WaitUntilViewChanged());
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestDev() {
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Tests GetScale/SetScale via the Graphics2D_Dev C++ wrapper
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int w = 20, h = 16;
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const float scale = 1.0f/2.0f;
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
732c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D_Dev dc_dev(dc);
734c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(1.0f, dc_dev.GetScale());
735c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(dc_dev.SetScale(scale));
736c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(scale, dc_dev.GetScale());
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try setting a few invalid scale factors. Ensure that we catch these errors
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and don't change the actual scale
739c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc_dev.SetScale(-1.0f));
740c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc_dev.SetScale(0.0f));
741c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(scale, dc_dev.GetScale());
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the context has the specified number of pixels, despite the
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-identity scale
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Size size;
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.width = -1;
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.height = -1;
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Bool is_always_opaque = PP_FALSE;
749c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(graphics_2d_interface_->Describe(dc_dev.pp_resource(), &size,
750c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               &is_always_opaque));
751c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(w, size.width);
752c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(h, size.height);
753c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_EQ(PP_FALSE, is_always_opaque);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This test makes sure that the out-of-process image data caching works as
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expected. Doing ReplaceContents quickly should re-use the image data from
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// older ones.
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string TestGraphics2D::TestReplaceContentsCaching() {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The cache is only active when running in the proxy, so skip it otherwise.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!testing_interface_->IsOutOfProcess())
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PASS();
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Here we test resource IDs as a way to determine if the resource is being
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // cached and re-used. This is non-optimal since it's entirely possible
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (and maybe better) for the proxy to return new resource IDs for the
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // re-used objects. Howevever, our current implementation does this so it is
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an easy thing to check for.
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // You could check for the shared memory pointers getting re-used, but the
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OS is very likely to use the same memory location for a newly-mapped image
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if one was deleted, meaning that it could pass even if the cache is broken.
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This would then require that we add some address-re-use-preventing code
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // which would be tricky.
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<PP_Resource> resources;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Size size(16, 16);
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pp::Graphics2D dc(instance_, size, false);
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do two replace contentses, adding the old resource IDs to our map.
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PP_Resource imageres = ReplaceContentsAndReturnID(&dc, size);
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(imageres);
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resources.insert(imageres);
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  imageres = ReplaceContentsAndReturnID(&dc, size);
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(imageres);
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resources.insert(imageres);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now doing more replace contents should re-use older IDs if the cache is
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // working.
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  imageres = ReplaceContentsAndReturnID(&dc, size);
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(resources.find(imageres) != resources.end());
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  imageres = ReplaceContentsAndReturnID(&dc, size);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(resources.find(imageres) != resources.end());
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PASS();
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string TestGraphics2D::TestBindNull() {
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Binding a null resource is not an error, it should clear all bound
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // resources. We can't easily test what resource is bound, but we can test
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that this doesn't throw an error.
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int w = 115, h = 117;
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pp::Graphics2D dc(instance_, pp::Size(w, h), false);
809c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_FALSE(dc.is_null());
810c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(dc));
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(pp::Graphics2D()));
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(instance_->BindGraphics(pp::Graphics3D()));
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PASS();
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
818