File: no_state_prefetch_utils.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (145 lines) | stat: -rw-r--r-- 5,580 bytes parent folder | download | duplicates (6)
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
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/no_state_prefetch/renderer/no_state_prefetch_utils.h"

#include "base/memory/weak_ptr.h"
#include "components/no_state_prefetch/renderer/no_state_prefetch_helper.h"
#include "content/public/common/page_visibility_state.h"
#include "content/public/renderer/render_frame.h"
#include "media/mojo/mojom/media_player.mojom.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "third_party/blink/public/platform/browser_interface_broker_proxy.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_view_observer.h"

namespace prerender {

namespace {
const char kDeferredMediaLoadStateKey[] = "kDeferredMediaLoadStateKey";

class DeferredMediaLoadState : public base::SupportsUserData::Data {
 public:
  DeferredMediaLoadState() = default;
  ~DeferredMediaLoadState() override = default;
  DeferredMediaLoadState(const DeferredMediaLoadState&) = delete;
  DeferredMediaLoadState& operator=(const DeferredMediaLoadState&) = delete;

  static void Create(content::RenderFrame* render_frame) {
    CHECK(render_frame);
    if (!render_frame->GetUserData(kDeferredMediaLoadStateKey)) {
      render_frame->SetUserData(kDeferredMediaLoadStateKey,
                                std::make_unique<DeferredMediaLoadState>());
    }
  }

  static void Reset(content::RenderFrame* render_frame) {
    CHECK(render_frame);
    render_frame->RemoveUserData(kDeferredMediaLoadStateKey);
  }

  static bool ShouldDeferMediaLoad(content::RenderFrame* render_frame) {
    // If `render_frame` is null, defer media load as the WebFrame
    // might be gone.
    if (!render_frame) {
      return true;
    }
    return render_frame->GetUserData(kDeferredMediaLoadStateKey);
  }
};

// Defers media player loading in background pages until they're visible unless
// the tab has previously played content before.
class MediaLoadDeferrer : public blink::WebViewObserver {
 public:
  MediaLoadDeferrer(content::RenderFrame* render_frame,
                    blink::WebView* web_view,
                    base::OnceClosure continue_loading_cb)
      : blink::WebViewObserver(web_view),
        continue_loading_cb_(std::move(continue_loading_cb)) {
    mojo::PendingReceiver<media::mojom::MediaPlayerObserverClient>
        media_player_observer_client_receiver =
            media_player_observer_client_.BindNewPipeAndPassReceiver();
    render_frame->GetBrowserInterfaceBroker().GetInterface(
        std::move(media_player_observer_client_receiver));
    media_player_observer_client_->GetHasPlayedBefore(
        base::BindOnce(&MediaLoadDeferrer::OnGetHasPlayedBeforeCallback,
                       weak_factory_.GetWeakPtr()));
  }

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

  ~MediaLoadDeferrer() override = default;

  // blink::WebViewObserver implementation:
  void OnDestruct() override { delete this; }
  void OnPageVisibilityChanged(
      content::PageVisibilityState visibility_state) override {
    if (visibility_state != content::PageVisibilityState::kVisible) {
      return;
    }
    std::move(continue_loading_cb_).Run();
    delete this;
  }

  void OnGetHasPlayedBeforeCallback(bool has_played_before) {
    blink::WebFrame* web_frame =
        GetWebView() ? GetWebView()->MainFrame() : nullptr;

    // If the page has played media before and doesn't require deferred
    // media load, load the player now.
    if (has_played_before && web_frame && web_frame->IsWebLocalFrame() &&
        !DeferredMediaLoadState::ShouldDeferMediaLoad(
            content::RenderFrame::FromWebFrame(web_frame->ToWebLocalFrame()))) {
      std::move(continue_loading_cb_).Run();
      delete this;
    }
  }

 private:
  mojo::Remote<media::mojom::MediaPlayerObserverClient>
      media_player_observer_client_;
  base::OnceClosure continue_loading_cb_;

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

}  // namespace

bool DeferMediaLoad(content::RenderFrame* render_frame,
                    bool has_played_media_before,
                    base::OnceClosure closure) {
  blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
  // Don't allow autoplay/autoload of media resources in a page that is hidden
  // and has no Document Picture-in-Picture window and either never played any
  // media before or the media load should be deferred in the frame. We want to
  // allow future loads even when hidden to allow playlist-like functionality.
  //
  // NOTE: This is also used to defer media loading for NoStatePrefetch.
  if ((web_frame->View()->GetVisibilityState() !=
           content::PageVisibilityState::kVisible &&
       (!has_played_media_before ||
        DeferredMediaLoadState::ShouldDeferMediaLoad(render_frame)) &&
       !web_frame->GetDocument().HasDocumentPictureInPictureWindow()) ||
      NoStatePrefetchHelper::IsPrefetching(render_frame)) {
    new MediaLoadDeferrer(render_frame, web_frame->View(), std::move(closure));
    return true;
  }

  std::move(closure).Run();
  return false;
}

void SetShouldDeferMediaLoad(content::RenderFrame* render_frame,
                             bool should_defer) {
  if (should_defer) {
    DeferredMediaLoadState::Create(render_frame);
  } else {
    DeferredMediaLoadState::Reset(render_frame);
  }
}

}  // namespace prerender