chromium/ios/web/js_features/fullscreen/fullscreen_java_script_feature.mm

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

#import "ios/web/js_features/fullscreen/fullscreen_java_script_feature.h"

#import "ios/web/public/js_messaging/java_script_feature_util.h"
#import "ios/web/public/js_messaging/script_message.h"
#import "ios/web/public/js_messaging/web_frame.h"
#import "ios/web/public/js_messaging/web_frames_manager.h"
#import "ios/web/web_state/ui/crw_web_controller.h"
#import "ios/web/web_state/web_state_impl.h"

namespace {
const char kScriptName[] = "fullscreen";

const char kViewportConfigurationHandlerName[] = "FullscreenViewportHandler";

static const char kScriptMessageViewportFitCoverKey[] = "cover";
}  // namespace

namespace web {

// static
FullscreenJavaScriptFeature* FullscreenJavaScriptFeature::GetInstance() {
  static base::NoDestructor<FullscreenJavaScriptFeature> instance;
  return instance.get();
}

FullscreenJavaScriptFeature::FullscreenJavaScriptFeature()
    : JavaScriptFeature(
          ContentWorld::kIsolatedWorld,
          {FeatureScript::CreateWithFilename(
              kScriptName,
              FeatureScript::InjectionTime::kDocumentEnd,
              FeatureScript::TargetFrames::kMainFrame,
              FeatureScript::ReinjectionBehavior::
                  kReinjectOnDocumentRecreation)},
          {web::java_script_features::GetCommonJavaScriptFeature(),
           web::java_script_features::GetMessageJavaScriptFeature()}) {}
FullscreenJavaScriptFeature::~FullscreenJavaScriptFeature() = default;

std::optional<std::string>
FullscreenJavaScriptFeature::GetScriptMessageHandlerName() const {
  return kViewportConfigurationHandlerName;
}

void FullscreenJavaScriptFeature::ScriptMessageReceived(
    WebState* web_state,
    const ScriptMessage& script_message) {
  const base::Value::Dict* script_dict =
      script_message.body() ? script_message.body()->GetIfDict() : nullptr;
  if (!script_dict) {
    return;
  }

  if (!script_message.is_main_frame()) {
    return;
  }

  const std::string* frame_id = script_dict->FindString("frame_id");
  if (!frame_id) {
    return;
  }

  WebFrame* main_frame = GetWebFramesManager(web_state)->GetMainWebFrame();
  std::string main_frame_id = main_frame ? main_frame->GetFrameId() : "";
  if (main_frame_id != *frame_id) {
    // Frame has changed, do not send message to the web controller as it would
    // update the incorrect navigation item.
    return;
  }
  auto cover = script_dict->FindBool(kScriptMessageViewportFitCoverKey);
  if (cover.has_value()) {
    CRWWebController* web_controller =
        WebStateImpl::FromWebState(web_state)->GetWebController();
    [web_controller handleViewportFit:static_cast<BOOL>(cover.value())];
  }
}

}  // namespace web