• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ppapi/tests/test_view.h"
6 
7 #include <sstream>
8 
9 #include "ppapi/c/pp_time.h"
10 #include "ppapi/c/private/ppb_testing_private.h"
11 #include "ppapi/cpp/completion_callback.h"
12 #include "ppapi/tests/testing_instance.h"
13 
14 REGISTER_TEST_CASE(View);
15 
16 // When waiting for view changed events, wait no longer than this.
17 static int kViewChangeTimeoutSec = 5;
18 
TestView(TestingInstance * instance)19 TestView::TestView(TestingInstance* instance)
20     : TestCase(instance),
21       post_quit_on_view_changed_(false) {
22 }
23 
DidChangeView(const pp::View & view)24 void TestView::DidChangeView(const pp::View& view) {
25   last_view_ = view;
26   page_visibility_log_.push_back(view.IsPageVisible());
27 
28   if (post_quit_on_view_changed_) {
29     post_quit_on_view_changed_ = false;
30     testing_interface_->QuitMessageLoop(instance_->pp_instance());
31   }
32 }
33 
Init()34 bool TestView::Init() {
35   return CheckTestingInterface();
36 }
37 
RunTests(const std::string & filter)38 void TestView::RunTests(const std::string& filter) {
39   RUN_TEST(CreatedVisible, filter);
40   RUN_TEST(CreatedInvisible, filter);
41   RUN_TEST(PageHideShow, filter);
42   RUN_TEST(SizeChange, filter);
43   RUN_TEST(ClipChange, filter);
44 }
45 
WaitUntilViewChanged()46 bool TestView::WaitUntilViewChanged() {
47   // Schedule a callback so this step times out if we don't get a ViewChanged
48   // in a reasonable amount of time.
49   pp::CompletionCallbackFactory<TestView> factory(this);
50   pp::CompletionCallback timeout =
51       factory.NewCallback(&TestView::QuitMessageLoop);
52   pp::Module::Get()->core()->CallOnMainThread(
53       kViewChangeTimeoutSec * 1000, timeout);
54 
55   size_t old_page_visibility_change_count = page_visibility_log_.size();
56 
57   // Run a nested message loop. It will exit either on ViewChanged or if the
58   // timeout happens.
59   post_quit_on_view_changed_ = true;
60   testing_interface_->RunMessageLoop(instance_->pp_instance());
61   post_quit_on_view_changed_ = false;
62 
63   // We know we got a view changed event if something was appended to the log.
64   return page_visibility_log_.size() > old_page_visibility_change_count;
65 }
66 
QuitMessageLoop(int32_t result)67 void TestView::QuitMessageLoop(int32_t result) {
68   testing_interface_->QuitMessageLoop(instance_->pp_instance());
69 }
70 
TestCreatedVisible()71 std::string TestView::TestCreatedVisible() {
72   ASSERT_FALSE(page_visibility_log_.empty());
73   ASSERT_TRUE(page_visibility_log_[0]);
74   PASS();
75 }
76 
TestCreatedInvisible()77 std::string TestView::TestCreatedInvisible() {
78   ASSERT_FALSE(page_visibility_log_.empty());
79 
80   if (page_visibility_log_[0]) {
81     // Add more error message since this test has some extra requirements.
82     instance_->AppendError("Initial page is set to visible. NOTE: "
83         "This test must be run in a background tab. "
84         "Either run in the UI test which does this, or you can middle-click "
85         "on the test link to run manually.");
86   }
87   ASSERT_FALSE(page_visibility_log_[0]);
88   PASS();
89 }
90 
TestPageHideShow()91 std::string TestView::TestPageHideShow() {
92   // Initial state should be visible.
93   ASSERT_FALSE(page_visibility_log_.empty());
94   ASSERT_TRUE(page_visibility_log_[0]);
95 
96   // Now that we're alive, tell the test knows it can change our visibility.
97   instance_->ReportProgress("TestPageHideShow:Created");
98 
99   // Wait until we get a hide event, being careful to handle spurious
100   // notifications of ViewChanged.
101   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
102   while (WaitUntilViewChanged() &&
103          page_visibility_log_[page_visibility_log_.size() - 1] &&
104          pp::Module::Get()->core()->GetTime() - begin_time <
105              kViewChangeTimeoutSec) {
106   }
107   if (page_visibility_log_[page_visibility_log_.size() - 1]) {
108     // Didn't get a view changed event that changed visibility (though there
109     // may have been some that didn't change visibility).
110     // Add more error message since this test has some extra requirements.
111     return "Didn't receive a hide event in timeout. NOTE: "
112         "This test requires tab visibility to change and won't pass if you "
113         "just run it in a browser. Normally the UI test should handle "
114         "this. You can also run manually by waiting 2 secs, creating a new "
115         "tab, waiting 2 more secs, and closing the new tab.";
116   }
117 
118   // Tell the test so it can show us again.
119   instance_->ReportProgress("TestPageHideShow:Hidden");
120 
121   // Wait until we get a show event.
122   begin_time = pp::Module::Get()->core()->GetTime();
123   while (WaitUntilViewChanged() &&
124          !page_visibility_log_[page_visibility_log_.size() - 1] &&
125          pp::Module::Get()->core()->GetTime() - begin_time <
126              kViewChangeTimeoutSec) {
127   }
128   ASSERT_TRUE(page_visibility_log_[page_visibility_log_.size() - 1]);
129 
130   PASS();
131 }
132 
TestSizeChange()133 std::string TestView::TestSizeChange() {
134   pp::Rect original_rect = last_view_.GetRect();
135 
136   pp::Rect desired_rect = original_rect;
137   desired_rect.set_width(original_rect.width() + 10);
138   desired_rect.set_height(original_rect.height() + 12);
139 
140   std::ostringstream script_stream;
141   script_stream << "var plugin = document.getElementById('plugin');";
142   script_stream << "plugin.setAttribute('width', "
143                 << desired_rect.width() << ");";
144   script_stream << "plugin.setAttribute('height', "
145                 << desired_rect.height() << ");";
146 
147   instance_->EvalScript(script_stream.str());
148 
149   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
150   while (WaitUntilViewChanged() && last_view_.GetRect() != desired_rect &&
151          pp::Module::Get()->core()->GetTime() - begin_time <
152              kViewChangeTimeoutSec) {
153   }
154   ASSERT_TRUE(last_view_.GetRect() == desired_rect);
155 
156   PASS();
157 }
158 
TestClipChange()159 std::string TestView::TestClipChange() {
160   pp::Rect original_rect = last_view_.GetRect();
161 
162   // Original clip should be the full frame.
163   pp::Rect original_clip = last_view_.GetClipRect();
164   ASSERT_TRUE(original_clip.x() == 0);
165   ASSERT_TRUE(original_clip.y() == 0);
166   ASSERT_TRUE(original_clip.width() == original_rect.width());
167   ASSERT_TRUE(original_clip.height() == original_rect.height());
168 
169   int clip_amount = original_rect.height() / 2;
170 
171   // It might be nice to set the position to be absolute and set the location,
172   // but this will cause WebKit to actually tear down the plugin and recreate
173   // it. So instead we add a big div to cause the document to be scrollable,
174   // and scroll it down.
175   std::ostringstream script_stream;
176   script_stream
177       << "var big = document.createElement('div');"
178       << "big.setAttribute('style', 'position:absolute; left:100px; "
179                                     "top:0px; width:1px; height:5000px;');"
180       << "document.body.appendChild(big);"
181       << "window.scrollBy(0, " << original_rect.y() + clip_amount << ");";
182 
183   instance_->EvalScript(script_stream.str());
184 
185   pp::Rect desired_clip = original_clip;
186   desired_clip.set_y(clip_amount);
187   desired_clip.set_height(desired_clip.height() - desired_clip.y());
188 
189   PP_Time begin_time = pp::Module::Get()->core()->GetTime();
190   while (WaitUntilViewChanged() && last_view_.GetClipRect() != desired_clip &&
191          pp::Module::Get()->core()->GetTime() - begin_time <
192              kViewChangeTimeoutSec) {
193   }
194   ASSERT_TRUE(last_view_.GetClipRect() == desired_clip);
195   PASS();
196 }
197