// 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 "android_webview/browser/aw_print_manager.h" #include #include "base/bind.h" #include "base/file_descriptor_posix.h" #include "base/files/file_util.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 "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "printing/print_job_constants.h" namespace android_webview { namespace { uint32_t SaveDataToFd(int fd, uint32_t page_count, scoped_refptr data) { bool result = fd > base::kInvalidFd && base::IsValueInRangeForNumericType(data->size()); if (result) result = base::WriteFileDescriptor(fd, *data); return result ? page_count : 0; } } // namespace AwPrintManager::AwPrintManager(content::WebContents* contents) : PrintManager(contents), content::WebContentsUserData(*contents) {} AwPrintManager::~AwPrintManager() = default; // static void AwPrintManager::BindPrintManagerHost( mojo::PendingAssociatedReceiver 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(); std::move(callback).Run(std::move(params)); } void AwPrintManager::UpdateParam( std::unique_ptr 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(1); // Set a valid dummy cookie value. } void AwPrintManager::ScriptedPrint( printing::mojom::ScriptedPrintParamsPtr scripted_params, ScriptedPrintCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); auto params = printing::mojom::PrintPagesParams::New(); params->params = printing::mojom::PrintParams::New(); 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(std::move(params)); return; } printing::RenderParamsFromPrintSettings(*settings_, params->params.get()); params->params->document_cookie = scripted_params->cookie; params->pages = settings_->ranges(); 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::PostTaskAndReplyWithResult( base::ThreadPool::CreateTaskRunner( {base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}) .get(), 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(page_count)); std::move(did_print_document_cb).Run(true); } WEB_CONTENTS_USER_DATA_KEY_IMPL(AwPrintManager); } // namespace android_webview