chromium/content/browser/android/render_widget_host_connector.cc

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

#include "content/browser/android/render_widget_host_connector.h"

#include "base/memory/raw_ptr.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "content/browser/web_contents/web_contents_android.h"
#include "content/browser/web_contents/web_contents_impl.h"

namespace content {

// Observes RenderWidgetHostViewAndroid to keep the instance up to date.
class RenderWidgetHostConnector::Observer
    : public WebContentsObserver,
      public WebContentsAndroid::DestructionObserver,
      public RenderWidgetHostViewAndroid::DestructionObserver {
 public:
  Observer(WebContents* web_contents, RenderWidgetHostConnector* connector);

  Observer(const Observer&) = delete;
  Observer& operator=(const Observer&) = delete;

  ~Observer() override;

  // WebContentsObserver implementation.
  void RenderViewReady() override;
  void RenderFrameHostChanged(RenderFrameHost* old_host,
                              RenderFrameHost* new_host) override;

  // WebContentsAndroid::DestructionObserver implementation.
  void WebContentsAndroidDestroyed(
      WebContentsAndroid* web_contents_android) override;

  // RenderWidgetHostViewAndroid::DestructionObserver implementation.
  void RenderWidgetHostViewDestroyed(
      RenderWidgetHostViewAndroid* rwhva) override;

  void DestroyEarly();
  void UpdateRenderWidgetHostView(RenderWidgetHostViewAndroid* new_rwhva);
  RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid() const;
  RenderWidgetHostViewAndroid* active_rwhva() const { return active_rwhva_; }

 private:
  void DoDestroy(WebContentsAndroid* web_contents_android);

  const raw_ptr<RenderWidgetHostConnector> connector_;

  // Active RenderWidgetHostView connected to this instance.
  raw_ptr<RenderWidgetHostViewAndroid> active_rwhva_;
};

RenderWidgetHostConnector::Observer::Observer(
    WebContents* web_contents,
    RenderWidgetHostConnector* connector)
    : WebContentsObserver(web_contents),
      connector_(connector),
      active_rwhva_(nullptr) {
  static_cast<WebContentsImpl*>(web_contents)
      ->GetWebContentsAndroid()
      ->AddDestructionObserver(this);
}

RenderWidgetHostConnector::Observer::~Observer() {
  DCHECK(!active_rwhva_);
}

void RenderWidgetHostConnector::Observer::RenderViewReady() {
  UpdateRenderWidgetHostView(GetRenderWidgetHostViewAndroid());
}

void RenderWidgetHostConnector::Observer::RenderFrameHostChanged(
    RenderFrameHost* old_host,
    RenderFrameHost* new_host) {
  if (!new_host->IsInPrimaryMainFrame()) {
    return;
  }

  auto* new_view = new_host ? static_cast<RenderWidgetHostViewBase*>(
                                  new_host->GetRenderWidgetHost()->GetView())
                            : nullptr;
  DCHECK(!new_view || !new_view->IsRenderWidgetHostViewChildFrame());
  auto* new_view_android = static_cast<RenderWidgetHostViewAndroid*>(new_view);
  UpdateRenderWidgetHostView(new_view_android);
}

void RenderWidgetHostConnector::Observer::WebContentsAndroidDestroyed(
    WebContentsAndroid* web_contents_android) {
  DoDestroy(web_contents_android);
}

void RenderWidgetHostConnector::Observer::DestroyEarly() {
  DoDestroy(
      static_cast<WebContentsImpl*>(web_contents())->GetWebContentsAndroid());
}

void RenderWidgetHostConnector::Observer::DoDestroy(
    WebContentsAndroid* web_contents_android) {
  web_contents_android->RemoveDestructionObserver(this);
  DCHECK(!active_rwhva_ || active_rwhva_ == GetRenderWidgetHostViewAndroid());
  UpdateRenderWidgetHostView(nullptr);
  delete connector_;
}

void RenderWidgetHostConnector::Observer::RenderWidgetHostViewDestroyed(
    RenderWidgetHostViewAndroid* destroyed_rwhva) {
  // Null out the raw pointer here and in the connector impl to keep
  // them from referencing the rwvha about to be destroyed.
  if (destroyed_rwhva == active_rwhva_)
    UpdateRenderWidgetHostView(nullptr);
}

void RenderWidgetHostConnector::Observer::UpdateRenderWidgetHostView(
    RenderWidgetHostViewAndroid* new_rwhva) {
  if (active_rwhva_ == new_rwhva)
    return;
  if (active_rwhva_)
    active_rwhva_->RemoveDestructionObserver(this);
  if (new_rwhva)
    new_rwhva->AddDestructionObserver(this);

  connector_->UpdateRenderProcessConnection(active_rwhva_, new_rwhva);
  active_rwhva_ = new_rwhva;
}

RenderWidgetHostViewAndroid*
RenderWidgetHostConnector::Observer::GetRenderWidgetHostViewAndroid() const {
  RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
  DCHECK(!rwhv || !static_cast<RenderWidgetHostViewBase*>(rwhv)
                       ->IsRenderWidgetHostViewChildFrame());
  return static_cast<RenderWidgetHostViewAndroid*>(rwhv);
}

RenderWidgetHostConnector::RenderWidgetHostConnector(WebContents* web_contents)
    : render_widget_observer_(new Observer(web_contents, this)) {}

void RenderWidgetHostConnector::Initialize() {
  render_widget_observer_->UpdateRenderWidgetHostView(
      render_widget_observer_->GetRenderWidgetHostViewAndroid());
}

RenderWidgetHostConnector::~RenderWidgetHostConnector() {}

RenderWidgetHostViewAndroid* RenderWidgetHostConnector::GetRWHVAForTesting()
    const {
  return render_widget_observer_->active_rwhva();
}

void RenderWidgetHostConnector::DestroyEarly() {
  render_widget_observer_->DestroyEarly();
}

WebContents* RenderWidgetHostConnector::web_contents() const {
  return render_widget_observer_->web_contents();
}

}  // namespace content