| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "components/language/ios/browser/language_detection_java_script_feature.h" |
| |
| #import "base/metrics/histogram_macros.h" |
| #import "components/language/ios/browser/ios_language_detection_tab_helper.h" |
| #import "components/prefs/pref_member.h" |
| #import "components/translate/core/browser/translate_pref_names.h" |
| #import "ios/web/public/browser_state.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" |
| |
| namespace { |
| |
| const char kScriptName[] = "language_detection"; |
| const char kLanguageDetectionTextCapturedMessageHandlerName[] = |
| "LanguageDetectionTextCaptured"; |
| |
| } // namespace |
| |
| namespace language { |
| |
| // static |
| LanguageDetectionJavaScriptFeature* |
| LanguageDetectionJavaScriptFeature::GetInstance() { |
| static base::NoDestructor<LanguageDetectionJavaScriptFeature> instance; |
| return instance.get(); |
| } |
| |
| LanguageDetectionJavaScriptFeature::LanguageDetectionJavaScriptFeature() |
| : web::JavaScriptFeature( |
| web::ContentWorld::kIsolatedWorld, |
| {FeatureScript::CreateWithFilename( |
| kScriptName, |
| FeatureScript::InjectionTime::kDocumentStart, |
| FeatureScript::TargetFrames::kMainFrame, |
| FeatureScript::ReinjectionBehavior::kInjectOncePerWindow)}) {} |
| |
| LanguageDetectionJavaScriptFeature::~LanguageDetectionJavaScriptFeature() = |
| default; |
| |
| void LanguageDetectionJavaScriptFeature::StartLanguageDetection( |
| web::WebFrame* frame) { |
| CallJavaScriptFunction(frame, "languageDetection.detectLanguage", {}); |
| } |
| |
| void LanguageDetectionJavaScriptFeature::ScriptMessageReceived( |
| web::WebState* web_state, |
| const web::ScriptMessage& script_message) { |
| if (!script_message.is_main_frame()) { |
| // Translate is only supported on main frame. |
| return; |
| } |
| |
| if (!script_message.body() || !script_message.body()->is_dict()) { |
| return; |
| } |
| |
| base::Value::Dict& body_dict = script_message.body()->GetDict(); |
| |
| std::optional<bool> has_notranslate = body_dict.FindBool("hasNoTranslate"); |
| const std::string* html_lang = body_dict.FindString("htmlLang"); |
| const std::string* http_content_language = |
| body_dict.FindString("httpContentLanguage"); |
| const std::string* frame_id = body_dict.FindString("frameId"); |
| if (!has_notranslate.has_value() || !html_lang || !http_content_language || |
| !frame_id) { |
| return; |
| } |
| |
| web::WebFrame* sender_frame = |
| GetWebFramesManager(web_state)->GetFrameWithId(*frame_id); |
| if (!sender_frame) { |
| return; |
| } |
| |
| if (!script_message.request_url()) { |
| return; |
| } |
| |
| GURL url = script_message.request_url().value(); |
| |
| language::IOSLanguageDetectionTabHelper* tab_helper = |
| language::IOSLanguageDetectionTabHelper::FromWebState(web_state); |
| if (!tab_helper) { |
| return; |
| } |
| |
| CallJavaScriptFunction( |
| sender_frame, "languageDetection.retrieveBufferedTextContent", {}, |
| base::BindOnce(&IOSLanguageDetectionTabHelper::OnTextRetrieved, |
| tab_helper->GetWeakPtr(), *has_notranslate, |
| *http_content_language, *html_lang, url), |
| base::Milliseconds(web::kJavaScriptFunctionCallDefaultTimeout)); |
| } |
| |
| std::optional<std::string> |
| LanguageDetectionJavaScriptFeature::GetScriptMessageHandlerName() const { |
| return kLanguageDetectionTextCapturedMessageHandlerName; |
| } |
| |
| } // namespace language |