1 // Copyright 2015 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 "chrome/browser/printing/print_dialog_cloud.h"
7 #include "base/base64.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/memory/ref_counted_memory.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/browser_window.h"
20 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "components/cloud_devices/common/cloud_devices_urls.h"
23 #include "components/google/core/browser/google_util.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/render_frame_host.h"
28 namespace print_dialog_cloud
{
32 // Limit is used only to allocate memory. Cloud has own small limit.
33 const int kMaxFileSize
= 1024 * 1024 * 1024;
35 // Sets print data into Cloud Print widget.
36 class PrintDataSetter
: public content::WebContentsObserver
{
38 PrintDataSetter(content::WebContents
* web_contents
,
39 const scoped_refptr
<base::RefCountedMemory
>& data
,
40 const base::string16
& print_job_title
,
41 const base::string16
& print_ticket
,
42 const std::string
& file_type
)
43 : WebContentsObserver(web_contents
) {
44 DCHECK_NE(data
->size(), 0u);
45 std::string base64_data
;
46 base::Base64Encode(base::StringPiece(data
->front_as
<char>(), data
->size()),
48 std::string
header("data:");
49 header
.append(file_type
);
50 header
.append(";base64,");
51 base64_data
.insert(0, header
);
53 InitPrintFunction(base::StringValue(base64_data
),
54 base::StringValue(print_job_title
));
58 // Overridden from content::WebContentsObserver:
59 void DocumentLoadedInFrame(
60 content::RenderFrameHost
* render_frame_host
) override
{
61 if (cloud_devices::IsCloudPrintURL(web_contents()->GetURL()))
62 render_frame_host
->ExecuteJavaScript(print_function_
);
65 void WebContentsDestroyed() override
{ delete this; }
67 void InitPrintFunction(const base::Value
& arg1
, const base::Value
& arg2
) {
68 std::vector
<const base::Value
*> args
;
69 args
.push_back(&arg1
);
70 args
.push_back(&arg2
);
72 content::WebUI::GetJavascriptCall("printApp._printDataUrl", args
);
75 base::string16 print_function_
;
77 DISALLOW_COPY_AND_ASSIGN(PrintDataSetter
);
80 void CreatePrintDialog(content::BrowserContext
* browser_context
,
81 const base::string16
& print_job_title
,
82 const base::string16
& print_ticket
,
83 const std::string
& file_type
,
84 const scoped_refptr
<base::RefCountedMemory
>& data
) {
85 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
86 Profile
* profile
= Profile::FromBrowserContext(browser_context
);
87 chrome::ScopedTabbedBrowserDisplayer
displayer(profile
,
88 chrome::GetActiveDesktop());
89 GURL url
= cloud_devices::GetCloudPrintRelativeURL("client/dialog.html");
90 content::WebContents
* web_contents
=
91 displayer
.browser()->OpenURL(content::OpenURLParams(
92 google_util::AppendGoogleLocaleParam(
93 url
, g_browser_process
->GetApplicationLocale()),
94 content::Referrer(), NEW_FOREGROUND_TAB
,
95 ui::PAGE_TRANSITION_AUTO_BOOKMARK
, false));
96 if (data
&& data
->size()) {
97 new PrintDataSetter(web_contents
, data
, print_job_title
, print_ticket
,
102 scoped_refptr
<base::RefCountedMemory
> ReadFile(
103 const base::FilePath
& path_to_file
) {
104 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
105 scoped_refptr
<base::RefCountedMemory
> data
;
106 int64_t file_size
= 0;
107 if (base::GetFileSize(path_to_file
, &file_size
) && file_size
!= 0) {
108 if (file_size
> kMaxFileSize
) {
109 DLOG(WARNING
) << " print data file too large to reserve space";
112 std::string file_data
;
113 file_data
.reserve(static_cast<size_t>(file_size
));
114 if (base::ReadFileToString(path_to_file
, &file_data
))
115 data
= base::RefCountedString::TakeString(&file_data
);
117 base::DeleteFile(path_to_file
, false);
121 void CreatePrintDialogForFile(content::BrowserContext
* browser_context
,
122 const base::FilePath
& path_to_file
,
123 const base::string16
& print_job_title
,
124 const base::string16
& print_ticket
,
125 const std::string
& file_type
) {
126 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
127 content::BrowserThread::PostTaskAndReplyWithResult(
128 content::BrowserThread::FILE, FROM_HERE
,
129 base::Bind(&ReadFile
, path_to_file
),
130 base::Bind(&CreatePrintDialog
, browser_context
,
131 print_job_title
, print_ticket
, file_type
));
136 bool CreatePrintDialogFromCommandLine(Profile
* profile
,
137 const base::CommandLine
& command_line
) {
138 base::FilePath cloud_print_file
=
139 command_line
.GetSwitchValuePath(switches::kCloudPrintFile
);
140 DCHECK(!cloud_print_file
.empty());
141 if (cloud_print_file
.empty())
143 base::string16 print_job_title
=
144 command_line
.GetSwitchValueNative(switches::kCloudPrintJobTitle
);
145 base::string16 print_job_print_ticket
=
146 command_line
.GetSwitchValueNative(switches::kCloudPrintPrintTicket
);
147 std::string file_type
=
148 command_line
.GetSwitchValueASCII(switches::kCloudPrintFileType
);
149 if (file_type
.empty())
150 file_type
= "application/pdf";
151 CreatePrintDialogForFile(profile
, cloud_print_file
, print_job_title
,
152 print_job_print_ticket
, file_type
);
156 } // namespace print_dialog_cloud