1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "include/base/cef_callback.h"
6 #include "include/cef_pack_resources.h"
7 #include "include/cef_request_context_handler.h"
8 #include "include/wrapper/cef_closure_task.h"
9 #include "include/wrapper/cef_stream_resource_handler.h"
10 #include "tests/ceftests/test_handler.h"
11 #include "tests/ceftests/test_util.h"
12 #include "tests/gtest/include/gtest/gtest.h"
13 #include "tests/shared/browser/client_app_browser.h"
14 #include "tests/shared/browser/resource_util.h"
15
16 namespace {
17
18 // Browser-side app delegate.
19 class PdfViewerBrowserTest : public client::ClientAppBrowser::Delegate {
20 public:
PdfViewerBrowserTest()21 PdfViewerBrowserTest() {}
22
OnBeforeCommandLineProcessing(CefRefPtr<client::ClientAppBrowser> app,CefRefPtr<CefCommandLine> command_line)23 void OnBeforeCommandLineProcessing(
24 CefRefPtr<client::ClientAppBrowser> app,
25 CefRefPtr<CefCommandLine> command_line) override {
26 // Allow all plugin loading by default.
27 command_line->AppendSwitchWithValue("plugin-policy", "allow");
28 }
29
30 private:
31 IMPLEMENT_REFCOUNTING(PdfViewerBrowserTest);
32 };
33
34 const char kPdfHtmlUrl[] = "http://tests/pdf.html";
35 const char kPdfDirectUrl[] = "http://tests/pdf.pdf";
36
37 // Delay waiting for iframe tests to load the PDF file.
38 #if defined(OS_LINUX)
39 const int64 kPdfLoadDelayMs = 7000;
40 #else
41 const int64 kPdfLoadDelayMs = 5000;
42 #endif
43
44 // Browser-side test handler.
45 class PdfViewerTestHandler : public TestHandler, public CefContextMenuHandler {
46 public:
47 enum Mode {
48 // No specified context or handler (implicitly uses the global context).
49 GLOBAL_DEFAULT,
50
51 // Global context with no handler.
52 GLOBAL_NO_HANDLER,
53
54 // Custom context with no handler.
55 CUSTOM_NO_HANDLER,
56 };
57
PdfViewerTestHandler(Mode mode,const std::string & url)58 PdfViewerTestHandler(Mode mode, const std::string& url)
59 : mode_(mode), url_(url) {}
60
61 // Loading the PDF directly in the main frame instead of a sub-frame.
HasDirectPdfLoad() const62 bool HasDirectPdfLoad() const { return url_ == kPdfDirectUrl; }
63
GetContextMenuHandler()64 CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
65 return this;
66 }
67
RunTest()68 void RunTest() override {
69 CefRefPtr<CefRequestContext> request_context;
70
71 if (mode_ == GLOBAL_NO_HANDLER) {
72 // Use the global request context.
73 request_context = CefRequestContext::CreateContext(
74 CefRequestContext::GetGlobalContext(), nullptr);
75 } else if (mode_ == CUSTOM_NO_HANDLER) {
76 // Create the request context that will use an in-memory cache.
77 CefRequestContextSettings settings;
78 request_context = CefRequestContext::CreateContext(settings, nullptr);
79 }
80
81 // Create the browser.
82 CreateBrowser(url_, request_context);
83
84 // Time out the test after a reasonable period of time.
85 SetTestTimeout(5000 + kPdfLoadDelayMs);
86 }
87
GetResourceHandler(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request)88 CefRefPtr<CefResourceHandler> GetResourceHandler(
89 CefRefPtr<CefBrowser> browser,
90 CefRefPtr<CefFrame> frame,
91 CefRefPtr<CefRequest> request) override {
92 const std::string& url = request->GetURL();
93 if (url == kPdfHtmlUrl) {
94 CefRefPtr<CefStreamReader> stream =
95 client::GetBinaryResourceReader("pdf.html");
96 return new CefStreamResourceHandler("text/html", stream);
97 } else if (url == kPdfDirectUrl) {
98 CefRefPtr<CefStreamReader> stream =
99 client::GetBinaryResourceReader("pdf.pdf");
100 return new CefStreamResourceHandler("application/pdf", stream);
101 }
102
103 return nullptr;
104 }
105
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)106 void OnLoadEnd(CefRefPtr<CefBrowser> browser,
107 CefRefPtr<CefFrame> frame,
108 int httpStatusCode) override {
109 bool is_pdf1 = false;
110 const std::string& url = frame->GetURL();
111 if (url == kPdfHtmlUrl) {
112 if (!got_on_load_end_html_)
113 got_on_load_end_html_.yes();
114 else
115 NOTREACHED();
116 } else if (url == kPdfDirectUrl) {
117 if (!got_on_load_end_pdf1_) {
118 got_on_load_end_pdf1_.yes();
119 is_pdf1 = true;
120 } else if (!got_on_load_end_pdf2_) {
121 got_on_load_end_pdf2_.yes();
122 } else {
123 NOTREACHED();
124 }
125 } else {
126 NOTREACHED();
127 }
128
129 if (is_pdf1) {
130 // The first PDF document has loaded.
131 // TODO(chrome): Add support for custom context menus.
132 if (IsChromeRuntimeEnabled() || got_context_menu_dismissed_) {
133 // After context menu display. Destroy the test.
134 CefPostDelayedTask(
135 TID_UI, base::BindOnce(&PdfViewerTestHandler::DestroyTest, this),
136 kPdfLoadDelayMs);
137 } else {
138 // Trigger the context menu.
139 CefPostDelayedTask(
140 TID_UI,
141 base::BindOnce(&PdfViewerTestHandler::TriggerContextMenu, this,
142 frame->GetBrowser()),
143 kPdfLoadDelayMs);
144 }
145 }
146 }
147
TriggerContextMenu(CefRefPtr<CefBrowser> browser)148 void TriggerContextMenu(CefRefPtr<CefBrowser> browser) {
149 CefMouseEvent mouse_event;
150
151 if (HasDirectPdfLoad()) {
152 // Somewhere in the main PDF viewing area (avoid left preview bar).
153 mouse_event.x = 400;
154 mouse_event.y = 200;
155 } else {
156 // Somewhere in the first PDF viewing area.
157 mouse_event.x = 100;
158 mouse_event.y = 100;
159 }
160
161 // Send right-click mouse down and mouse up to tigger context menu.
162 browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, false, 1);
163 browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_RIGHT, true, 1);
164 }
165
RunContextMenu(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefRefPtr<CefContextMenuParams> params,CefRefPtr<CefMenuModel> model,CefRefPtr<CefRunContextMenuCallback> callback)166 bool RunContextMenu(CefRefPtr<CefBrowser> browser,
167 CefRefPtr<CefFrame> frame,
168 CefRefPtr<CefContextMenuParams> params,
169 CefRefPtr<CefMenuModel> model,
170 CefRefPtr<CefRunContextMenuCallback> callback) override {
171 EXPECT_FALSE(got_run_context_menu_);
172 got_run_context_menu_.yes();
173
174 // Do nothing with the context menu.
175 callback->Cancel();
176
177 return true;
178 }
179
OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame)180 void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,
181 CefRefPtr<CefFrame> frame) override {
182 EXPECT_FALSE(got_context_menu_dismissed_);
183 got_context_menu_dismissed_.yes();
184
185 CefPostTask(TID_UI,
186 base::BindOnce(&PdfViewerTestHandler::DestroyTest, this));
187 }
188
DestroyTest()189 void DestroyTest() override {
190 // TODO(chrome): Add support for custom context menus.
191 if (!IsChromeRuntimeEnabled()) {
192 EXPECT_TRUE(got_run_context_menu_);
193 EXPECT_TRUE(got_context_menu_dismissed_);
194 } else {
195 EXPECT_FALSE(got_run_context_menu_);
196 EXPECT_FALSE(got_context_menu_dismissed_);
197 }
198
199 if (url_ == kPdfHtmlUrl) {
200 // The HTML file will load the PDF twice in iframes.
201 EXPECT_TRUE(got_on_load_end_html_);
202 EXPECT_TRUE(got_on_load_end_pdf1_);
203 EXPECT_TRUE(got_on_load_end_pdf2_);
204 } else if (url_ == kPdfDirectUrl) {
205 // Load the PDF file directly.
206 EXPECT_FALSE(got_on_load_end_html_);
207 EXPECT_TRUE(got_on_load_end_pdf1_);
208 EXPECT_FALSE(got_on_load_end_pdf2_);
209 } else {
210 NOTREACHED();
211 }
212
213 TestHandler::DestroyTest();
214 }
215
216 const Mode mode_;
217 const std::string url_;
218
219 TrackCallback got_on_load_end_html_;
220 TrackCallback got_on_load_end_pdf1_;
221 TrackCallback got_on_load_end_pdf2_;
222 TrackCallback got_run_context_menu_;
223 TrackCallback got_context_menu_dismissed_;
224
225 IMPLEMENT_REFCOUNTING(PdfViewerTestHandler);
226 };
227
228 } // namespace
229
230 #define RUN_TEST(name, type, url) \
231 TEST(PdfViewerTest, name) { \
232 CefRefPtr<PdfViewerTestHandler> handler = \
233 new PdfViewerTestHandler(PdfViewerTestHandler::type, url); \
234 handler->ExecuteTest(); \
235 ReleaseAndWaitForDestructor(handler); \
236 }
237
RUN_TEST(GlobalDefaultPdfDirect,GLOBAL_DEFAULT,kPdfDirectUrl)238 RUN_TEST(GlobalDefaultPdfDirect, GLOBAL_DEFAULT, kPdfDirectUrl)
239 RUN_TEST(GlobalDefaultPdfHtml, GLOBAL_DEFAULT, kPdfHtmlUrl)
240
241 RUN_TEST(GlobalNoHandlerPdfDirect, GLOBAL_NO_HANDLER, kPdfDirectUrl)
242 RUN_TEST(GlobalNoHandlerPdfHtml, GLOBAL_NO_HANDLER, kPdfHtmlUrl)
243
244 RUN_TEST(CustomNoHandlerPdfDirect, CUSTOM_NO_HANDLER, kPdfDirectUrl)
245 RUN_TEST(CustomNoHandlerPdfHtml, CUSTOM_NO_HANDLER, kPdfHtmlUrl)
246
247 // Entry point for creating PDF viewer browser test objects.
248 // Called from client_app_delegates.cc.
249 void CreatePdfViewerBrowserTests(
250 client::ClientAppBrowser::DelegateSet& delegates) {
251 delegates.insert(new PdfViewerBrowserTest);
252 }
253