chromium/chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/printing/print_preview/print_view_manager_cros.h"

#include <utility>

#include "base/unguessable_token.h"
#include "chrome/browser/chromeos/printing/print_preview/print_preview_ui_wrapper.h"
#include "chrome/browser/chromeos/printing/print_preview/print_preview_webcontents_manager.h"
#include "components/printing/common/print.mojom.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "printing/print_job_constants.h"
#include "stdint.h"

namespace chromeos {

PrintViewManagerCros::PrintViewManagerCros(content::WebContents* web_contents)
    : PrintViewManagerCrosBase(web_contents),
      content::WebContentsUserData<PrintViewManagerCros>(*web_contents),
      token_(base::UnguessableToken::Create()) {}

PrintViewManagerCros::~PrintViewManagerCros() {
  if (ui_wrapper_) {
    ui_wrapper_->Reset();
  }
}

// static
void PrintViewManagerCros::BindPrintManagerHost(
    mojo::PendingAssociatedReceiver<::printing::mojom::PrintManagerHost>
        receiver,
    content::RenderFrameHost* rfh) {
  CHECK(rfh);

  auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
  CHECK(web_contents);

  // An instance of PrintViewManagerCros is guaranteed to be available if
  // binding a PrintManagerHost.
  auto* print_manager = PrintViewManagerCros::FromWebContents(web_contents);
  CHECK(print_manager);

  print_manager->BindReceiver(std::move(receiver), rfh);
}

// TODO(jimmyxgong): Implement stubs.
void PrintViewManagerCros::DidShowPrintDialog() {}

void PrintViewManagerCros::SetupScriptedPrintPreview(
    SetupScriptedPrintPreviewCallback callback) {}

void PrintViewManagerCros::ShowScriptedPrintPreview(bool source_is_modifiable) {
}

void PrintViewManagerCros::RequestPrintPreview(
    ::printing::mojom::RequestPrintPreviewParamsPtr params) {
  PrintPreviewWebcontentsManager::Get()->RequestPrintPreview(
      token_, web_contents(), std::move(params));
}

void PrintViewManagerCros::CheckForCancel(int32_t preview_ui_id,
                                          int32_t request_id,
                                          CheckForCancelCallback callback) {
  std::move(callback).Run(
      PrintPreviewUiWrapper::ShouldCancelRequest(preview_ui_id, request_id));
}

void PrintViewManagerCros::RenderFrameDeleted(
    content::RenderFrameHost* render_frame_host) {
  if (render_frame_host_ == render_frame_host) {
    PrintPreviewDone();
  }
  // TODO(jimmyxgong): Attempt to remove a print job if active.
}

bool PrintViewManagerCros::PrintPreviewNow(content::RenderFrameHost* rfh,
                                           bool has_selection) {
  CHECK(rfh);

  // Don't print / print preview crashed tabs.
  // If the render frame is not live, it's possible we'll never get the
  // `RenderFrameDeleted` observer call and may lead to a UaF
  // render_frame_host_.
  if (IsCrashed() || !rfh->IsRenderFrameLive()) {
    return false;
  }

  // TODO(b/339311234): Handle passing a print renderer remote from android.
  GetPrintRenderFrame(rfh)->InitiatePrintPreview(
#if BUILDFLAG(IS_CHROMEOS_ASH)
      mojo::NullAssociatedRemote(),
#endif
      has_selection);
  DCHECK(!render_frame_host_);
  render_frame_host_ = rfh;
  // Upon re-opening the print dialog, we should also reset the print preview
  // UI wrapper.
  if (ui_wrapper_) {
    ui_wrapper_->Reset();
  }
  ui_wrapper_.reset();
  ui_wrapper_ = std::make_unique<PrintPreviewUiWrapper>();
  ui_wrapper_->BindPrintPreviewUI(rfh);
  return true;
}

void PrintViewManagerCros::PrintPreviewDone() {
  PrintPreviewWebcontentsManager::Get()->PrintPreviewDone(token_);
  HandlePrintPreviewRemoved();
}

void PrintViewManagerCros::HandlePrintPreviewRemoved() {
  CHECK(render_frame_host_);

  if (render_frame_host_->IsRenderFrameLive() &&
      IsPrintRenderFrameConnected(render_frame_host_)) {
    GetPrintRenderFrame(render_frame_host_)->OnPrintPreviewDialogClosed();
  }
  render_frame_host_ = nullptr;

  if (ui_wrapper_) {
    ui_wrapper_->Reset();
  }
}

void PrintViewManagerCros::HandleGeneratePrintPreview(
    const base::Value::Dict& settings) {
  ui_wrapper_->GeneratePrintPreview(settings.Clone());
}

WEB_CONTENTS_USER_DATA_KEY_IMPL(PrintViewManagerCros);

}  // namespace chromeos