chromium/components/cast_receiver/browser/application_client.cc

// Copyright 2022 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/cast_receiver/browser/application_client.h"

#include "base/supports_user_data.h"
#include "components/media_control/browser/media_blocker.h"
#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
#include "components/url_rewrite/common/url_loader_throttle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"

namespace cast_receiver {
namespace {

// Key in the WebContents's UserData here the instance for a given WebContents
// is stored.
const char kApplicationControlsUserDataKey[] =
    "components/cast_receiver/browser/application_client";

// Helper function to call the method on each observer
template <typename TObserver, typename TFunc, typename... TArgs>
void NotifyObservers(base::ObserverList<TObserver>& observers,
                     TFunc&& func,
                     TArgs&&... args) {
  for (auto& observer : observers) {
    (observer.*func)(args...);
  }
}

// This class acts as a wrapper around WebContents-specific classes, acting on
// them based on changes to it. Specifically, it handles connection of any
// cross-process mojo APIs.
class ApplicationControlsImpl : public ApplicationClient::ApplicationControls,
                                public base::SupportsUserData::Data {
 public:
  explicit ApplicationControlsImpl(content::WebContents& web_contents)
      : web_contents_(web_contents), media_blocker_(&web_contents) {
    url_request_rewrite_rules_manager_.AddWebContents(&web_contents);
  }
  ~ApplicationControlsImpl() override {
    url_request_rewrite_rules_manager_.RemoveWebContents(&*web_contents_);
  }

  media_control::MediaBlocker& GetMediaBlocker() override {
    return media_blocker_;
  }

  url_rewrite::UrlRequestRewriteRulesManager& GetUrlRequestRewriteRulesManager()
      override {
    return url_request_rewrite_rules_manager_;
  }

 private:
  const raw_ref<content::WebContents> web_contents_;
  media_control::MediaBlocker media_blocker_;
  url_rewrite::UrlRequestRewriteRulesManager url_request_rewrite_rules_manager_;
};

}  // namespace

ApplicationClient::ApplicationControls::~ApplicationControls() = default;

ApplicationClient::ApplicationClient(
    network::NetworkContextGetter network_context_getter)
    : network_context_getter_(std::move(network_context_getter)),
      weak_factory_(this) {}

ApplicationClient::~ApplicationClient() = default;

void ApplicationClient::AddStreamingResolutionObserver(
    StreamingResolutionObserver* observer) {
  streaming_resolution_observer_list_.AddObserver(observer);
}

void ApplicationClient::RemoveStreamingResolutionObserver(
    StreamingResolutionObserver* observer) {
  streaming_resolution_observer_list_.RemoveObserver(observer);
}

void ApplicationClient::AddApplicationStateObserver(
    ApplicationStateObserver* observer) {
  application_state_observer_list_.AddObserver(observer);
}

void ApplicationClient::RemoveApplicationStateObserver(
    ApplicationStateObserver* observer) {
  application_state_observer_list_.RemoveObserver(observer);
}

void ApplicationClient::OnWebContentsCreated(
    content::WebContents* web_contents) {
  DCHECK(web_contents);
  web_contents->SetUserData(
      &kApplicationControlsUserDataKey,
      std::make_unique<ApplicationControlsImpl>(*web_contents));
}

std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
ApplicationClient::CreateURLLoaderThrottles(
    const base::RepeatingCallback<content::WebContents*()>& wc_getter,
    int frame_tree_node_id,
    CorsExemptHeaderCallback is_cors_exempt_header_cb) {
  std::vector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
  if (frame_tree_node_id == content::RenderFrameHost::kNoFrameTreeNodeId) {
    return throttles;
  }

  content::WebContents* web_contents = wc_getter.Run();
  if (web_contents) {
    const auto& rules = GetApplicationControls(*web_contents)
                            .GetUrlRequestRewriteRulesManager()
                            .GetCachedRules();
    if (rules) {
      throttles.emplace_back(std::make_unique<url_rewrite::URLLoaderThrottle>(
          rules, std::move(is_cors_exempt_header_cb)));
    }
  }
  return throttles;
}

void ApplicationClient::OnStreamingResolutionChanged(
    const gfx::Rect& size,
    const media::VideoTransformation& transformation) {
  NotifyObservers(streaming_resolution_observer_list_,
                  &StreamingResolutionObserver::OnStreamingResolutionChanged,
                  size, transformation);
}

void ApplicationClient::OnForegroundApplicationChanged(
    RuntimeApplication* app) {
  NotifyObservers(application_state_observer_list_,
                  &ApplicationStateObserver::OnForegroundApplicationChanged,
                  app);
}

ApplicationClient::ApplicationControls&
ApplicationClient::GetApplicationControls(
    const content::WebContents& web_contents) {
  ApplicationControlsImpl* instance = static_cast<ApplicationControlsImpl*>(
      web_contents.GetUserData(&kApplicationControlsUserDataKey));
  DCHECK(instance);
  return *instance;
}

}  // namespace cast_receiver