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.
5 #include "ppapi/tests/test_view.h"
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"
14 REGISTER_TEST_CASE(View
);
16 // When waiting for view changed events, wait no longer than this.
17 #if !defined(THREAD_SANITIZER)
18 static int kViewChangeTimeoutSec
= 5;
20 // ThreadSanitizer may slow the interaction down significantly.
21 static int kViewChangeTimeoutSec
= 30;
24 TestView::TestView(TestingInstance
* instance
)
26 post_quit_on_view_changed_(false) {
29 void TestView::DidChangeView(const pp::View
& view
) {
31 page_visibility_log_
.push_back(view
.IsPageVisible());
33 if (post_quit_on_view_changed_
) {
34 post_quit_on_view_changed_
= false;
35 testing_interface_
->QuitMessageLoop(instance_
->pp_instance());
39 bool TestView::Init() {
40 return CheckTestingInterface();
43 void TestView::RunTests(const std::string
& filter
) {
44 RUN_TEST(CreatedVisible
, filter
);
45 RUN_TEST(CreatedInvisible
, filter
);
46 RUN_TEST(PageHideShow
, filter
);
47 RUN_TEST(SizeChange
, filter
);
48 RUN_TEST(ClipChange
, filter
);
51 bool TestView::WaitUntilViewChanged() {
52 // Schedule a callback so this step times out if we don't get a ViewChanged
53 // in a reasonable amount of time.
54 pp::CompletionCallbackFactory
<TestView
> factory(this);
55 pp::CompletionCallback timeout
=
56 factory
.NewCallback(&TestView::QuitMessageLoop
);
57 pp::Module::Get()->core()->CallOnMainThread(
58 kViewChangeTimeoutSec
* 1000, timeout
);
60 size_t old_page_visibility_change_count
= page_visibility_log_
.size();
62 // Run a nested message loop. It will exit either on ViewChanged or if the
64 post_quit_on_view_changed_
= true;
65 testing_interface_
->RunMessageLoop(instance_
->pp_instance());
66 post_quit_on_view_changed_
= false;
68 // We know we got a view changed event if something was appended to the log.
69 return page_visibility_log_
.size() > old_page_visibility_change_count
;
72 void TestView::QuitMessageLoop(int32_t result
) {
73 testing_interface_
->QuitMessageLoop(instance_
->pp_instance());
76 std::string
TestView::TestCreatedVisible() {
77 ASSERT_FALSE(page_visibility_log_
.empty());
78 ASSERT_TRUE(page_visibility_log_
[0]);
82 std::string
TestView::TestCreatedInvisible() {
83 ASSERT_FALSE(page_visibility_log_
.empty());
85 if (page_visibility_log_
[0]) {
86 // Add more error message since this test has some extra requirements.
87 instance_
->AppendError("Initial page is set to visible. NOTE: "
88 "This test must be run in a background tab. "
89 "Either run in the UI test which does this, or you can middle-click "
90 "on the test link to run manually.");
92 ASSERT_FALSE(page_visibility_log_
[0]);
96 std::string
TestView::TestPageHideShow() {
97 // Initial state should be visible.
98 ASSERT_FALSE(page_visibility_log_
.empty());
99 ASSERT_TRUE(page_visibility_log_
[0]);
101 // Now that we're alive, tell the test knows it can change our visibility.
102 instance_
->ReportProgress("TestPageHideShow:Created");
104 // Wait until we get a hide event, being careful to handle spurious
105 // notifications of ViewChanged.
106 PP_Time begin_time
= pp::Module::Get()->core()->GetTime();
107 while (WaitUntilViewChanged() &&
108 page_visibility_log_
[page_visibility_log_
.size() - 1] &&
109 pp::Module::Get()->core()->GetTime() - begin_time
<
110 kViewChangeTimeoutSec
) {
112 if (page_visibility_log_
[page_visibility_log_
.size() - 1]) {
113 // Didn't get a view changed event that changed visibility (though there
114 // may have been some that didn't change visibility).
115 // Add more error message since this test has some extra requirements.
116 return "Didn't receive a hide event in timeout. NOTE: "
117 "This test requires tab visibility to change and won't pass if you "
118 "just run it in a browser. Normally the UI test should handle "
119 "this. You can also run manually by waiting 2 secs, creating a new "
120 "tab, waiting 2 more secs, and closing the new tab.";
123 // Tell the test so it can show us again.
124 instance_
->ReportProgress("TestPageHideShow:Hidden");
126 // Wait until we get a show event.
127 begin_time
= pp::Module::Get()->core()->GetTime();
128 while (WaitUntilViewChanged() &&
129 !page_visibility_log_
[page_visibility_log_
.size() - 1] &&
130 pp::Module::Get()->core()->GetTime() - begin_time
<
131 kViewChangeTimeoutSec
) {
133 ASSERT_TRUE(page_visibility_log_
[page_visibility_log_
.size() - 1]);
138 std::string
TestView::TestSizeChange() {
139 pp::Rect original_rect
= last_view_
.GetRect();
141 pp::Rect desired_rect
= original_rect
;
142 desired_rect
.set_width(original_rect
.width() + 10);
143 desired_rect
.set_height(original_rect
.height() + 12);
145 std::ostringstream script_stream
;
146 script_stream
<< "var plugin = document.getElementById('plugin');";
147 script_stream
<< "plugin.setAttribute('width', "
148 << desired_rect
.width() << ");";
149 script_stream
<< "plugin.setAttribute('height', "
150 << desired_rect
.height() << ");";
152 instance_
->EvalScript(script_stream
.str());
154 PP_Time begin_time
= pp::Module::Get()->core()->GetTime();
155 while (WaitUntilViewChanged() && last_view_
.GetRect() != desired_rect
&&
156 pp::Module::Get()->core()->GetTime() - begin_time
<
157 kViewChangeTimeoutSec
) {
159 ASSERT_TRUE(last_view_
.GetRect() == desired_rect
);
164 std::string
TestView::TestClipChange() {
165 pp::Rect original_rect
= last_view_
.GetRect();
167 // Original clip should be the full frame.
168 pp::Rect original_clip
= last_view_
.GetClipRect();
169 ASSERT_TRUE(original_clip
.x() == 0);
170 ASSERT_TRUE(original_clip
.y() == 0);
171 ASSERT_TRUE(original_clip
.width() == original_rect
.width());
172 ASSERT_TRUE(original_clip
.height() == original_rect
.height());
174 int clip_amount
= original_rect
.height() / 2;
176 // It might be nice to set the position to be absolute and set the location,
177 // but this will cause WebKit to actually tear down the plugin and recreate
178 // it. So instead we add a big div to cause the document to be scrollable,
179 // and scroll it down.
180 std::ostringstream script_stream
;
182 << "var big = document.createElement('div');"
183 << "big.setAttribute('style', 'position:absolute; left:100px; "
184 "top:0px; width:1px; height:5000px;');"
185 << "document.body.appendChild(big);"
186 << "window.scrollBy(0, " << original_rect
.y() + clip_amount
<< ");";
188 instance_
->EvalScript(script_stream
.str());
190 pp::Rect desired_clip
= original_clip
;
191 desired_clip
.set_y(clip_amount
);
192 desired_clip
.set_height(desired_clip
.height() - desired_clip
.y());
194 PP_Time begin_time
= pp::Module::Get()->core()->GetTime();
195 while (WaitUntilViewChanged() && last_view_
.GetClipRect() != desired_clip
&&
196 pp::Module::Get()->core()->GetTime() - begin_time
<
197 kViewChangeTimeoutSec
) {
199 ASSERT_TRUE(last_view_
.GetClipRect() == desired_clip
);