Skip to content
This repository was archived by the owner on Apr 3, 2020. It is now read-only.

Commit d45a698

Browse files
author
Mrunal Kapade
committed
Enable window.print() for Linux
This enables window.print() api so that crosswalk based apps can print within their app. It doesn't provide Print Preview like Chrome but does pop up system print dialog to configure print settings. It also relies on a small modification to build/common.gypi in chromium-crosswalk repo to disable the print preview for which I will submit a seprate PR. BUG=XWALK-5680
1 parent 6ebd942 commit d45a698

25 files changed

+3139
-2
lines changed

runtime/browser/printing/print_job.cc

Lines changed: 463 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// Copyright (c) 2012 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+
#ifndef XWALK_RUNTIME_BROWSER_PRINTING_PRINT_JOB_H_
6+
#define XWALK_RUNTIME_BROWSER_PRINTING_PRINT_JOB_H_
7+
8+
#include <memory>
9+
10+
#include "base/macros.h"
11+
#include "base/memory/weak_ptr.h"
12+
#include "base/message_loop/message_loop.h"
13+
#include "build/build_config.h"
14+
#include "content/public/browser/notification_observer.h"
15+
#include "content/public/browser/notification_registrar.h"
16+
#include "xwalk/runtime/browser/printing/print_job_worker_owner.h"
17+
18+
class Thread;
19+
20+
namespace base {
21+
class RefCountedMemory;
22+
}
23+
24+
namespace printing {
25+
class PrintedDocument;
26+
class PrintedPage;
27+
class PrintedPagesSource;
28+
}
29+
30+
namespace xwalk {
31+
32+
class JobEventDetails;
33+
class MetafilePlayer;
34+
class PdfToEmfConverter;
35+
class PrintJobWorker;
36+
class PrinterQuery;
37+
38+
// Manages the print work for a specific document. Talks to the printer through
39+
// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a
40+
// worker thread so the caller never blocks. PrintJob will send notifications on
41+
// any state change. While printing, the PrintJobManager instance keeps a
42+
// reference to the job to be sure it is kept alive. All the code in this class
43+
// runs in the UI thread.
44+
class PrintJob : public PrintJobWorkerOwner,
45+
public content::NotificationObserver {
46+
public:
47+
// Create a empty PrintJob. When initializing with this constructor,
48+
// post-constructor initialization must be done with Initialize().
49+
PrintJob();
50+
51+
// Grabs the ownership of the PrintJobWorker from another job, which is
52+
// usually a PrinterQuery. Set the expected page count of the print job.
53+
void Initialize(PrintJobWorkerOwner* job, printing::PrintedPagesSource* source,
54+
int page_count);
55+
56+
// content::NotificationObserver implementation.
57+
void Observe(int type,
58+
const content::NotificationSource& source,
59+
const content::NotificationDetails& details) override;
60+
61+
// PrintJobWorkerOwner implementation.
62+
void GetSettingsDone(const printing::PrintSettings& new_settings,
63+
printing::PrintingContext::Result result) override;
64+
PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) override;
65+
const printing::PrintSettings& settings() const override;
66+
int cookie() const override;
67+
68+
// Starts the actual printing. Signals the worker that it should begin to
69+
// spool as soon as data is available.
70+
void StartPrinting();
71+
72+
// Asks for the worker thread to finish its queued tasks and disconnects the
73+
// delegate object. The PrintJobManager will remove its reference. This may
74+
// have the side-effect of destroying the object if the caller doesn't have a
75+
// handle to the object. Use PrintJob::is_stopped() to check whether the
76+
// worker thread has actually stopped.
77+
void Stop();
78+
79+
// Cancels printing job and stops the worker thread. Takes effect immediately.
80+
void Cancel();
81+
82+
// Synchronously wait for the job to finish. It is mainly useful when the
83+
// process is about to be shut down and we're waiting for the spooler to eat
84+
// our data.
85+
bool FlushJob(base::TimeDelta timeout);
86+
87+
// Disconnects the PrintedPage source (PrintedPagesSource). It is done when
88+
// the source is being destroyed.
89+
void DisconnectSource();
90+
91+
// Returns true if the print job is pending, i.e. between a StartPrinting()
92+
// and the end of the spooling.
93+
bool is_job_pending() const;
94+
95+
// Access the current printed document. Warning: may be NULL.
96+
printing::PrintedDocument* document() const;
97+
98+
#if defined(OS_WIN)
99+
void StartPdfToEmfConversion(
100+
const scoped_refptr<base::RefCountedMemory>& bytes,
101+
const gfx::Size& page_size,
102+
const gfx::Rect& content_area);
103+
#endif // OS_WIN
104+
105+
protected:
106+
~PrintJob() override;
107+
108+
private:
109+
// Updates document_ to a new instance.
110+
void UpdatePrintedDocument(printing::PrintedDocument* new_document);
111+
112+
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
113+
void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
114+
115+
// Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE
116+
// notification.
117+
void OnDocumentDone();
118+
119+
// Terminates the worker thread in a very controlled way, to work around any
120+
// eventual deadlock.
121+
void ControlledWorkerShutdown();
122+
123+
// Called at shutdown when running a nested message loop.
124+
void Quit();
125+
126+
void HoldUntilStopIsCalled();
127+
128+
#if defined(OS_WIN)
129+
void OnPdfToEmfStarted(int page_count);
130+
void OnPdfToEmfPageConverted(int page_number,
131+
float scale_factor,
132+
std::unique_ptr<MetafilePlayer> emf);
133+
#endif // OS_WIN
134+
135+
content::NotificationRegistrar registrar_;
136+
137+
// Source that generates the PrintedPage's (i.e. a WebContents). It will be
138+
// set back to NULL if the source is deleted before this object.
139+
printing::PrintedPagesSource* source_;
140+
141+
// All the UI is done in a worker thread because many Win32 print functions
142+
// are blocking and enters a message loop without your consent. There is one
143+
// worker thread per print job.
144+
std::unique_ptr<PrintJobWorker> worker_;
145+
146+
// Cache of the print context settings for access in the UI thread.
147+
printing::PrintSettings settings_;
148+
149+
// The printed document.
150+
scoped_refptr<printing::PrintedDocument> document_;
151+
152+
// Is the worker thread printing.
153+
bool is_job_pending_;
154+
155+
// Is Canceling? If so, try to not cause recursion if on FAILED notification,
156+
// the notified calls Cancel() again.
157+
bool is_canceling_;
158+
159+
#if defined(OS_WIN)
160+
class PdfToEmfState;
161+
std::unique_ptr<PdfToEmfState> ptd_to_emf_state_;
162+
#endif // OS_WIN
163+
164+
// Used at shutdown so that we can quit a nested message loop.
165+
base::WeakPtrFactory<PrintJob> quit_factory_;
166+
167+
DISALLOW_COPY_AND_ASSIGN(PrintJob);
168+
};
169+
170+
// Details for a NOTIFY_PRINT_JOB_EVENT notification. The members may be NULL.
171+
class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
172+
public:
173+
// Event type.
174+
enum Type {
175+
// Print... dialog box has been closed with OK button.
176+
USER_INIT_DONE,
177+
178+
// Print... dialog box has been closed with CANCEL button.
179+
USER_INIT_CANCELED,
180+
181+
// An automated initialization has been done, e.g. Init(false, NULL).
182+
DEFAULT_INIT_DONE,
183+
184+
// A new document started printing.
185+
NEW_DOC,
186+
187+
// A new page started printing.
188+
NEW_PAGE,
189+
190+
// A page is done printing.
191+
PAGE_DONE,
192+
193+
// A document is done printing. The worker thread is still alive. Warning:
194+
// not a good moment to release the handle to PrintJob.
195+
DOC_DONE,
196+
197+
// The worker thread is finished. A good moment to release the handle to
198+
// PrintJob.
199+
JOB_DONE,
200+
201+
// All missing pages have been requested.
202+
ALL_PAGES_REQUESTED,
203+
204+
// An error occured. Printing is canceled.
205+
FAILED,
206+
};
207+
208+
JobEventDetails(Type type, printing::PrintedDocument* document, printing::PrintedPage* page);
209+
210+
// Getters.
211+
printing::PrintedDocument* document() const;
212+
printing::PrintedPage* page() const;
213+
Type type() const {
214+
return type_;
215+
}
216+
217+
private:
218+
friend class base::RefCountedThreadSafe<JobEventDetails>;
219+
220+
~JobEventDetails();
221+
222+
scoped_refptr<printing::PrintedDocument> document_;
223+
scoped_refptr<printing::PrintedPage> page_;
224+
const Type type_;
225+
226+
DISALLOW_COPY_AND_ASSIGN(JobEventDetails);
227+
};
228+
229+
} // namespace xwalk
230+
231+
#endif // XWALK_RUNTIME_BROWSER_PRINTING_PRINT_JOB_H_
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright (c) 2012 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 "xwalk/runtime/browser/printing/print_job_manager.h"
6+
7+
#include "content/public/browser/browser_thread.h"
8+
#include "content/public/browser/notification_service.h"
9+
#include "printing/printed_document.h"
10+
#include "printing/printed_page.h"
11+
#include "xwalk/runtime/browser/printing/print_job.h"
12+
#include "xwalk/runtime/browser/printing/printer_query.h"
13+
#include "xwalk/runtime/common/xwalk_notification_types.h"
14+
15+
16+
namespace xwalk {
17+
18+
PrintQueriesQueue::PrintQueriesQueue() {
19+
}
20+
21+
PrintQueriesQueue::~PrintQueriesQueue() {
22+
base::AutoLock lock(lock_);
23+
queued_queries_.clear();
24+
}
25+
26+
void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) {
27+
base::AutoLock lock(lock_);
28+
DCHECK(job);
29+
queued_queries_.push_back(make_scoped_refptr(job));
30+
DCHECK(job->is_valid());
31+
}
32+
33+
scoped_refptr<PrinterQuery> PrintQueriesQueue::PopPrinterQuery(
34+
int document_cookie) {
35+
base::AutoLock lock(lock_);
36+
for (PrinterQueries::iterator itr = queued_queries_.begin();
37+
itr != queued_queries_.end(); ++itr) {
38+
if ((*itr)->cookie() == document_cookie && !(*itr)->is_callback_pending()) {
39+
scoped_refptr<PrinterQuery> current_query(*itr);
40+
queued_queries_.erase(itr);
41+
DCHECK(current_query->is_valid());
42+
return current_query;
43+
}
44+
}
45+
return NULL;
46+
}
47+
48+
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery(
49+
int render_process_id,
50+
int render_view_id) {
51+
scoped_refptr<PrinterQuery> job =
52+
new PrinterQuery(render_process_id, render_view_id);
53+
return job;
54+
}
55+
56+
void PrintQueriesQueue::Shutdown() {
57+
PrinterQueries queries_to_stop;
58+
{
59+
base::AutoLock lock(lock_);
60+
queued_queries_.swap(queries_to_stop);
61+
}
62+
// Stop all pending queries, requests to generate print preview do not have
63+
// corresponding PrintJob, so any pending preview requests are not covered
64+
// by PrintJobManager::StopJobs and should be stopped explicitly.
65+
for (PrinterQueries::iterator itr = queries_to_stop.begin();
66+
itr != queries_to_stop.end(); ++itr) {
67+
(*itr)->PostTask(FROM_HERE, base::Bind(&PrinterQuery::StopWorker, *itr));
68+
}
69+
}
70+
71+
PrintJobManager::PrintJobManager() : is_shutdown_(false) {
72+
registrar_.Add(this, NOTIFICATION_XWALK_PRINT_JOB_EVENT,
73+
content::NotificationService::AllSources());
74+
}
75+
76+
PrintJobManager::~PrintJobManager() {
77+
}
78+
79+
scoped_refptr<PrintQueriesQueue> PrintJobManager::queue() {
80+
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
81+
if (!queue_.get())
82+
queue_ = new PrintQueriesQueue();
83+
return queue_;
84+
}
85+
86+
void PrintJobManager::Shutdown() {
87+
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
88+
DCHECK(!is_shutdown_);
89+
is_shutdown_ = true;
90+
registrar_.RemoveAll();
91+
StopJobs(true);
92+
if (queue_.get())
93+
queue_->Shutdown();
94+
queue_ = NULL;
95+
}
96+
97+
void PrintJobManager::StopJobs(bool wait_for_finish) {
98+
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
99+
// Copy the array since it can be modified in transit.
100+
PrintJobs to_stop;
101+
to_stop.swap(current_jobs_);
102+
103+
for (PrintJobs::const_iterator job = to_stop.begin(); job != to_stop.end();
104+
++job) {
105+
// Wait for two minutes for the print job to be spooled.
106+
if (wait_for_finish)
107+
(*job)->FlushJob(base::TimeDelta::FromMinutes(2));
108+
(*job)->Stop();
109+
}
110+
}
111+
112+
void PrintJobManager::Observe(int type,
113+
const content::NotificationSource& source,
114+
const content::NotificationDetails& details) {
115+
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
116+
switch (type) {
117+
case NOTIFICATION_XWALK_PRINT_JOB_EVENT: {
118+
OnPrintJobEvent(content::Source<PrintJob>(source).ptr(),
119+
*content::Details<JobEventDetails>(details).ptr());
120+
break;
121+
}
122+
default: {
123+
NOTREACHED();
124+
break;
125+
}
126+
}
127+
}
128+
129+
void PrintJobManager::OnPrintJobEvent(
130+
PrintJob* print_job,
131+
const JobEventDetails& event_details) {
132+
switch (event_details.type()) {
133+
case JobEventDetails::NEW_DOC: {
134+
DCHECK(current_jobs_.end() == current_jobs_.find(print_job));
135+
// Causes a AddRef().
136+
current_jobs_.insert(print_job);
137+
break;
138+
}
139+
case JobEventDetails::JOB_DONE: {
140+
DCHECK(current_jobs_.end() != current_jobs_.find(print_job));
141+
current_jobs_.erase(print_job);
142+
break;
143+
}
144+
case JobEventDetails::FAILED: {
145+
current_jobs_.erase(print_job);
146+
break;
147+
}
148+
case JobEventDetails::USER_INIT_DONE:
149+
case JobEventDetails::USER_INIT_CANCELED:
150+
case JobEventDetails::DEFAULT_INIT_DONE:
151+
case JobEventDetails::NEW_PAGE:
152+
case JobEventDetails::PAGE_DONE:
153+
case JobEventDetails::DOC_DONE:
154+
case JobEventDetails::ALL_PAGES_REQUESTED: {
155+
// Don't care.
156+
break;
157+
}
158+
default: {
159+
NOTREACHED();
160+
break;
161+
}
162+
}
163+
}
164+
165+
} // namespace xwalk

0 commit comments

Comments
 (0)