1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130

content / browser / display_cutout / display_cutout_host_impl.cc [blame]

// Copyright 2018 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/display_cutout/display_cutout_host_impl.h"

#include "content/browser/display_cutout/display_cutout_constants.h"
#include "content/browser/display_cutout/safe_area_insets_host.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/navigation_handle.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"

namespace content {

DisplayCutoutHostImpl::DisplayCutoutHostImpl(WebContentsImpl* web_contents)
    : SafeAreaInsetsHost(web_contents) {}

DisplayCutoutHostImpl::~DisplayCutoutHostImpl() = default;

void DisplayCutoutHostImpl::ViewportFitChangedForFrame(
    RenderFrameHost* rfh,
    blink::mojom::ViewportFit value) {
  if (GetValueOrDefault(rfh) == value)
    return;

  values_[rfh] = value;

  // If we are the current |RenderFrameHost| frame then notify
  // WebContentsObservers about the new value.
  if (current_rfh_.get() == rfh)
    web_contents_impl_->NotifyViewportFitChanged(value);
}

void DisplayCutoutHostImpl::DidAcquireFullscreen(RenderFrameHost* rfh) {
  SetCurrentRenderFrameHost(rfh);
}

void DisplayCutoutHostImpl::DidExitFullscreen() {
  SetCurrentRenderFrameHost(nullptr);
}

void DisplayCutoutHostImpl::DidFinishNavigation(
    NavigationHandle* navigation_handle) {
  // If the navigation is not in the main frame or if we are a same document
  // navigation then we should stop now.
  if (!navigation_handle->IsInPrimaryMainFrame() ||
      navigation_handle->IsSameDocument()) {
    return;
  }

  // When Edge To Edge on Android is enabled it needs the messaging sent to
  // Java.
  bool is_not_just_fullscreen =
      base::FeatureList::IsEnabled(features::kDrawCutoutEdgeToEdge);

  // If we finish a main frame navigation and the |WebDisplayMode| is
  // fullscreen then we should make the main frame the current
  // |RenderFrameHost|.  Note that this is probably not correct; we do not check
  // that the navigation completed successfully, nor do we check if the main
  // frame is still IsRenderFrameLive().
  blink::mojom::DisplayMode mode = web_contents_impl_->GetDisplayMode();
  if (is_not_just_fullscreen ||
      mode == blink::mojom::DisplayMode::kFullscreen) {
    SetCurrentRenderFrameHost(web_contents_impl_->GetPrimaryMainFrame());
  }
}

void DisplayCutoutHostImpl::RenderFrameDeleted(RenderFrameHost* rfh) {
  values_.erase(rfh);

  // If we were the current |RenderFrameHost| then we should clear that.
  if (current_rfh_.get() == rfh)
    SetCurrentRenderFrameHost(nullptr);
}

void DisplayCutoutHostImpl::RenderFrameCreated(RenderFrameHost* rfh) {
  ViewportFitChangedForFrame(rfh, blink::mojom::ViewportFit::kAuto);
}

void DisplayCutoutHostImpl::SetDisplayCutoutSafeArea(gfx::Insets insets) {
  insets_ = insets;

  if (current_rfh_)
    SendSafeAreaToFrame(current_rfh_.get(), insets);
}

void DisplayCutoutHostImpl::SetCurrentRenderFrameHost(RenderFrameHost* rfh) {
  if (current_rfh_.get() == rfh) {
    if (rfh) {
      // Send an update even when navigating to the same page or doing a reload.
      // When we finish navigation we need to push the Safe Area back to the
      // client to set env() variables for that frame so it can draw correctly.
      SendSafeAreaToFrame(rfh, insets_);
    }
    return;
  }

  // If we had a previous frame then we should clear the insets on that frame.
  if (current_rfh_)
    SendSafeAreaToFrame(current_rfh_.get(), gfx::Insets());

  // If the new RenderFrameHost is nullptr we should stop here and notify
  // observers that the new viewport fit is kAuto (the default).
  if (!rfh) {
    current_rfh_ = nullptr;
    web_contents_impl_->NotifyViewportFitChanged(
        blink::mojom::ViewportFit::kAuto);
    return;
  }

  // Update the |current_rfh_| with the new frame.
  current_rfh_ = static_cast<RenderFrameHostImpl*>(rfh)->GetWeakPtr();

  // Send the current safe area to the new frame.
  SendSafeAreaToFrame(rfh, insets_);

  // Notify the WebContentsObservers that the viewport fit value has changed.
  web_contents_impl_->NotifyViewportFitChanged(GetValueOrDefault(rfh));
}

blink::mojom::ViewportFit DisplayCutoutHostImpl::GetValueOrDefault(
    RenderFrameHost* rfh) const {
  auto value = values_.find(rfh);
  if (value != values_.end())
    return value->second;
  return blink::mojom::ViewportFit::kAuto;
}

}  // namespace content