diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/chrome_qt.gyp | 24 | ||||
-rw-r--r-- | src/core/config/common.pri | 2 | ||||
-rw-r--r-- | src/core/config/embedded_linux.pri | 1 | ||||
-rw-r--r-- | src/core/config/embedded_qnx.pri | 1 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.cpp | 6 | ||||
-rw-r--r-- | src/core/print_view_manager_base_qt.cpp | 520 | ||||
-rw-r--r-- | src/core/print_view_manager_base_qt.h | 150 | ||||
-rw-r--r-- | src/core/print_view_manager_qt.cpp | 254 | ||||
-rw-r--r-- | src/core/print_view_manager_qt.h | 126 | ||||
-rw-r--r-- | src/core/printing_message_filter_qt.cpp | 260 | ||||
-rw-r--r-- | src/core/printing_message_filter_qt.h | 138 | ||||
-rw-r--r-- | src/core/qtwebengine.gypi | 17 | ||||
-rw-r--r-- | src/core/renderer/content_renderer_client_qt.cpp | 14 | ||||
-rw-r--r-- | src/core/renderer/print_web_view_helper_delegate_qt.cpp | 72 | ||||
-rw-r--r-- | src/core/renderer/print_web_view_helper_delegate_qt.h | 65 | ||||
-rw-r--r-- | src/core/web_engine_context.cpp | 13 | ||||
-rw-r--r-- | src/core/web_engine_context.h | 13 |
17 files changed, 1673 insertions, 3 deletions
diff --git a/src/core/chrome_qt.gyp b/src/core/chrome_qt.gyp index 626691db4..d7e6cc2e9 100644 --- a/src/core/chrome_qt.gyp +++ b/src/core/chrome_qt.gyp @@ -118,7 +118,29 @@ '<(DEPTH)/chrome/renderer/spellchecker/platform_spelling_engine.h', ], }], - ] + ], + }], + ['enable_basic_printing==1 or enable_print_preview==1', { + 'sources': [ + '<(DEPTH)/chrome/browser/printing/print_job.cc', + '<(DEPTH)/chrome/browser/printing/print_job.h', + '<(DEPTH)/chrome/browser/printing/print_job_manager.cc', + '<(DEPTH)/chrome/browser/printing/print_job_manager.h', + '<(DEPTH)/chrome/browser/printing/print_job_worker.cc', + '<(DEPTH)/chrome/browser/printing/print_job_worker.h', + '<(DEPTH)/chrome/browser/printing/print_job_worker_owner.cc', + '<(DEPTH)/chrome/browser/printing/print_job_worker_owner.h', + '<(DEPTH)/chrome/browser/printing/printer_query.cc', + '<(DEPTH)/chrome/browser/printing/printer_query.h', + '<(DEPTH)/extensions/browser/notification_types.h', + '<(DEPTH)/extensions/browser/notification_types.cc', + ], + 'dependencies': [ + '<(chromium_src_dir)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings', + ], + 'include_dirs': [ + '<(chromium_src_dir)/extensions', + ], }], ], }, diff --git a/src/core/config/common.pri b/src/core/config/common.pri index c5921a573..96506cd37 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -5,6 +5,6 @@ GYP_CONFIG += use_qt=1 # We do not want to ship more external binary blobs, so let v8 embed its startup data. GYP_CONFIG += v8_use_external_startup_data=0 # Disable printing since we don't support it yet -GYP_CONFIG += enable_basic_printing=0 enable_print_preview=0 +GYP_CONFIG += enable_basic_printing=1 enable_print_preview=0 # WebSpeech requires Google API keys and adds dependencies on speex and flac. GYP_CONFIG += enable_web_speech=0 diff --git a/src/core/config/embedded_linux.pri b/src/core/config/embedded_linux.pri index 84db049cb..7cabf52ac 100644 --- a/src/core/config/embedded_linux.pri +++ b/src/core/config/embedded_linux.pri @@ -9,6 +9,7 @@ GYP_CONFIG += \ embedded=1 \ enable_autofill_dialog=0 \ enable_automation=0 \ + enable_basic_printing=0 \ enable_captive_portal_detection=0 \ enable_extensions=0 \ enable_google_now=0 \ diff --git a/src/core/config/embedded_qnx.pri b/src/core/config/embedded_qnx.pri index 34470d2d8..c05e8bb59 100644 --- a/src/core/config/embedded_qnx.pri +++ b/src/core/config/embedded_qnx.pri @@ -4,6 +4,7 @@ include(common.pri) GYP_CONFIG += \ disable_nacl=1 \ + enable_basic_printing=0 \ enable_plugins=0 \ enable_webrtc=0 \ use_ash=0 \ diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 54430b81c..9e021dd6a 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -76,6 +76,9 @@ #include "location_provider_qt.h" #endif #include "media_capture_devices_dispatcher.h" +#if defined(ENABLE_BASIC_PRINTING) +#include "printing_message_filter_qt.h" +#endif // defined(ENABLE_BASIC_PRINTING) #include "resource_dispatcher_host_delegate_qt.h" #include "user_script_controller_host.h" #include "web_contents_delegate_qt.h" @@ -364,6 +367,9 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* #if defined(ENABLE_SPELLCHECK) host->AddFilter(new SpellCheckMessageFilter(id)); #endif +#if defined(ENABLE_BASIC_PRINTING) + host->AddFilter(new PrintingMessageFilterQt(host->GetID())); +#endif // defined(ENABLE_BASIC_PRINTING) } void ContentBrowserClientQt::ResourceDispatcherHostCreated() diff --git a/src/core/print_view_manager_base_qt.cpp b/src/core/print_view_manager_base_qt.cpp new file mode 100644 index 000000000..ea6345f94 --- /dev/null +++ b/src/core/print_view_manager_base_qt.cpp @@ -0,0 +1,520 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "print_view_manager_qt.h" + +#include "type_conversion.h" +#include "web_engine_context.h" + +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "base/timer/timer.h" +#include "base/values.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/printing/print_job.h" +#include "chrome/browser/printing/print_job_manager.h" +#include "chrome/browser/printing/printer_query.h" +#include "components/printing/common/print_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "printing/pdf_metafile_skia.h" +#include "printing/print_job_constants.h" +#include "printing/printed_document.h" + +namespace QtWebEngineCore { + +PrintViewManagerBaseQt::~PrintViewManagerBaseQt() +{ +} + +// PrintedPagesSource implementation. +base::string16 PrintViewManagerBaseQt::RenderSourceName() +{ + return toString16(QLatin1String("")); +} + +PrintViewManagerBaseQt::PrintViewManagerBaseQt(content::WebContents *contents) + : printing::PrintManager(contents) + , m_isInsideInnerMessageLoop(false) + , m_isExpectingFirstPage(false) + , m_didPrintingSucceed(false) + , m_printerQueriesQueue(WebEngineContext::current()->getPrintJobManager()->queue()) +{ + +} + +void PrintViewManagerBaseQt::OnNotifyPrintJobEvent( + const printing::JobEventDetails& event_details) { + switch (event_details.type()) { + case printing::JobEventDetails::FAILED: { + TerminatePrintJob(true); + + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PRINT_JOB_RELEASED, + content::Source<content::WebContents>(web_contents()), + content::NotificationService::NoDetails()); + break; + } + case printing::JobEventDetails::USER_INIT_DONE: + case printing::JobEventDetails::DEFAULT_INIT_DONE: + case printing::JobEventDetails::USER_INIT_CANCELED: { + NOTREACHED(); + break; + } + case printing::JobEventDetails::ALL_PAGES_REQUESTED: { + break; + } + case printing::JobEventDetails::NEW_DOC: + case printing::JobEventDetails::NEW_PAGE: + case printing::JobEventDetails::PAGE_DONE: + case printing::JobEventDetails::DOC_DONE: { + // Don't care about the actual printing process. + break; + } + case printing::JobEventDetails::JOB_DONE: { + // Printing is done, we don't need it anymore. + // print_job_->is_job_pending() may still be true, depending on the order + // of object registration. + m_didPrintingSucceed = true; + ReleasePrintJob(); + + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PRINT_JOB_RELEASED, + content::Source<content::WebContents>(web_contents()), + content::NotificationService::NoDetails()); + break; + } + default: { + NOTREACHED(); + break; + } + } +} + + +// content::WebContentsObserver implementation. +// Cancels the print job. +void PrintViewManagerBaseQt::NavigationStopped() +{ +} + +// content::WebContentsObserver implementation. +void PrintViewManagerBaseQt::DidStartLoading() +{ +} + +// content::NotificationObserver implementation. +void PrintViewManagerBaseQt::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_PRINT_JOB_EVENT: + OnNotifyPrintJobEvent(*content::Details<printing::JobEventDetails>(details).ptr()); + break; + default: + NOTREACHED(); + break; + + } +} + // Terminates or cancels the print job if one was pending. +void PrintViewManagerBaseQt::RenderProcessGone(base::TerminationStatus status) +{ + PrintManager::RenderProcessGone(status); + ReleasePrinterQuery(); + + if (!m_printJob.get()) + return; + + scoped_refptr<printing::PrintedDocument> document(m_printJob->document()); + if (document.get()) { + // If IsComplete() returns false, the document isn't completely rendered. + // Since our renderer is gone, there's nothing to do, cancel it. Otherwise, + // the print job may finish without problem. + TerminatePrintJob(!document->IsComplete()); + } +} + +void PrintViewManagerBaseQt::ReleasePrinterQuery() { + if (!cookie_) + return; + + int cookie = cookie_; + cookie_ = 0; + + printing::PrintJobManager* printJobManager = + WebEngineContext::current()->getPrintJobManager(); + // May be NULL in tests. + if (!printJobManager) + return; + + scoped_refptr<printing::PrinterQuery> printerQuery; + printerQuery = m_printerQueriesQueue->PopPrinterQuery(cookie); + if (!printerQuery.get()) + return; + content::BrowserThread::PostTask( + content::BrowserThread::IO, FROM_HERE, + base::Bind(&printing::PrinterQuery::StopWorker, printerQuery.get())); +} + + +// content::WebContentsObserver implementation. +bool PrintViewManagerBaseQt::OnMessageReceived(const IPC::Message& message) +{ + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBaseQt, message) + IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) + IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, + OnShowInvalidPrinterSettingsError); + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled || PrintManager::OnMessageReceived(message); +} + +void PrintViewManagerBaseQt::StopWorker(int documentCookie) { + if (documentCookie <= 0) + return; + scoped_refptr<printing::PrinterQuery> printer_query = + m_printerQueriesQueue->PopPrinterQuery(documentCookie); + if (printer_query.get()) { + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, + base::Bind(&printing::PrinterQuery::StopWorker, + printer_query)); + } +} + + +// IPC handlers +void PrintViewManagerBaseQt::OnDidPrintPage( + const PrintHostMsg_DidPrintPage_Params& params) { + if (!OpportunisticallyCreatePrintJob(params.document_cookie)) + return; + + printing::PrintedDocument* document = m_printJob->document(); + if (!document || params.document_cookie != document->cookie()) { + // Out of sync. It may happen since we are completely asynchronous. Old + // spurious messages can be received if one of the processes is overloaded. + return; + } + +#if defined(OS_MACOSX) + const bool metafile_must_be_valid = true; +#else + const bool metafile_must_be_valid = m_isExpectingFirstPage; + m_isExpectingFirstPage = false; +#endif + + // Only used when |metafile_must_be_valid| is true. + scoped_ptr<base::SharedMemory> shared_buf; + if (metafile_must_be_valid) { + if (!base::SharedMemory::IsHandleValid(params.metafile_data_handle)) { + NOTREACHED() << "invalid memory handle"; + web_contents()->Stop(); + return; + } + shared_buf.reset(new base::SharedMemory(params.metafile_data_handle, true)); + if (!shared_buf->Map(params.data_size)) { + NOTREACHED() << "couldn't map"; + web_contents()->Stop(); + return; + } + } else { + if (base::SharedMemory::IsHandleValid(params.metafile_data_handle)) { + NOTREACHED() << "unexpected valid memory handle"; + web_contents()->Stop(); + base::SharedMemory::CloseHandle(params.metafile_data_handle); + return; + } + } + + scoped_ptr<printing::PdfMetafileSkia> metafile(new printing::PdfMetafileSkia); + if (metafile_must_be_valid) { + if (!metafile->InitFromData(shared_buf->memory(), params.data_size)) { + NOTREACHED() << "Invalid metafile header"; + web_contents()->Stop(); + return; + } + } + +#if defined(OS_WIN) && !defined(TOOLKIT_QT) + if (metafile_must_be_valid) { + scoped_refptr<base::RefCountedBytes> bytes = new base::RefCountedBytes( + reinterpret_cast<const unsigned char*>(shared_buf->memory()), + params.data_size); + + document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf")); + m_printJob->StartPdfToEmfConversion( + bytes, params.page_size, params.content_area); + } +#else + // Update the rendered document. It will send notifications to the listener. + document->SetPage(params.page_number, + metafile.Pass(), +#if defined(OS_WIN) + 1.0f, // shrink factor, needed on windows. +#endif // defined(OS_WIN) + params.page_size, + params.content_area); + + ShouldQuitFromInnerMessageLoop(); +#endif // defined (OS_WIN) && !defined(TOOLKIT_QT) +} + +void PrintViewManagerBaseQt::OnShowInvalidPrinterSettingsError() +{ +} + +bool PrintViewManagerBaseQt::CreateNewPrintJob(printing::PrintJobWorkerOwner* job) { + DCHECK(!m_isInsideInnerMessageLoop); + + // Disconnect the current print_job_. + DisconnectFromCurrentPrintJob(); + + // We can't print if there is no renderer. + if (!web_contents()->GetRenderViewHost() || + !web_contents()->GetRenderViewHost()->IsRenderViewLive()) { + return false; + } + + // Ask the renderer to generate the print preview, create the print preview + // view and switch to it, initialize the printer and show the print dialog. + DCHECK(!m_printJob.get()); + DCHECK(job); + if (!job) + return false; + + m_printJob = new printing::PrintJob(); + m_printJob->Initialize(job, this, number_pages_); + m_registrar.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, + content::Source<printing::PrintJob>(m_printJob.get())); + m_didPrintingSucceed = false; + return true; +} + +void PrintViewManagerBaseQt::DisconnectFromCurrentPrintJob() { + // Make sure all the necessary rendered page are done. Don't bother with the + // return value. + bool result = RenderAllMissingPagesNow(); + + // Verify that assertion. + if (m_printJob.get() && + m_printJob->document() && + !m_printJob->document()->IsComplete()) { + DCHECK(!result); + // That failed. + TerminatePrintJob(true); + } else { + // DO NOT wait for the job to finish. + ReleasePrintJob(); + } +#if !defined(OS_MACOSX) + m_isExpectingFirstPage = true; +#endif +} + +void PrintViewManagerBaseQt::PrintingDone(bool success) { + if (!m_printJob.get()) + return; + Send(new PrintMsg_PrintingDone(routing_id(), success)); +} + +void PrintViewManagerBaseQt::TerminatePrintJob(bool cancel) { + if (!m_printJob.get()) + return; + + if (cancel) { + // We don't need the metafile data anymore because the printing is canceled. + m_printJob->Cancel(); + m_isInsideInnerMessageLoop = false; + } else { + DCHECK(!m_isInsideInnerMessageLoop); + DCHECK(!m_printJob->document() || m_printJob->document()->IsComplete()); + + // WebContents is either dying or navigating elsewhere. We need to render + // all the pages in an hurry if a print job is still pending. This does the + // trick since it runs a blocking message loop: + m_printJob->Stop(); + } + ReleasePrintJob(); +} + +bool PrintViewManagerBaseQt::OpportunisticallyCreatePrintJob(int cookie) +{ + if (m_printJob.get()) + return true; + + if (!cookie) { + // Out of sync. It may happens since we are completely asynchronous. Old + // spurious message can happen if one of the processes is overloaded. + return false; + } + + // The job was initiated by a script. Time to get the corresponding worker + // thread. + scoped_refptr<printing::PrinterQuery> queued_query = m_printerQueriesQueue->PopPrinterQuery(cookie); + if (!queued_query.get()) { + NOTREACHED(); + return false; + } + + if (!CreateNewPrintJob(queued_query.get())) { + // Don't kill anything. + return false; + } + + // Settings are already loaded. Go ahead. This will set + // print_job_->is_job_pending() to true. + m_printJob->StartPrinting(); + return true; +} + +void PrintViewManagerBaseQt::ReleasePrintJob() { + if (!m_printJob.get()) + return; + + PrintingDone(m_didPrintingSucceed); + + m_registrar.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, + content::Source<printing::PrintJob>(m_printJob.get())); + m_printJob->DisconnectSource(); + // Don't close the worker thread. + m_printJob = NULL; +} + +// Requests the RenderView to render all the missing pages for the print job. +// No-op if no print job is pending. Returns true if at least one page has +// been requested to the renderer. +bool PrintViewManagerBaseQt::RenderAllMissingPagesNow() +{ + if (!m_printJob.get() || !m_printJob->is_job_pending()) + return false; + + // We can't print if there is no renderer. + if (!web_contents() || + !web_contents()->GetRenderViewHost() || + !web_contents()->GetRenderViewHost()->IsRenderViewLive()) { + return false; + } + + // Is the document already complete? + if (m_printJob->document() && m_printJob->document()->IsComplete()) { + m_didPrintingSucceed = true; + return true; + } + + // WebContents is either dying or a second consecutive request to print + // happened before the first had time to finish. We need to render all the + // pages in an hurry if a print_job_ is still pending. No need to wait for it + // to actually spool the pages, only to have the renderer generate them. Run + // a message loop until we get our signal that the print job is satisfied. + // PrintJob will send a ALL_PAGES_REQUESTED after having received all the + // pages it needs. MessageLoop::current()->Quit() will be called as soon as + // print_job_->document()->IsComplete() is true on either ALL_PAGES_REQUESTED + // or in DidPrintPage(). The check is done in + // ShouldQuitFromInnerMessageLoop(). + // BLOCKS until all the pages are received. (Need to enable recursive task) + if (!RunInnerMessageLoop()) { + // This function is always called from DisconnectFromCurrentPrintJob() so we + // know that the job will be stopped/canceled in any case. + return false; + } + return true; +} + +bool PrintViewManagerBaseQt::RunInnerMessageLoop() { + // This value may actually be too low: + // + // - If we're looping because of printer settings initialization, the premise + // here is that some poor users have their print server away on a VPN over a + // slow connection. In this situation, the simple fact of opening the printer + // can be dead slow. On the other side, we don't want to die infinitely for a + // real network error. Give the printer 60 seconds to comply. + // + // - If we're looping because of renderer page generation, the renderer could + // be CPU bound, the page overly complex/large or the system just + // memory-bound. + static const int kPrinterSettingsTimeout = 60000; + base::OneShotTimer quit_timer; + quit_timer.Start(FROM_HERE, + base::TimeDelta::FromMilliseconds(kPrinterSettingsTimeout), + base::MessageLoop::current(), &base::MessageLoop::Quit); + + m_isInsideInnerMessageLoop = true; + + // Need to enable recursive task. + { + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + base::MessageLoop::current()->Run(); + } + + bool success = true; + if (m_isInsideInnerMessageLoop) { + // Ok we timed out. That's sad. + m_isInsideInnerMessageLoop = false; + success = false; + } + + return success; +} + +// Quits the current message loop if these conditions hold true: a document is +// loaded and is complete and waiting_for_pages_to_be_rendered_ is true. This +// function is called in DidPrintPage() or on ALL_PAGES_REQUESTED +// notification. The inner message loop is created was created by +// RenderAllMissingPagesNow(). +void PrintViewManagerBaseQt::ShouldQuitFromInnerMessageLoop() +{ + // Look at the reason. + DCHECK(m_printJob->document()); + if (m_printJob->document() && + m_printJob->document()->IsComplete() && + m_isInsideInnerMessageLoop) { + // We are in a message loop created by RenderAllMissingPagesNow. Quit from + // it. + base::MessageLoop::current()->Quit(); + m_isInsideInnerMessageLoop = false; + } +} + +} // namespace QtWebEngineCore diff --git a/src/core/print_view_manager_base_qt.h b/src/core/print_view_manager_base_qt.h new file mode 100644 index 000000000..f1e001eee --- /dev/null +++ b/src/core/print_view_manager_base_qt.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINT_VIEW_MANAGER_BASE_QT_H +#define PRINT_VIEW_MANAGER_BASE_QT_H + +#include "base/memory/ref_counted.h" +#include "base/prefs/pref_member.h" +#include "base/strings/string16.h" +#include "components/printing/browser/print_manager.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "printing/printed_pages_source.h" + +struct PrintHostMsg_DidPrintPage_Params; + +namespace content { +class RenderViewHost; +} + +namespace printing { +class JobEventDetails; +class MetafilePlayer; +class PrintJob; +class PrintJobWorkerOwner; +class PrintQueriesQueue; +} + +namespace QtWebEngineCore { +class PrintViewManagerBaseQt + : public content::NotificationObserver + , public printing::PrintManager + , public printing::PrintedPagesSource +{ +public: + ~PrintViewManagerBaseQt() override; + + // PrintedPagesSource implementation. + base::string16 RenderSourceName() override; + +protected: + explicit PrintViewManagerBaseQt(content::WebContents*); + + // content::WebContentsObserver implementation. + // Cancels the print job. + void NavigationStopped() override; + + // Terminates or cancels the print job if one was pending. + void RenderProcessGone(base::TerminationStatus status) override; + + // content::WebContentsObserver implementation. + bool OnMessageReceived(const IPC::Message& message) override; + + // IPC Message handlers. + void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params); + void OnShowInvalidPrinterSettingsError(); + + // Processes a NOTIFY_PRINT_JOB_EVENT notification. + void OnNotifyPrintJobEvent(const printing::JobEventDetails& event_details); + + int number_pages_; // Number of pages to print in the print job. + int cookie_; + scoped_ptr<base::DictionaryValue> m_printSettings; + + // content::NotificationObserver implementation. + void Observe(int, + const content::NotificationSource&, + const content::NotificationDetails&) override; + void StopWorker(int document_cookie); + + // In the case of Scripted Printing, where the renderer is controlling the + // control flow, print_job_ is initialized whenever possible. No-op is + // print_job_ is initialized. + bool OpportunisticallyCreatePrintJob(int cookie); + + // Requests the RenderView to render all the missing pages for the print job. + // No-op if no print job is pending. Returns true if at least one page has + // been requested to the renderer. + bool RenderAllMissingPagesNow(); + + // Quits the current message loop if these conditions hold true: a document is + // loaded and is complete and waiting_for_pages_to_be_rendered_ is true. This + // function is called in DidPrintPage() or on ALL_PAGES_REQUESTED + // notification. The inner message loop is created was created by + // RenderAllMissingPagesNow(). + void ShouldQuitFromInnerMessageLoop(); + + bool RunInnerMessageLoop(); + + void TerminatePrintJob(bool cancel); + void PrintingDone(bool success); + void DisconnectFromCurrentPrintJob(); + + bool CreateNewPrintJob(printing::PrintJobWorkerOwner* job); + void ReleasePrintJob(); + void ReleasePrinterQuery(); + +private: + content::NotificationRegistrar m_registrar; + scoped_refptr<printing::PrintJob> m_printJob; + + bool m_isInsideInnerMessageLoop; + bool m_isExpectingFirstPage; + bool m_didPrintingSucceed; + scoped_refptr<printing::PrintQueriesQueue> m_printerQueriesQueue; + // content::WebContentsObserver implementation. + void DidStartLoading() override; + DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBaseQt); +}; + +} // namespace QtWebEngineCore +#endif // PRINT_VIEW_MANAGER_BASE_QT_H + diff --git a/src/core/print_view_manager_qt.cpp b/src/core/print_view_manager_qt.cpp new file mode 100644 index 000000000..f9b9c9f29 --- /dev/null +++ b/src/core/print_view_manager_qt.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "print_view_manager_qt.h" + +#include "type_conversion.h" +#include "web_engine_context.h" + +#include <QtGui/QPageLayout> +#include <QtGui/QPageSize> + +#include "base/values.h" +#include "chrome/browser/printing/print_job_manager.h" +#include "chrome/browser/printing/printer_query.h" +#include "components/printing/common/print_messages.h" +#include "content/public/browser/browser_thread.h" +#include "printing/pdf_metafile_skia.h" +#include "printing/print_job_constants.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(QtWebEngineCore::PrintViewManagerQt); + +namespace { +static int request_id = 0; +static const qreal kMicronsToMillimeter = 1000.0f; + +static scoped_refptr<base::RefCountedBytes> +GetDataFromHandle(base::SharedMemoryHandle handle, uint32 data_size) { + scoped_ptr<base::SharedMemory> shared_buf( + new base::SharedMemory(handle, true)); + + if (!shared_buf->Map(data_size)) { + NOTREACHED(); + return NULL; + } + + unsigned char* data = static_cast<unsigned char*>(shared_buf->memory()); + std::vector<unsigned char> dataVector(data, data + data_size); + return base::RefCountedBytes::TakeVector(&dataVector); +} + +// Write the PDF file to disk. +static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data, + const base::FilePath& path, + const base::Callback<void(bool)>& callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); + DCHECK_GT(data->size(), 0U); + + printing::PdfMetafileSkia metafile; + metafile.InitFromData(static_cast<const void*>(data->front()), data->size()); + + base::File file(path, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + bool ok = file.IsValid() && metafile.SaveTo(&file); + + if (!callback.is_null()) { + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(callback, ok)); + } +} + +static void applyQPageLayoutSettingsToDictionary(const QPageLayout& pageLayout, base::DictionaryValue& print_settings) +{ + //Set page size attributes, chromium expects these in micrometers + QSizeF pageSizeInMilimeter = pageLayout.pageSize().size(QPageSize::Millimeter); + scoped_ptr<base::DictionaryValue> sizeDict(new base::DictionaryValue); + sizeDict->SetInteger(printing::kSettingMediaSizeWidthMicrons, pageSizeInMilimeter.width() * kMicronsToMillimeter); + sizeDict->SetInteger(printing::kSettingMediaSizeHeightMicrons, pageSizeInMilimeter.height() * kMicronsToMillimeter); + print_settings.Set(printing::kSettingMediaSize, sizeDict.Pass()); + + print_settings.SetBoolean(printing::kSettingLandscape, pageLayout.orientation() == QPageLayout::Landscape); + + print_settings.SetInteger(printing::kPreviewRequestID, request_id++); + print_settings.SetBoolean(printing::kIsFirstRequest, request_id != 0); + + // The following are standard settings that Chromium expects to be set. + print_settings.SetBoolean(printing::kSettingPrintToPDF, true); + print_settings.SetBoolean(printing::kSettingCloudPrintDialog, false); + print_settings.SetBoolean(printing::kSettingPrintWithPrivet, false); + print_settings.SetBoolean(printing::kSettingPrintWithExtension, false); + + print_settings.SetBoolean(printing::kSettingGenerateDraftData, false); + print_settings.SetBoolean(printing::kSettingPreviewModifiable, false); + print_settings.SetInteger(printing::kSettingColor, printing::COLOR); + print_settings.SetInteger(printing::kSettingDuplexMode, printing::SIMPLEX); + print_settings.SetInteger(printing::kSettingDuplexMode, printing::UNKNOWN_DUPLEX_MODE); + print_settings.SetInteger(printing::kSettingCopies, 1); + print_settings.SetBoolean(printing::kSettingCollate, false); + print_settings.SetBoolean(printing::kSettingGenerateDraftData, false); + print_settings.SetBoolean(printing::kSettingPreviewModifiable, false); + + print_settings.SetBoolean(printing::kSettingShouldPrintSelectionOnly, false); + print_settings.SetBoolean(printing::kSettingShouldPrintBackgrounds, false); + print_settings.SetBoolean(printing::kSettingHeaderFooterEnabled, false); + print_settings.SetString(printing::kSettingDeviceName, ""); + print_settings.SetInteger(printing::kPreviewUIID, 12345678); +} + +} // namespace + +namespace QtWebEngineCore { + +PrintViewManagerQt::~PrintViewManagerQt() +{ +} + +#if defined(ENABLE_BASIC_PRINTING) +bool PrintViewManagerQt::PrintToPDF(const QPageLayout &pageLayout, const QString &filePath) +{ + return PrintToPDFWithCallback(pageLayout, filePath, base::Callback<void(bool)>()); +} + +bool PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout, const QString &filePath, base::Callback<void(bool)> callback) +{ + // If there already is a pending print in progress, don't try starting another one. + if (m_printSettings) + return false; + + m_printSettings.reset(new base::DictionaryValue()); + applyQPageLayoutSettingsToDictionary(pageLayout, *m_printSettings); + m_pdfOutputPath = toFilePath(filePath); + + return Send(new PrintMsg_InitiatePrintPreview(routing_id(), false)); +} +#endif // defined(ENABLE_BASIC_PRINTING) + +// PrintedPagesSource implementation. +base::string16 PrintViewManagerQt::RenderSourceName() +{ + return toString16(QLatin1String("")); +} + +PrintViewManagerQt::PrintViewManagerQt(content::WebContents *contents) + : PrintViewManagerBaseQt(contents) +{ + +} + +// content::WebContentsObserver implementation. +bool PrintViewManagerQt::OnMessageReceived(const IPC::Message& message) +{ + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PrintViewManagerQt, message) + IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) + IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview, + OnRequestPrintPreview) + IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting, + OnMetafileReadyForPrinting); + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled || PrintManager::OnMessageReceived(message); +} + +void PrintViewManagerQt::resetPdfState() +{ + m_pdfOutputPath.clear(); + m_pdfPrintCallback.Reset(); + m_printSettings.reset(); +} + +// IPC handlers + +void PrintViewManagerQt::OnRequestPrintPreview( + const PrintHostMsg_RequestPrintPreview_Params& params) +{ + Send(new PrintMsg_PrintPreview(routing_id(), *m_printSettings)); +} + +void PrintViewManagerQt::OnMetafileReadyForPrinting( + const PrintHostMsg_DidPreviewDocument_Params& params) +{ + StopWorker(params.document_cookie); + + scoped_refptr<base::RefCountedBytes> data_bytes = + GetDataFromHandle(params.metafile_data_handle, params.data_size); + if (!data_bytes || !data_bytes->size()) { + resetPdfState(); + return; + } + + // Create local copies so we can reset the state and take a new pdf print job. + base::Callback<void(bool)> pdf_print_callback = m_pdfPrintCallback; + base::FilePath pdfOutputPath = m_pdfOutputPath; + + // Save the PDF file to disk and then execute the callback. + content::BrowserThread::PostTask(content::BrowserThread::FILE, + FROM_HERE, + base::Bind(&SavePdfFile, data_bytes, pdfOutputPath, + pdf_print_callback)); + + resetPdfState(); +} + +void PrintViewManagerQt::OnDidShowPrintDialog() +{ +} + +// content::WebContentsObserver implementation. +void PrintViewManagerQt::DidStartLoading() +{ +} + +// content::WebContentsObserver implementation. +// Cancels the print job. +void PrintViewManagerQt::NavigationStopped() +{ + resetPdfState(); +} + +void PrintViewManagerQt::RenderProcessGone(base::TerminationStatus status) +{ + PrintViewManagerBaseQt::RenderProcessGone(status); + resetPdfState(); +} + + +} // namespace QtWebEngineCore diff --git a/src/core/print_view_manager_qt.h b/src/core/print_view_manager_qt.h new file mode 100644 index 000000000..6ef7ec754 --- /dev/null +++ b/src/core/print_view_manager_qt.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINT_VIEW_MANAGER_QT_H +#define PRINT_VIEW_MANAGER_QT_H + +#include "print_view_manager_base_qt.h" + +#include <QtWebEngineCore/qtwebenginecoreglobal.h> +#include "base/memory/ref_counted.h" +#include "base/prefs/pref_member.h" +#include "base/strings/string16.h" +#include "components/printing/browser/print_manager.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_user_data.h" +#include "printing/printed_pages_source.h" + +struct PrintHostMsg_RequestPrintPreview_Params; +struct PrintHostMsg_DidPreviewDocument_Params; + +namespace content { +class RenderViewHost; +} + +namespace printing { +class JobEventDetails; +class MetafilePlayer; +class PrintJob; +class PrintJobWorkerOwner; +class PrintQueriesQueue; +} + +QT_BEGIN_NAMESPACE +class QPageLayout; +class QString; +QT_END_NAMESPACE + +namespace QtWebEngineCore { +class PrintViewManagerQt + : PrintViewManagerBaseQt + , public content::WebContentsUserData<PrintViewManagerQt> +{ +public: + ~PrintViewManagerQt() override; + +#if defined(ENABLE_BASIC_PRINTING) + // Method to print a page to a Pdf document with page size \a pageSize in location \a filePath. + bool PrintToPDF(const QPageLayout& pageLayout, const QString& filePath); + bool PrintToPDFWithCallback(const QPageLayout& pageLayout, const QString& filePath, base::Callback<void(bool)> callback); +#endif // ENABLE_BASIC_PRINTING + + // PrintedPagesSource implementation. + base::string16 RenderSourceName() override; + +protected: + explicit PrintViewManagerQt(content::WebContents*); + + // content::WebContentsObserver implementation. + // Cancels the print job. + void NavigationStopped() override; + + // Terminates or cancels the print job if one was pending. + void RenderProcessGone(base::TerminationStatus status) override; + + // content::WebContentsObserver implementation. + bool OnMessageReceived(const IPC::Message& message) override; + + // IPC handlers + void OnDidShowPrintDialog(); + void OnRequestPrintPreview(const PrintHostMsg_RequestPrintPreview_Params&); + void OnMetafileReadyForPrinting(const PrintHostMsg_DidPreviewDocument_Params& params); + + base::FilePath m_pdfOutputPath; + base::Callback<void(bool)> m_pdfPrintCallback; + +private: + friend class content::WebContentsUserData<PrintViewManagerQt>; + + void resetPdfState(); + + // content::WebContentsObserver implementation. + void DidStartLoading() override; + DISALLOW_COPY_AND_ASSIGN(PrintViewManagerQt); +}; + +} // namespace QtWebEngineCore +#endif // PRINT_VIEW_MANAGER_QT_H + diff --git a/src/core/printing_message_filter_qt.cpp b/src/core/printing_message_filter_qt.cpp new file mode 100644 index 000000000..b9955fbb4 --- /dev/null +++ b/src/core/printing_message_filter_qt.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "printing_message_filter_qt.h" + +#include "web_engine_context.h" + +#include <string> + +#include "base/bind.h" +#include "chrome/browser/printing/print_job_manager.h" +#include "chrome/browser/printing/printer_query.h" +#include "components/printing/browser/print_manager_utils.h" +#include "components/printing/common/print_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/child_process_host.h" + +using content::BrowserThread; + +namespace QtWebEngineCore { + +PrintingMessageFilterQt::PrintingMessageFilterQt(int render_process_id) + : BrowserMessageFilter(PrintMsgStart), + render_process_id_(render_process_id), + queue_(WebEngineContext::current()->getPrintJobManager()->queue()) { + DCHECK(queue_.get()); +} + +PrintingMessageFilterQt::~PrintingMessageFilterQt() { +} + +void PrintingMessageFilterQt::OverrideThreadForMessage( + const IPC::Message& message, BrowserThread::ID* thread) { +} + +bool PrintingMessageFilterQt::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilterQt, message) +#if defined(OS_WIN) + IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection) +#endif + IPC_MESSAGE_HANDLER(PrintHostMsg_IsPrintingEnabled, OnIsPrintingEnabled) + IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, + OnGetDefaultPrintSettings) + IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) + IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings, + OnUpdatePrintSettings) + IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +#if defined(OS_WIN) +void PrintingMessageFilterQt::OnDuplicateSection( + base::SharedMemoryHandle renderer_handle, + base::SharedMemoryHandle* browser_handle) { + // Duplicate the handle in this process right now so the memory is kept alive + // (even if it is not mapped) + base::SharedMemory shared_buf(renderer_handle, true, PeerHandle()); + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle); +} +#endif + +void PrintingMessageFilterQt::OnIsPrintingEnabled(bool* is_enabled) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + *is_enabled = true; +} + +void PrintingMessageFilterQt::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + scoped_refptr<printing::PrinterQuery> printer_query; + + printer_query = queue_->PopPrinterQuery(0); + if (!printer_query.get()) { + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); + } + + // Loads default settings. This is asynchronous, only the IPC message sender + // will hang until the settings are retrieved. + printer_query->GetSettings( + printing::PrinterQuery::GetSettingsAskParam::DEFAULTS, + 0, + false, + printing::DEFAULT_MARGINS, + false, + base::Bind(&PrintingMessageFilterQt::OnGetDefaultPrintSettingsReply, + this, + printer_query, + reply_msg)); +} + +void PrintingMessageFilterQt::OnGetDefaultPrintSettingsReply( + scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg) { + PrintMsg_Print_Params params; + if (!printer_query.get() || + printer_query->last_status() != printing::PrintingContext::OK) { + params.Reset(); + } else { + RenderParamsFromPrintSettings(printer_query->settings(), ¶ms); + params.document_cookie = printer_query->cookie(); + } + PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params); + Send(reply_msg); + // If printing was enabled. + if (printer_query.get()) { + // If user hasn't cancelled. + if (printer_query->cookie() && printer_query->settings().dpi()) { + queue_->QueuePrinterQuery(printer_query.get()); + } else { + printer_query->StopWorker(); + } + } +} + +void PrintingMessageFilterQt::OnScriptedPrint( + const PrintHostMsg_ScriptedPrint_Params& params, + IPC::Message* reply_msg) { + scoped_refptr<printing::PrinterQuery> printer_query = + queue_->PopPrinterQuery(params.cookie); + if (!printer_query.get()) { + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); + } + printer_query->GetSettings( + printing::PrinterQuery::GetSettingsAskParam::ASK_USER, + params.expected_pages_count, + params.has_selection, + params.margin_type, + params.is_scripted, + base::Bind(&PrintingMessageFilterQt::OnScriptedPrintReply, + this, + printer_query, + reply_msg)); +} + +void PrintingMessageFilterQt::OnScriptedPrintReply( + scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg) { + PrintMsg_PrintPages_Params params; + + if (printer_query->last_status() != printing::PrintingContext::OK || + !printer_query->settings().dpi()) { + params.Reset(); + } else { + RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); + params.params.document_cookie = printer_query->cookie(); + params.pages = printing::PageRange::GetPages(printer_query->settings().ranges()); + } + PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params); + Send(reply_msg); + if (params.params.dpi && params.params.document_cookie) { + queue_->QueuePrinterQuery(printer_query.get()); + } else { + printer_query->StopWorker(); + } +} + +void PrintingMessageFilterQt::OnUpdatePrintSettings( + int document_cookie, const base::DictionaryValue& job_settings, + IPC::Message* reply_msg) { + scoped_ptr<base::DictionaryValue> new_settings(job_settings.DeepCopy()); + + scoped_refptr<printing::PrinterQuery> printer_query; + printer_query = queue_->PopPrinterQuery(document_cookie); + if (!printer_query.get()) { + int host_id = render_process_id_; + int routing_id = reply_msg->routing_id(); + if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId, + &host_id) || + !new_settings->GetInteger(printing::kPreviewInitiatorRoutingId, + &routing_id)) { + host_id = content::ChildProcessHost::kInvalidUniqueID; + routing_id = content::ChildProcessHost::kInvalidUniqueID; + } + printer_query = queue_->CreatePrinterQuery(host_id, routing_id); + } + printer_query->SetSettings( + new_settings.Pass(), + base::Bind(&PrintingMessageFilterQt::OnUpdatePrintSettingsReply, this, + printer_query, reply_msg)); +} + +void PrintingMessageFilterQt::OnUpdatePrintSettingsReply( + scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg) { + PrintMsg_PrintPages_Params params; + if (!printer_query.get() || + printer_query->last_status() != printing::PrintingContext::OK) { + params.Reset(); + } else { + RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); + params.params.document_cookie = printer_query->cookie(); + params.pages = printing::PageRange::GetPages(printer_query->settings().ranges()); + } + + PrintHostMsg_UpdatePrintSettings::WriteReplyParams( + reply_msg, + params, + printer_query.get() && + (printer_query->last_status() == printing::PrintingContext::CANCEL)); + Send(reply_msg); + // If user hasn't cancelled. + if (printer_query.get()) { + if (printer_query->cookie() && printer_query->settings().dpi()) { + queue_->QueuePrinterQuery(printer_query.get()); + } else { + printer_query->StopWorker(); + } + } +} + +void PrintingMessageFilterQt::OnCheckForCancel(int32 preview_ui_id, + int preview_request_id, + bool* cancel) { + *cancel = false; +} + +} // namespace printing diff --git a/src/core/printing_message_filter_qt.h b/src/core/printing_message_filter_qt.h new file mode 100644 index 000000000..004e5b86a --- /dev/null +++ b/src/core/printing_message_filter_qt.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINTING_PRINTING_MESSAGE_FILTER_QT_H_ +#define PRINTING_PRINTING_MESSAGE_FILTER_QT_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/prefs/pref_member.h" +#include "content/public/browser/browser_message_filter.h" + +#if defined(OS_WIN) +#include "base/memory/shared_memory.h" +#endif + +struct PrintHostMsg_ScriptedPrint_Params; + +namespace base { +class DictionaryValue; +class FilePath; +} + +namespace content { +class WebContents; +} + +namespace printing { + +class PrintJobManager; +class PrintQueriesQueue; +class PrinterQuery; +} + +namespace QtWebEngineCore { +// This class filters out incoming printing related IPC messages for the +// renderer process on the IPC thread. +class PrintingMessageFilterQt : public content::BrowserMessageFilter { + public: + PrintingMessageFilterQt(int render_process_id); + + // content::BrowserMessageFilter methods. + void OverrideThreadForMessage(const IPC::Message& message, + content::BrowserThread::ID* thread) override; + bool OnMessageReceived(const IPC::Message& message) override; + + private: + ~PrintingMessageFilterQt() override; + +#if defined(OS_WIN) + // Used to pass resulting EMF from renderer to browser in printing. + void OnDuplicateSection(base::SharedMemoryHandle renderer_handle, + base::SharedMemoryHandle* browser_handle); +#endif + + // GetPrintSettingsForRenderView must be called via PostTask and + // base::Bind. Collapse the settings-specific params into a + // struct to avoid running into issues with too many params + // to base::Bind. + struct GetPrintSettingsForRenderViewParams; + + // Checks if printing is enabled. + void OnIsPrintingEnabled(bool* is_enabled); + + // Get the default print setting. + void OnGetDefaultPrintSettings(IPC::Message* reply_msg); + void OnGetDefaultPrintSettingsReply(scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg); + + // The renderer host have to show to the user the print dialog and returns + // the selected print settings. The task is handled by the print worker + // thread and the UI thread. The reply occurs on the IO thread. + void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params, + IPC::Message* reply_msg); + void OnScriptedPrintReply(scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg); + + // Modify the current print settings based on |job_settings|. The task is + // handled by the print worker thread and the UI thread. The reply occurs on + // the IO thread. + void OnUpdatePrintSettings(int document_cookie, + const base::DictionaryValue& job_settings, + IPC::Message* reply_msg); + void OnUpdatePrintSettingsReply(scoped_refptr<printing::PrinterQuery> printer_query, + IPC::Message* reply_msg); + + // Check to see if print preview has been cancelled. + void OnCheckForCancel(int32 preview_ui_id, + int preview_request_id, + bool* cancel); + + const int render_process_id_; + + scoped_refptr<printing::PrintQueriesQueue> queue_; + + DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilterQt); +}; + +} // namespace printing + +#endif // PRINTING_PRINTING_MESSAGE_FILTER_QT_H_ diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index c4fcc4309..42bf43822 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -120,5 +120,22 @@ ['OS=="mac"', { 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, }], + ['enable_basic_printing==1 or enable_print_preview==1', { + 'dependencies': [ + '<(chromium_src_dir)/components/components.gyp:printing_browser', + '<(chromium_src_dir)/components/components.gyp:printing_common', + '<(chromium_src_dir)/components/components.gyp:printing_renderer', + ], + 'sources': [ + 'printing_message_filter_qt.cpp', + 'print_view_manager_base_qt.cpp', + 'print_view_manager_qt.cpp', + 'printing_message_filter_qt.h', + 'print_view_manager_base_qt.h', + 'print_view_manager_qt.h', + 'renderer/print_web_view_helper_delegate_qt.cpp', + 'renderer/print_web_view_helper_delegate_qt.h', + ] + }], ], } diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 36e4f83f1..77d93226c 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -50,6 +50,9 @@ #endif #include "components/cdm/renderer/widevine_key_systems.h" #include "components/error_page/common/error_page_params.h" +#if defined (ENABLE_BASIC_PRINTING) +#include "components/printing/renderer/print_web_view_helper.h" +#endif // if defined(ENABLE_BASIC_PRINTING) #include "components/visitedlink/renderer/visitedlink_slave.h" #include "components/web_cache/renderer/web_cache_render_process_observer.h" #include "content/public/renderer/render_frame.h" @@ -65,6 +68,10 @@ #include "content/public/common/web_preferences.h" #include "renderer/web_channel_ipc_transport.h" +#if defined (ENABLE_BASIC_PRINTING) +#include "renderer/print_web_view_helper_delegate_qt.h" +#endif // if defined(ENABLE_BASIC_PRINTING) + #include "renderer/render_frame_observer_qt.h" #include "renderer/render_view_observer_qt.h" #include "renderer/user_script_controller.h" @@ -112,6 +119,13 @@ void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view #if defined(ENABLE_SPELLCHECK) new SpellCheckProvider(render_view, m_spellCheck.data()); #endif + +#if defined(ENABLE_BASIC_PRINTING) + new printing::PrintWebViewHelper( + render_view, + scoped_ptr<printing::PrintWebViewHelper::Delegate>( + new PrintWebViewHelperDelegateQt())); +#endif // defined(ENABLE_BASIC_PRINTING) } void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.cpp b/src/core/renderer/print_web_view_helper_delegate_qt.cpp new file mode 100644 index 000000000..6d74685fe --- /dev/null +++ b/src/core/renderer/print_web_view_helper_delegate_qt.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "print_web_view_helper_delegate_qt.h" + +#include "third_party/WebKit/public/web/WebElement.h" + +namespace QtWebEngineCore { +PrintWebViewHelperDelegateQt::~PrintWebViewHelperDelegateQt() +{ + +} + +bool PrintWebViewHelperDelegateQt::CancelPrerender(content::RenderView* render_view, + int routing_id) +{ + return true; +} + +blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame* frame) +{ + return blink::WebElement(); +} + +bool PrintWebViewHelperDelegateQt::IsPrintPreviewEnabled() +{ + return false; +} + +bool PrintWebViewHelperDelegateQt::OverridePrint(blink::WebLocalFrame* frame) +{ + return false; +} + +} diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.h b/src/core/renderer/print_web_view_helper_delegate_qt.h new file mode 100644 index 000000000..a854242ba --- /dev/null +++ b/src/core/renderer/print_web_view_helper_delegate_qt.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PRINT_WEB_VIEW_HELPER_DELEGATE_QT_H +#define PRINT_WEB_VIEW_HELPER_DELEGATE_QT_H + +#include "components/printing/renderer/print_web_view_helper.h" + +namespace QtWebEngineCore { + +class PrintWebViewHelperDelegateQt : public printing::PrintWebViewHelper::Delegate +{ +public: + ~PrintWebViewHelperDelegateQt() override; + + bool CancelPrerender(content::RenderView* render_view, + int routing_id) override; + + blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override; + + bool IsPrintPreviewEnabled() override; + + bool OverridePrint(blink::WebLocalFrame* frame) override; +}; // class PrintWebViewHelperDelegateQt +} + +#endif // PRINT_WEB_VIEW_HELPER_DELEGATE_QT_H + diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index c28d60f95..f4574f8b3 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -48,6 +48,9 @@ #include "base/run_loop.h" #include "base/threading/thread_restrictions.h" #include "cc/base/switches.h" +#if defined(ENABLE_BASIC_PRINTING) +#include "chrome/browser/printing/print_job_manager.h" +#endif // defined(ENABLE_BASIC_PRINTING) #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/utility_process_host_impl.h" @@ -287,6 +290,16 @@ WebEngineContext::WebEngineContext() // thread to avoid a thread check assertion in its constructor when it // first gets referenced on the IO thread. MediaCaptureDevicesDispatcher::GetInstance(); + +#if defined(ENABLE_BASIC_PRINTING) + m_printJobManager.reset(new printing::PrintJobManager()); +#endif // defined(ENABLE_BASIC_PRINTING) } +#if defined(ENABLE_BASIC_PRINTING) +printing::PrintJobManager* WebEngineContext::getPrintJobManager() +{ + return m_printJobManager.get(); +} +#endif // defined(ENABLE_BASIC_PRINTING) } // namespace diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index 6d40d72a2..3c69d87ca 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -58,6 +58,12 @@ class BrowserMainRunner; class ContentMainRunner; } +#if defined(ENABLE_BASIC_PRINTING) +namespace printing { +class PrintJobManager; +} +#endif // defined(ENABLE_BASIC_PRINTING) + QT_FORWARD_DECLARE_CLASS(QObject) namespace QtWebEngineCore { @@ -72,7 +78,9 @@ public: QtWebEngineCore::BrowserContextAdapter *defaultBrowserContext(); QObject *globalQObject(); - +#if defined(ENABLE_BASIC_PRINTING) + printing::PrintJobManager* getPrintJobManager(); +#endif // defined(ENABLE_BASIC_PRINTING) void destroyBrowserContext(); void destroy(); @@ -88,6 +96,9 @@ private: QObject* m_globalQObject; QExplicitlySharedDataPointer<BrowserContextAdapter> m_defaultBrowserContext; scoped_ptr<devtools_http_handler::DevToolsHttpHandler> m_devtools; +#if defined(ENABLE_BASIC_PRINTING) + scoped_ptr<printing::PrintJobManager> m_printJobManager; +#endif // defined(ENABLE_BASIC_PRINTING) }; } // namespace |