| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "android_webview/browser/aw_print_manager.h" |
| |
| #include <utility> |
| |
| #include "base/file_descriptor_posix.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "components/printing/browser/print_manager_utils.h" |
| #include "components/printing/common/print.mojom.h" |
| #include "components/printing/common/print_params.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "printing/print_job_constants.h" |
| #include "printing/print_settings.h" |
| |
| namespace android_webview { |
| |
| namespace { |
| |
| uint32_t SaveDataToFd(int fd, |
| uint32_t page_count, |
| scoped_refptr<base::RefCountedSharedMemoryMapping> data) { |
| bool result = fd > base::kInvalidFd && |
| base::IsValueInRangeForNumericType<int>(data->size()); |
| if (result) |
| result = base::WriteFileDescriptor(fd, *data); |
| return result ? page_count : 0; |
| } |
| |
| } // namespace |
| |
| AwPrintManager::AwPrintManager(content::WebContents* contents) |
| : PrintManager(contents), |
| content::WebContentsUserData<AwPrintManager>(*contents) {} |
| |
| AwPrintManager::~AwPrintManager() = default; |
| |
| // static |
| void AwPrintManager::BindPrintManagerHost( |
| mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost> receiver, |
| content::RenderFrameHost* rfh) { |
| auto* web_contents = content::WebContents::FromRenderFrameHost(rfh); |
| if (!web_contents) |
| return; |
| auto* print_manager = AwPrintManager::FromWebContents(web_contents); |
| if (!print_manager) |
| return; |
| print_manager->BindReceiver(std::move(receiver), rfh); |
| } |
| |
| void AwPrintManager::PdfWritingDone(int page_count) { |
| pdf_writing_done_callback().Run(page_count); |
| // Invalidate the file descriptor so it doesn't get reused. |
| fd_ = -1; |
| } |
| |
| bool AwPrintManager::PrintNow() { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| auto* rfh = web_contents()->GetPrimaryMainFrame(); |
| if (!rfh->IsRenderFrameLive()) |
| return false; |
| GetPrintRenderFrame(rfh)->PrintRequestedPages(); |
| return true; |
| } |
| |
| void AwPrintManager::GetDefaultPrintSettings( |
| GetDefaultPrintSettingsCallback callback) { |
| // Unlike PrintViewManagerBase, we do process this in UI thread. |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| auto params = printing::mojom::PrintParams::New(); |
| printing::RenderParamsFromPrintSettings(*settings_, params.get()); |
| params->document_cookie = cookie(); |
| if (!printing::PrintMsgPrintParamsIsValid(*params)) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| |
| std::move(callback).Run(std::move(params)); |
| } |
| |
| void AwPrintManager::UpdateParam( |
| std::unique_ptr<printing::PrintSettings> settings, |
| int file_descriptor, |
| PrintManager::PdfWritingDoneCallback callback) { |
| DCHECK(settings); |
| DCHECK(callback); |
| settings_ = std::move(settings); |
| fd_ = file_descriptor; |
| set_pdf_writing_done_callback(std::move(callback)); |
| set_cookie(printing::PrintSettings::NewCookie()); |
| } |
| |
| void AwPrintManager::ScriptedPrint( |
| printing::mojom::ScriptedPrintParamsPtr scripted_params, |
| ScriptedPrintCallback callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| |
| if (scripted_params->is_scripted && |
| GetCurrentTargetFrame()->IsNestedWithinFencedFrame()) { |
| DLOG(ERROR) << "Unexpected message received. Script Print is not allowed" |
| " in a fenced frame."; |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| |
| auto params = printing::mojom::PrintPagesParams::New(); |
| params->params = printing::mojom::PrintParams::New(); |
| printing::RenderParamsFromPrintSettings(*settings_, params->params.get()); |
| params->params->document_cookie = scripted_params->cookie; |
| params->pages = settings_->ranges(); |
| |
| if (!printing::PrintMsgPrintParamsIsValid(*params->params)) { |
| std::move(callback).Run(nullptr); |
| return; |
| } |
| |
| std::move(callback).Run(std::move(params)); |
| } |
| |
| void AwPrintManager::DidPrintDocument( |
| printing::mojom::DidPrintDocumentParamsPtr params, |
| DidPrintDocumentCallback callback) { |
| if (params->document_cookie != cookie()) { |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| const printing::mojom::DidPrintContentParams& content = *params->content; |
| if (!content.metafile_data_region.IsValid()) { |
| NOTREACHED() << "invalid memory handle"; |
| web_contents()->Stop(); |
| PdfWritingDone(0); |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| auto data = base::RefCountedSharedMemoryMapping::CreateFromWholeRegion( |
| content.metafile_data_region); |
| if (!data) { |
| NOTREACHED() << "couldn't map"; |
| web_contents()->Stop(); |
| PdfWritingDone(0); |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| if (number_pages() > printing::kMaxPageCount) { |
| web_contents()->Stop(); |
| PdfWritingDone(0); |
| std::move(callback).Run(false); |
| return; |
| } |
| |
| DCHECK(pdf_writing_done_callback()); |
| base::ThreadPool::CreateTaskRunner( |
| {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
| base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}) |
| ->PostTaskAndReplyWithResult( |
| FROM_HERE, base::BindOnce(&SaveDataToFd, fd_, number_pages(), data), |
| base::BindOnce(&AwPrintManager::OnDidPrintDocumentWritingDone, |
| pdf_writing_done_callback(), std::move(callback))); |
| } |
| |
| // static |
| void AwPrintManager::OnDidPrintDocumentWritingDone( |
| const PdfWritingDoneCallback& callback, |
| DidPrintDocumentCallback did_print_document_cb, |
| uint32_t page_count) { |
| DCHECK_LE(page_count, printing::kMaxPageCount); |
| if (callback) |
| callback.Run(base::checked_cast<int>(page_count)); |
| std::move(did_print_document_cb).Run(true); |
| } |
| |
| WEB_CONTENTS_USER_DATA_KEY_IMPL(AwPrintManager); |
| |
| } // namespace android_webview |