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
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312

content / browser / renderer_host / delegated_frame_host.h [blame]

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

#ifndef CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_
#define CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_

#include <stdint.h>

#include <vector>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "components/viz/client/frame_evictor.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_timing_details_map.h"
#include "components/viz/common/hit_test/hit_test_query.h"
#include "components/viz/host/host_frame_sink_client.h"
#include "components/viz/host/host_frame_sink_manager.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/common/content_export.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
#include "services/viz/public/mojom/hit_test/hit_test_region_list.mojom.h"
#include "third_party/blink/public/common/page/content_to_visible_time_reporter.h"
#include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom-forward.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_observer.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/rect_conversions.h"

namespace content {

class DelegatedFrameHost;

// The DelegatedFrameHostClient is the interface from the DelegatedFrameHost,
// which manages delegated frames, and the ui::Compositor being used to
// display them.
class CONTENT_EXPORT DelegatedFrameHostClient {
 public:
  virtual ~DelegatedFrameHostClient() {}

  virtual ui::Layer* DelegatedFrameHostGetLayer() const = 0;
  virtual bool DelegatedFrameHostIsVisible() const = 0;
  // Returns the color that the resize gutters should be drawn with.
  virtual SkColor DelegatedFrameHostGetGutterColor() const = 0;
  virtual void OnFrameTokenChanged(uint32_t frame_token,
                                   base::TimeTicks activation_time) = 0;
  virtual float GetDeviceScaleFactor() const = 0;
  virtual void InvalidateLocalSurfaceIdOnEviction() = 0;
  virtual viz::FrameEvictorClient::EvictIds CollectSurfaceIdsForEviction() = 0;
  virtual bool ShouldShowStaleContentOnEviction() = 0;
};

// The DelegatedFrameHost is used to host all of the RenderWidgetHostView state
// and functionality that is associated with delegated frames being sent from
// the RenderWidget. The DelegatedFrameHost will push these changes through to
// the ui::Compositor associated with its DelegatedFrameHostClient.
class CONTENT_EXPORT DelegatedFrameHost
    : public ui::CompositorObserver,
      public viz::FrameEvictorClient,
      public viz::HostFrameSinkClient {
 public:
  enum class FrameEvictionState {
    kNotStarted = 0,          // Frame eviction is ready.
    kPendingEvictionRequests  // Frame eviction is paused with pending requests.
  };

  class Observer {
   public:
    virtual void OnFrameEvictionStateChanged(FrameEvictionState new_state) = 0;

   protected:
    virtual ~Observer() = default;
  };

  // |should_register_frame_sink_id| flag indicates whether DelegatedFrameHost
  // is responsible for registering the associated FrameSinkId with the
  // compositor or not. This is set only on non-aura platforms, since aura is
  // responsible for doing the appropriate [un]registration.
  DelegatedFrameHost(const viz::FrameSinkId& frame_sink_id,
                     DelegatedFrameHostClient* client,
                     bool should_register_frame_sink_id);

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

  ~DelegatedFrameHost() override;

  void AddObserverForTesting(Observer* observer);
  void RemoveObserverForTesting(Observer* observer);

  // ui::CompositorObserver implementation.
  void OnCompositingShuttingDown(ui::Compositor* compositor) override;

  void ClearFallbackSurfaceForCommitPending();
  void ResetFallbackToFirstNavigationSurface();

  // viz::HostFrameSinkClient implementation.
  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
  void OnFrameTokenChanged(uint32_t frame_token,
                           base::TimeTicks activation_time) override;

  // Public interface exposed to RenderWidgetHostView.

  // kOccluded means the native window for the host was
  // occluded/hidden, kOther is for other causes, e.g., a tab became a
  // background tab.
  enum class HiddenCause { kOccluded, kOther };

  void WasHidden(HiddenCause cause);

  // TODO(ccameron): Include device scale factor here.
  void WasShown(const viz::LocalSurfaceId& local_surface_id,
                const gfx::Size& dip_size,
                blink::mojom::RecordContentToVisibleTimeRequestPtr
                    record_tab_switch_time_request);

  // Called to request the presentation time for the next frame or cancel any
  // requests when the RenderWidget's visibility state is not changing. If the
  // visibility state is changing call WasHidden or WasShown instead.
  void RequestSuccessfulPresentationTimeForNextFrame(
      blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request);
  void CancelSuccessfulPresentationTimeRequest();

  void EmbedSurface(const viz::LocalSurfaceId& local_surface_id,
                    const gfx::Size& dip_size,
                    cc::DeadlinePolicy deadline_policy);
  bool HasSavedFrame() const;
  void AttachToCompositor(ui::Compositor* compositor);
  void DetachFromCompositor();

  // Copies |src_subrect| from the compositing surface into a bitmap (first
  // overload) or texture (second overload). |output_size| specifies the size of
  // the output bitmap or texture.
  // Note: |src_subrect| is specified in DIP dimensions while |output_size|
  // expects pixels. If |src_subrect| is empty, the entire surface area is
  // copied.
  void CopyFromCompositingSurface(
      const gfx::Rect& src_subrect,
      const gfx::Size& output_size,
      base::OnceCallback<void(const SkBitmap&)> callback);
  void CopyFromCompositingSurfaceAsTexture(
      const gfx::Rect& src_subrect,
      const gfx::Size& output_size,
      viz::CopyOutputRequest::CopyOutputRequestCallback callback);

  bool CanCopyFromCompositingSurface() const;
  const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }

  // FrameEvictorClient:
  // Returns the surface id for the most recently embedded surface.
  viz::SurfaceId GetCurrentSurfaceId() const override;

  bool HasPrimarySurface() const;
  bool HasFallbackSurface() const;

  viz::SurfaceId GetFallbackSurfaceIdForTesting() const;

  void OnCompositingDidCommitForTesting(ui::Compositor* compositor) {
    OnCompositingDidCommit(compositor);
  }

  gfx::Size CurrentFrameSizeInDipForTesting() const {
    return current_frame_size_in_dip_;
  }

  void DidNavigate();

  // Navigation to a different page than the current one has begun. Caches the
  // current LocalSurfaceId information so that old content can be evicted if
  // navigation fails to complete.
  void DidNavigateMainFramePreCommit();

  // Called when the page has just entered BFCache.
  void DidEnterBackForwardCache();

  void WindowTitleChanged(const std::string& title);

  // If our SurfaceLayer doesn't have a fallback, use the fallback info of
  // |other|.
  void TakeFallbackContentFrom(DelegatedFrameHost* other);

  base::WeakPtr<DelegatedFrameHost> GetWeakPtr() {
    return weak_factory_.GetWeakPtr();
  }

  const ui::Layer* stale_content_layer() const {
    return stale_content_layer_.get();
  }

  FrameEvictionState frame_eviction_state() const {
    return frame_eviction_state_;
  }

  const viz::FrameEvictor* GetFrameEvictorForTesting() const {
    return frame_evictor_.get();
  }

  viz::SurfaceId GetPreNavigationSurfaceIdForTesting() const {
    return GetPreNavigationSurfaceId();
  }

  viz::SurfaceId GetFirstSurfaceIdAfterNavigationForTesting() const;

  void SetIsFrameSinkIdOwner(bool is_owner);

  // This is used to evict also the UI compositor if native occlusion is
  // enabled. This only makes sense on desktop platforms where the UI compositor
  // corresponds to a browser window, and native occlusion is supported.
  static bool ShouldIncludeUiCompositorForEviction();

 private:
  friend class DelegatedFrameHostClient;
  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
                           StaleFrameContentOnEvictionNormal);
  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
                           StaleFrameContentOnEvictionRejected);
  FRIEND_TEST_ALL_PREFIXES(RenderWidgetHostViewAuraBrowserTest,
                           StaleFrameContentOnEvictionNone);
  FRIEND_TEST_ALL_PREFIXES(NoCompositingRenderWidgetHostViewBrowserTest,
                           BFCachedSurfaceShouldNotBeEvicted);

  // FrameEvictorClient implementation.
  void EvictDelegatedFrame(
      const std::vector<viz::SurfaceId>& surface_ids) override;
  viz::FrameEvictorClient::EvictIds CollectSurfaceIdsForEviction()
      const override;
  viz::SurfaceId GetPreNavigationSurfaceId() const override;

  void DidCopyStaleContent(std::unique_ptr<viz::CopyOutputResult> result);

  void ContinueDelegatedFrameEviction(
      const std::vector<viz::SurfaceId>& surface_ids);

  SkColor GetGutterColor() const;

  void CopyFromCompositingSurfaceInternal(
      const gfx::Rect& src_subrect,
      const gfx::Size& output_size,
      viz::CopyOutputRequest::ResultFormat format,
      viz::CopyOutputRequest::ResultDestination destination,
      viz::CopyOutputRequest::CopyOutputRequestCallback callback);

  void SetFrameEvictionStateAndNotifyObservers(
      FrameEvictionState frame_eviction_state);

  const viz::FrameSinkId frame_sink_id_;
  const raw_ptr<DelegatedFrameHostClient> client_;
  const bool should_register_frame_sink_id_;
  raw_ptr<ui::Compositor> compositor_ = nullptr;

  // The LocalSurfaceId of the currently embedded surface.
  //
  // TODO(crbug.com/40274223): this value is a copy of what the browser
  // wants to embed. The source of truth is stored else where. We should
  // consider de-dup this ID.
  viz::LocalSurfaceId local_surface_id_;

  // The size of the above surface (updated at the same time).
  gfx::Size surface_dip_size_;

  // In non-surface sync, this is the size of the most recently activated
  // surface (which is suitable for calculating gutter size). In surface sync,
  // this is most recent size set in EmbedSurface.
  // TODO(ccameron): The meaning of "current" should be made more clear here.
  gfx::Size current_frame_size_in_dip_;

  const raw_ptr<viz::HostFrameSinkManager> host_frame_sink_manager_;

  std::unique_ptr<viz::FrameEvictor> frame_evictor_;

  viz::LocalSurfaceId first_local_surface_id_after_navigation_;

  // While navigating we have no active |local_surface_id_|. Track the one from
  // before a navigation, because if the navigation fails to complete, we will
  // need to evict its surface. If the old page enters BFCache, this id is used
  // to restore `local_surface_id_`.
  viz::LocalSurfaceId pre_navigation_local_surface_id_;

  // The fallback ID for BFCache restore. It is set when `this` enters the
  // BFCache and is cleared when resize-while-hidden (which supplies with a
  // latest fallback ID) or after it is used in `EmbedSurface`.
  viz::LocalSurfaceId bfcache_fallback_;

  FrameEvictionState frame_eviction_state_ = FrameEvictionState::kNotStarted;

  // Layer responsible for displaying the stale content for the DFHC when the
  // actual web content frame has been evicted. This will be reset when a new
  // compositor frame is submitted.
  std::unique_ptr<ui::Layer> stale_content_layer_;

  blink::ContentToVisibleTimeReporter tab_switch_time_recorder_;

  // Speculative RenderWidgetHostViews can start with a FrameSinkId owned by the
  // currently committed RenderWidgetHostView. Ownership is transferred when the
  // navigation is committed. This bit tracks whether this DelegatedFrameHost
  // owns its FrameSinkId.
  bool owns_frame_sink_id_ = false;

  base::ObserverList<Observer>::Unchecked observers_;

  base::WeakPtrFactory<DelegatedFrameHost> weak_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_RENDERER_HOST_DELEGATED_FRAME_HOST_H_