1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "weblayer/browser/tab_impl.h"
6
7 #include <cmath>
8
9 #include "base/auto_reset.h"
10 #include "base/guid.h"
11 #include "base/logging.h"
12 #include "base/no_destructor.h"
13 #include "base/task/thread_pool.h"
14 #include "base/time/default_tick_clock.h"
15 #include "cc/layers/layer.h"
16 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
17 #include "components/autofill/core/browser/autofill_manager.h"
18 #include "components/autofill/core/browser/autofill_provider.h"
19 #include "components/blocked_content/popup_blocker.h"
20 #include "components/blocked_content/popup_blocker_tab_helper.h"
21 #include "components/blocked_content/popup_opener_tab_helper.h"
22 #include "components/blocked_content/popup_tracker.h"
23 #include "components/captive_portal/core/buildflags.h"
24 #include "components/content_settings/browser/page_specific_content_settings.h"
25 #include "components/embedder_support/android/util/user_agent_utils.h"
26 #include "components/find_in_page/find_tab_helper.h"
27 #include "components/find_in_page/find_types.h"
28 #include "components/js_injection/browser/js_communication_host.h"
29 #include "components/js_injection/browser/web_message_host.h"
30 #include "components/js_injection/browser/web_message_host_factory.h"
31 #include "components/permissions/permission_manager.h"
32 #include "components/permissions/permission_request_manager.h"
33 #include "components/permissions/permission_result.h"
34 #include "components/prefs/pref_service.h"
35 #include "components/sessions/content/session_tab_helper.h"
36 #include "components/translate/core/browser/translate_manager.h"
37 #include "components/ukm/content/source_url_recorder.h"
38 #include "components/webrtc/media_stream_devices_controller.h"
39 #include "content/public/browser/browser_task_traits.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/context_menu_params.h"
42 #include "content/public/browser/file_select_listener.h"
43 #include "content/public/browser/navigation_controller.h"
44 #include "content/public/browser/navigation_entry.h"
45 #include "content/public/browser/navigation_handle.h"
46 #include "content/public/browser/render_frame_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/render_widget_host_view.h"
49 #include "content/public/browser/renderer_preferences_util.h"
50 #include "content/public/browser/web_contents.h"
51 #include "content/public/browser/web_contents_observer.h"
52 #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
53 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
54 #include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
55 #include "ui/base/window_open_disposition.h"
56 #include "weblayer/browser/autofill_client_impl.h"
57 #include "weblayer/browser/browser_context_impl.h"
58 #include "weblayer/browser/browser_impl.h"
59 #include "weblayer/browser/browser_process.h"
60 #include "weblayer/browser/content_browser_client_impl.h"
61 #include "weblayer/browser/favicon/favicon_fetcher_impl.h"
62 #include "weblayer/browser/favicon/favicon_tab_helper.h"
63 #include "weblayer/browser/file_select_helper.h"
64 #include "weblayer/browser/host_content_settings_map_factory.h"
65 #include "weblayer/browser/i18n_util.h"
66 #include "weblayer/browser/infobar_service.h"
67 #include "weblayer/browser/js_communication/web_message_host_factory_wrapper.h"
68 #include "weblayer/browser/navigation_controller_impl.h"
69 #include "weblayer/browser/navigation_entry_data.h"
70 #include "weblayer/browser/no_state_prefetch/prerender_tab_helper.h"
71 #include "weblayer/browser/page_load_metrics_initialize.h"
72 #include "weblayer/browser/page_specific_content_settings_delegate.h"
73 #include "weblayer/browser/password_manager_driver_factory.h"
74 #include "weblayer/browser/permissions/permission_manager_factory.h"
75 #include "weblayer/browser/persistence/browser_persister.h"
76 #include "weblayer/browser/popup_navigation_delegate_impl.h"
77 #include "weblayer/browser/profile_impl.h"
78 #include "weblayer/browser/translate_client_impl.h"
79 #include "weblayer/browser/user_agent.h"
80 #include "weblayer/browser/weblayer_features.h"
81 #include "weblayer/common/isolated_world_ids.h"
82 #include "weblayer/public/fullscreen_delegate.h"
83 #include "weblayer/public/js_communication/web_message.h"
84 #include "weblayer/public/js_communication/web_message_host_factory.h"
85 #include "weblayer/public/new_tab_delegate.h"
86 #include "weblayer/public/tab_observer.h"
87
88 #if !defined(OS_ANDROID)
89 #include "ui/views/controls/webview/webview.h"
90 #endif
91
92 #if defined(OS_ANDROID)
93 #include "base/android/callback_android.h"
94 #include "base/android/jni_array.h"
95 #include "base/android/jni_string.h"
96 #include "base/json/json_writer.h"
97 #include "base/trace_event/trace_event.h"
98 #include "components/autofill/android/provider/autofill_provider_android.h"
99 #include "components/browser_ui/sms/android/sms_infobar.h"
100 #include "components/download/content/public/context_menu_download.h"
101 #include "components/embedder_support/android/contextmenu/context_menu_builder.h"
102 #include "components/embedder_support/android/delegate/color_chooser_android.h"
103 #include "components/javascript_dialogs/tab_modal_dialog_manager.h" // nogncheck
104 #include "components/translate/core/browser/translate_manager.h"
105 #include "ui/android/view_android.h"
106 #include "ui/gfx/android/java_bitmap.h"
107 #include "weblayer/browser/browser_controls_container_view.h"
108 #include "weblayer/browser/browser_controls_navigation_state_handler.h"
109 #include "weblayer/browser/controls_visibility_reason.h"
110 #include "weblayer/browser/java/jni/TabImpl_jni.h"
111 #include "weblayer/browser/javascript_tab_modal_dialog_manager_delegate_android.h"
112 #include "weblayer/browser/js_communication/web_message_host_factory_proxy.h"
113 #include "weblayer/browser/translate_client_impl.h"
114 #include "weblayer/browser/url_bar/trusted_cdn_observer.h"
115 #include "weblayer/browser/weblayer_factory_impl_android.h"
116 #include "weblayer/browser/webrtc/media_stream_manager.h"
117 #endif
118
119 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
120 #include "components/captive_portal/content/captive_portal_tab_helper.h"
121 #include "weblayer/browser/captive_portal_service_factory.h"
122 #endif
123
124 #if defined(OS_ANDROID)
125 using base::android::AttachCurrentThread;
126 using base::android::JavaParamRef;
127 using base::android::ScopedJavaGlobalRef;
128 using base::android::ScopedJavaLocalRef;
129 #endif
130
131 namespace weblayer {
132
133 namespace {
134
135 // Maximum size of data when calling SetData().
136 constexpr int kMaxDataSize = 4096;
137
138 #if defined(OS_ANDROID)
139 bool g_system_autofill_disabled_for_testing = false;
140
141 #endif
142
NewTabTypeFromWindowDisposition(WindowOpenDisposition disposition)143 NewTabType NewTabTypeFromWindowDisposition(WindowOpenDisposition disposition) {
144 // WindowOpenDisposition has a *ton* of types, but the following are really
145 // the only ones that should be hit for this code path.
146 switch (disposition) {
147 case WindowOpenDisposition::NEW_FOREGROUND_TAB:
148 return NewTabType::kForeground;
149 case WindowOpenDisposition::NEW_BACKGROUND_TAB:
150 return NewTabType::kBackground;
151 case WindowOpenDisposition::NEW_POPUP:
152 return NewTabType::kNewPopup;
153 case WindowOpenDisposition::NEW_WINDOW:
154 return NewTabType::kNewWindow;
155 default:
156 // The set of allowed types are in
157 // ContentTabClientImpl::CanCreateWindow().
158 NOTREACHED();
159 return NewTabType::kForeground;
160 }
161 }
162
163 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
164 // Opens a captive portal login page in |web_contents|.
OpenCaptivePortalLoginTabInWebContents(content::WebContents * web_contents)165 void OpenCaptivePortalLoginTabInWebContents(
166 content::WebContents* web_contents) {
167 content::OpenURLParams params(
168 CaptivePortalServiceFactory::GetForBrowserContext(
169 web_contents->GetBrowserContext())
170 ->test_url(),
171 content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
172 ui::PAGE_TRANSITION_LINK, false);
173 web_contents->OpenURL(params);
174 }
175 #endif
176
177 // Pointer value of this is used as a key in base::SupportsUserData for
178 // WebContents. Value of the key is an instance of |UserData|.
179 constexpr int kWebContentsUserDataKey = 0;
180
181 struct UserData : public base::SupportsUserData::Data {
182 TabImpl* tab = nullptr;
183 };
184
185 #if defined(OS_ANDROID)
HandleJavaScriptResult(const ScopedJavaGlobalRef<jobject> & callback,base::Value result)186 void HandleJavaScriptResult(const ScopedJavaGlobalRef<jobject>& callback,
187 base::Value result) {
188 std::string json;
189 base::JSONWriter::Write(result, &json);
190 base::android::RunStringCallbackAndroid(callback, json);
191 }
192
OnConvertedToJavaBitmap(const ScopedJavaGlobalRef<jobject> & value_callback,const ScopedJavaGlobalRef<jobject> & java_bitmap)193 void OnConvertedToJavaBitmap(const ScopedJavaGlobalRef<jobject>& value_callback,
194 const ScopedJavaGlobalRef<jobject>& java_bitmap) {
195 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
196 TabImpl::ScreenShotErrors error =
197 java_bitmap ? TabImpl::ScreenShotErrors::kNone
198 : TabImpl::ScreenShotErrors::kBitmapAllocationFailed;
199 Java_TabImpl_runCaptureScreenShotCallback(AttachCurrentThread(),
200 value_callback, java_bitmap,
201 static_cast<int>(error));
202 }
203
204 // Convert SkBitmap to java Bitmap on a background thread since it involves a
205 // memcpy.
ConvertToJavaBitmapBackgroundThread(const SkBitmap & bitmap,base::OnceCallback<void (const ScopedJavaGlobalRef<jobject> &)> callback)206 void ConvertToJavaBitmapBackgroundThread(
207 const SkBitmap& bitmap,
208 base::OnceCallback<void(const ScopedJavaGlobalRef<jobject>&)> callback) {
209 // Make sure to only pass ScopedJavaGlobalRef between threads.
210 ScopedJavaGlobalRef<jobject> java_bitmap = ScopedJavaGlobalRef<jobject>(
211 gfx::ConvertToJavaBitmap(bitmap, gfx::OomBehavior::kReturnNullOnOom));
212 content::GetUIThreadTaskRunner({})->PostTask(
213 FROM_HERE, base::BindOnce(std::move(callback), std::move(java_bitmap)));
214 }
215
OnScreenShotCaptured(const ScopedJavaGlobalRef<jobject> & value_callback,const SkBitmap & bitmap)216 void OnScreenShotCaptured(const ScopedJavaGlobalRef<jobject>& value_callback,
217 const SkBitmap& bitmap) {
218 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
219 if (bitmap.isNull() || bitmap.drawsNothing()) {
220 Java_TabImpl_runCaptureScreenShotCallback(
221 AttachCurrentThread(), value_callback, nullptr,
222 static_cast<int>(TabImpl::ScreenShotErrors::kCaptureFailed));
223 return;
224 }
225 // Not using PostTaskAndReplyWithResult to ensure ScopedJavaLocalRef is not
226 // passed between threads.
227 base::ThreadPool::PostTask(
228 FROM_HERE,
229 {base::TaskPriority::BEST_EFFORT,
230 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
231 base::BindOnce(&ConvertToJavaBitmapBackgroundThread, bitmap,
232 base::BindOnce(&OnConvertedToJavaBitmap, value_callback)));
233 }
234
235 #endif // OS_ANDROID
236
GetTabs()237 std::set<TabImpl*>& GetTabs() {
238 static base::NoDestructor<std::set<TabImpl*>> s_all_tab_impl;
239 return *s_all_tab_impl;
240 }
241
242 // Simulates a WeakPtr for WebContents. Specifically if the WebContents
243 // supplied to the constructor is destroyed then web_contents() returns
244 // null.
245 class WebContentsTracker : public content::WebContentsObserver {
246 public:
WebContentsTracker(content::WebContents * web_contents)247 explicit WebContentsTracker(content::WebContents* web_contents)
248 : content::WebContentsObserver(web_contents) {}
249 };
250
251 } // namespace
252
253 #if defined(OS_ANDROID)
254
JNI_TabImpl_FromWebContents(JNIEnv * env,const base::android::JavaParamRef<jobject> & j_web_contents)255 static ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents(
256 JNIEnv* env,
257 const base::android::JavaParamRef<jobject>& j_web_contents) {
258 content::WebContents* web_contents =
259 content::WebContents::FromJavaWebContents(j_web_contents);
260 TabImpl* tab = TabImpl::FromWebContents(web_contents);
261 if (tab)
262 return ScopedJavaLocalRef<jobject>(tab->GetJavaTab());
263 return nullptr;
264 }
265
JNI_TabImpl_DestroyContextMenuParams(JNIEnv * env,jlong native_context_menu_params)266 static void JNI_TabImpl_DestroyContextMenuParams(
267 JNIEnv* env,
268 jlong native_context_menu_params) {
269 // Note: this runs on the finalizer thread which isn't the UI thread.
270 auto* context_menu_params =
271 reinterpret_cast<content::ContextMenuParams*>(native_context_menu_params);
272 delete context_menu_params;
273 }
274
TabImpl(ProfileImpl * profile,const JavaParamRef<jobject> & java_impl,std::unique_ptr<content::WebContents> web_contents)275 TabImpl::TabImpl(ProfileImpl* profile,
276 const JavaParamRef<jobject>& java_impl,
277 std::unique_ptr<content::WebContents> web_contents)
278 : TabImpl(profile, std::move(web_contents)) {
279 java_impl_ = java_impl;
280 }
281 #endif
282
TabImpl(ProfileImpl * profile,std::unique_ptr<content::WebContents> web_contents,const std::string & guid)283 TabImpl::TabImpl(ProfileImpl* profile,
284 std::unique_ptr<content::WebContents> web_contents,
285 const std::string& guid)
286 : profile_(profile),
287 web_contents_(std::move(web_contents)),
288 guid_(guid.empty() ? base::GenerateGUID() : guid) {
289 GetTabs().insert(this);
290 DCHECK(web_contents_);
291 // This code path is hit when the page requests a new tab, which should
292 // only be possible from the same profile.
293 DCHECK_EQ(profile_->GetBrowserContext(), web_contents_->GetBrowserContext());
294
295 // FaviconTabHelper adds a WebContentsObserver. Create FaviconTabHelper
296 // before |this| observes the WebContents to ensure favicons are reset before
297 // notifying weblayer observers of changes.
298 FaviconTabHelper::CreateForWebContents(web_contents_.get());
299
300 UpdateRendererPrefs(false);
301 locale_change_subscription_ =
302 i18n::RegisterLocaleChangeCallback(base::BindRepeating(
303 &TabImpl::UpdateRendererPrefs, base::Unretained(this), true));
304
305 std::unique_ptr<UserData> user_data = std::make_unique<UserData>();
306 user_data->tab = this;
307 web_contents_->SetUserData(&kWebContentsUserDataKey, std::move(user_data));
308
309 web_contents_->SetDelegate(this);
310 Observe(web_contents_.get());
311
312 navigation_controller_ = std::make_unique<NavigationControllerImpl>(this);
313
314 find_in_page::FindTabHelper::CreateForWebContents(web_contents_.get());
315 GetFindTabHelper()->AddObserver(this);
316
317 TranslateClientImpl::CreateForWebContents(web_contents_.get());
318
319 sessions::SessionTabHelper::CreateForWebContents(
320 web_contents_.get(),
321 base::BindRepeating(&TabImpl::GetSessionServiceTabHelperDelegate));
322
323 permissions::PermissionRequestManager::CreateForWebContents(
324 web_contents_.get());
325 content_settings::PageSpecificContentSettings::CreateForWebContents(
326 web_contents_.get(),
327 std::make_unique<PageSpecificContentSettingsDelegate>(
328 web_contents_.get()));
329 blocked_content::PopupBlockerTabHelper::CreateForWebContents(
330 web_contents_.get());
331 blocked_content::PopupOpenerTabHelper::CreateForWebContents(
332 web_contents_.get(), base::DefaultTickClock::GetInstance(),
333 HostContentSettingsMapFactory::GetForBrowserContext(
334 web_contents_->GetBrowserContext()));
335 PasswordManagerDriverFactory::CreateForWebContents(web_contents_.get());
336
337 InitializePageLoadMetricsForWebContents(web_contents_.get());
338 ukm::InitializeSourceUrlRecorderForWebContents(web_contents_.get());
339
340 #if defined(OS_ANDROID)
341 InfoBarService::CreateForWebContents(web_contents_.get());
342 javascript_dialogs::TabModalDialogManager::CreateForWebContents(
343 web_contents_.get(),
344 std::make_unique<JavaScriptTabModalDialogManagerDelegateAndroid>(
345 web_contents_.get()));
346
347 browser_controls_navigation_state_handler_ =
348 std::make_unique<BrowserControlsNavigationStateHandler>(
349 web_contents_.get(), this);
350
351 TrustedCDNObserver::CreateForWebContents(web_contents_.get());
352 #endif
353
354 #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
355 captive_portal::CaptivePortalTabHelper::CreateForWebContents(
356 web_contents_.get(),
357 CaptivePortalServiceFactory::GetForBrowserContext(
358 web_contents_->GetBrowserContext()),
359 base::BindRepeating(&OpenCaptivePortalLoginTabInWebContents,
360 web_contents_.get()));
361 #endif
362
363 // PrerenderTabHelper adds a WebContentsObserver.
364 PrerenderTabHelper::CreateForWebContents(web_contents_.get());
365 }
366
~TabImpl()367 TabImpl::~TabImpl() {
368 DCHECK(!browser_);
369
370 GetFindTabHelper()->RemoveObserver(this);
371
372 // Delete the WebContents and related objects that may be observing
373 // the WebContents now to avoid calling back when this object is partially
374 // deleted. DidFinishNavigation() may be called while deleting WebContents,
375 // so stop observing first. Similarly WebContents destructor can callback to
376 // delegate such as NavigationStateChanged, so clear its Delegate as well.
377 #if defined(OS_ANDROID)
378 browser_controls_navigation_state_handler_.reset();
379 #endif
380 Observe(nullptr);
381 web_contents_->SetDelegate(nullptr);
382 if (navigation_controller_->should_delay_web_contents_deletion()) {
383 // Some user-data on WebContents directly or indirectly references this.
384 // Remove that linkage to avoid use-after-free.
385 web_contents_->RemoveUserData(&kWebContentsUserDataKey);
386 web_contents_->RemoveUserData(
387 autofill::ContentAutofillDriverFactory::
388 kContentAutofillDriverFactoryWebContentsUserDataKey);
389 // Have Profile handle the task posting to ensure the WebContents is
390 // deleted before Profile. To do otherwise means it would be possible for
391 // the Profile to outlive the WebContents, which is problematic (crash).
392 profile_->DeleteWebContentsSoon(std::move(web_contents_));
393 }
394 web_contents_.reset();
395 GetTabs().erase(this);
396 }
397
398 // static
FromWebContents(content::WebContents * web_contents)399 TabImpl* TabImpl::FromWebContents(content::WebContents* web_contents) {
400 if (!web_contents)
401 return nullptr;
402
403 UserData* user_data = reinterpret_cast<UserData*>(
404 web_contents->GetUserData(&kWebContentsUserDataKey));
405 return user_data ? user_data->tab : nullptr;
406 }
407
408 // static
GetAllTabImpl()409 std::set<TabImpl*> TabImpl::GetAllTabImpl() {
410 return GetTabs();
411 }
412
AddDataObserver(DataObserver * observer)413 void TabImpl::AddDataObserver(DataObserver* observer) {
414 data_observers_.AddObserver(observer);
415 }
416
RemoveDataObserver(DataObserver * observer)417 void TabImpl::RemoveDataObserver(DataObserver* observer) {
418 data_observers_.RemoveObserver(observer);
419 }
420
GetBrowser()421 Browser* TabImpl::GetBrowser() {
422 return browser_;
423 }
424
SetErrorPageDelegate(ErrorPageDelegate * delegate)425 void TabImpl::SetErrorPageDelegate(ErrorPageDelegate* delegate) {
426 error_page_delegate_ = delegate;
427 }
428
SetFullscreenDelegate(FullscreenDelegate * delegate)429 void TabImpl::SetFullscreenDelegate(FullscreenDelegate* delegate) {
430 if (delegate == fullscreen_delegate_)
431 return;
432
433 const bool had_delegate = (fullscreen_delegate_ != nullptr);
434 const bool has_delegate = (delegate != nullptr);
435
436 // If currently fullscreen, and the delegate is being set to null, force an
437 // exit now (otherwise the delegate can't take us out of fullscreen).
438 if (is_fullscreen_ && fullscreen_delegate_ && had_delegate != has_delegate)
439 OnExitFullscreen();
440
441 fullscreen_delegate_ = delegate;
442 // Whether fullscreen is enabled depends upon whether there is a delegate. If
443 // having a delegate changed, then update the renderer (which is where
444 // fullscreen enabled is tracked).
445 if (had_delegate != has_delegate)
446 web_contents_->OnWebPreferencesChanged();
447 }
448
SetNewTabDelegate(NewTabDelegate * delegate)449 void TabImpl::SetNewTabDelegate(NewTabDelegate* delegate) {
450 new_tab_delegate_ = delegate;
451 }
452
SetGoogleAccountsDelegate(GoogleAccountsDelegate * delegate)453 void TabImpl::SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) {
454 google_accounts_delegate_ = delegate;
455 }
456
AddObserver(TabObserver * observer)457 void TabImpl::AddObserver(TabObserver* observer) {
458 observers_.AddObserver(observer);
459 }
460
RemoveObserver(TabObserver * observer)461 void TabImpl::RemoveObserver(TabObserver* observer) {
462 observers_.RemoveObserver(observer);
463 }
464
GetNavigationController()465 NavigationController* TabImpl::GetNavigationController() {
466 return navigation_controller_.get();
467 }
468
ExecuteScript(const base::string16 & script,bool use_separate_isolate,JavaScriptResultCallback callback)469 void TabImpl::ExecuteScript(const base::string16& script,
470 bool use_separate_isolate,
471 JavaScriptResultCallback callback) {
472 if (use_separate_isolate) {
473 web_contents_->GetMainFrame()->ExecuteJavaScriptInIsolatedWorld(
474 script, std::move(callback), ISOLATED_WORLD_ID_WEBLAYER);
475 } else {
476 content::RenderFrameHost::AllowInjectingJavaScript();
477 web_contents_->GetMainFrame()->ExecuteJavaScript(script,
478 std::move(callback));
479 }
480 }
481
GetGuid()482 const std::string& TabImpl::GetGuid() {
483 return guid_;
484 }
485
SetData(const std::map<std::string,std::string> & data)486 void TabImpl::SetData(const std::map<std::string, std::string>& data) {
487 bool result = SetDataInternal(data);
488 DCHECK(result) << "Data given to SetData() was too large.";
489 }
490
GetData()491 const std::map<std::string, std::string>& TabImpl::GetData() {
492 return data_;
493 }
494
AddWebMessageHostFactory(std::unique_ptr<WebMessageHostFactory> factory,const base::string16 & js_object_name,const std::vector<std::string> & allowed_origin_rules)495 base::string16 TabImpl::AddWebMessageHostFactory(
496 std::unique_ptr<WebMessageHostFactory> factory,
497 const base::string16& js_object_name,
498 const std::vector<std::string>& allowed_origin_rules) {
499 if (!js_communication_host_) {
500 js_communication_host_ =
501 std::make_unique<js_injection::JsCommunicationHost>(
502 web_contents_.get());
503 }
504 return js_communication_host_->AddWebMessageHostFactory(
505 std::make_unique<WebMessageHostFactoryWrapper>(std::move(factory)),
506 js_object_name, allowed_origin_rules);
507 }
508
RemoveWebMessageHostFactory(const base::string16 & js_object_name)509 void TabImpl::RemoveWebMessageHostFactory(
510 const base::string16& js_object_name) {
511 if (js_communication_host_)
512 js_communication_host_->RemoveWebMessageHostFactory(js_object_name);
513 }
514
ExecuteScriptWithUserGestureForTests(const base::string16 & script)515 void TabImpl::ExecuteScriptWithUserGestureForTests(
516 const base::string16& script) {
517 web_contents_->GetMainFrame()->ExecuteJavaScriptWithUserGestureForTests(
518 script);
519 }
520
CreateFaviconFetcher(FaviconFetcherDelegate * delegate)521 std::unique_ptr<FaviconFetcher> TabImpl::CreateFaviconFetcher(
522 FaviconFetcherDelegate* delegate) {
523 return std::make_unique<FaviconFetcherImpl>(web_contents_.get(), delegate);
524 }
525
526 #if !defined(OS_ANDROID)
AttachToView(views::WebView * web_view)527 void TabImpl::AttachToView(views::WebView* web_view) {
528 web_view->SetWebContents(web_contents_.get());
529 web_contents_->Focus();
530 }
531 #endif
532
WebPreferencesChanged()533 void TabImpl::WebPreferencesChanged() {
534 web_contents_->OnWebPreferencesChanged();
535 }
536
SetWebPreferences(blink::web_pref::WebPreferences * prefs)537 void TabImpl::SetWebPreferences(blink::web_pref::WebPreferences* prefs) {
538 prefs->fullscreen_supported = !!fullscreen_delegate_;
539
540 if (!browser_)
541 return;
542 browser_->SetWebPreferences(prefs);
543 }
544
OnLosingActive()545 void TabImpl::OnLosingActive() {
546 if (is_fullscreen_)
547 web_contents_->ExitFullscreen(/* will_cause_resize */ false);
548 }
549
IsActive()550 bool TabImpl::IsActive() {
551 return browser_->GetActiveTab() == this;
552 }
553
ShowContextMenu(const content::ContextMenuParams & params)554 void TabImpl::ShowContextMenu(const content::ContextMenuParams& params) {
555 #if defined(OS_ANDROID)
556 Java_TabImpl_showContextMenu(
557 base::android::AttachCurrentThread(), java_impl_,
558 context_menu::BuildJavaContextMenuParams(params),
559 reinterpret_cast<jlong>(new content::ContextMenuParams(params)));
560 #endif
561 }
562
563 #if defined(OS_ANDROID)
564 // static
DisableAutofillSystemIntegrationForTesting()565 void TabImpl::DisableAutofillSystemIntegrationForTesting() {
566 g_system_autofill_disabled_for_testing = true;
567 }
568
JNI_TabImpl_CreateTab(JNIEnv * env,jlong profile,const JavaParamRef<jobject> & java_impl)569 static jlong JNI_TabImpl_CreateTab(JNIEnv* env,
570 jlong profile,
571 const JavaParamRef<jobject>& java_impl) {
572 ProfileImpl* profile_impl = reinterpret_cast<ProfileImpl*>(profile);
573 content::WebContents::CreateParams create_params(
574 profile_impl->GetBrowserContext());
575 create_params.initially_hidden = true;
576 return reinterpret_cast<intptr_t>(new TabImpl(
577 profile_impl, java_impl, content::WebContents::Create(create_params)));
578 }
579
JNI_TabImpl_DeleteTab(JNIEnv * env,jlong tab)580 static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) {
581 TabImpl* tab_impl = reinterpret_cast<TabImpl*>(tab);
582 DCHECK(tab_impl);
583 // RemoveTabBeforeDestroyingFromJava() should have been called before this,
584 // which sets browser to null.
585 DCHECK(!tab_impl->browser());
586 delete tab_impl;
587 }
588
GetWebContents(JNIEnv * env)589 ScopedJavaLocalRef<jobject> TabImpl::GetWebContents(JNIEnv* env) {
590 return web_contents_->GetJavaWebContents();
591 }
592
SetBrowserControlsContainerViews(JNIEnv * env,jlong native_top_controls_container_view,jlong native_bottom_controls_container_view)593 void TabImpl::SetBrowserControlsContainerViews(
594 JNIEnv* env,
595 jlong native_top_controls_container_view,
596 jlong native_bottom_controls_container_view) {
597 top_controls_container_view_ =
598 reinterpret_cast<BrowserControlsContainerView*>(
599 native_top_controls_container_view);
600 bottom_controls_container_view_ =
601 reinterpret_cast<BrowserControlsContainerView*>(
602 native_bottom_controls_container_view);
603 }
604
ExecuteScript(JNIEnv * env,const JavaParamRef<jstring> & script,bool use_separate_isolate,const JavaParamRef<jobject> & callback)605 void TabImpl::ExecuteScript(JNIEnv* env,
606 const JavaParamRef<jstring>& script,
607 bool use_separate_isolate,
608 const JavaParamRef<jobject>& callback) {
609 ScopedJavaGlobalRef<jobject> jcallback(env, callback);
610 ExecuteScript(base::android::ConvertJavaStringToUTF16(script),
611 use_separate_isolate,
612 base::BindOnce(&HandleJavaScriptResult, jcallback));
613 }
614
SetJavaImpl(JNIEnv * env,const JavaParamRef<jobject> & impl)615 void TabImpl::SetJavaImpl(JNIEnv* env, const JavaParamRef<jobject>& impl) {
616 // This should only be called early on and only once.
617 DCHECK(!java_impl_);
618 java_impl_ = impl;
619 }
620
OnAutofillProviderChanged(JNIEnv * env,const JavaParamRef<jobject> & autofill_provider)621 void TabImpl::OnAutofillProviderChanged(
622 JNIEnv* env,
623 const JavaParamRef<jobject>& autofill_provider) {
624 if (g_system_autofill_disabled_for_testing)
625 return;
626
627 if (!autofill_provider_) {
628 // The first invocation should be when instantiating the autofill
629 // infrastructure, at which point the Java-side object should not be null.
630 DCHECK(autofill_provider);
631
632 // Initialize the native side of the autofill infrastructure.
633 autofill_provider_ = std::make_unique<autofill::AutofillProviderAndroid>(
634 autofill_provider, web_contents_.get());
635 InitializeAutofill();
636 return;
637 }
638
639 // The AutofillProvider Java object has been changed; inform
640 // |autofill_provider_|.
641 auto* provider =
642 static_cast<autofill::AutofillProviderAndroid*>(autofill_provider_.get());
643 provider->OnJavaAutofillProviderChanged(env, autofill_provider);
644 }
645
UpdateBrowserControlsConstraint(JNIEnv * env,jint constraint,jboolean animate)646 void TabImpl::UpdateBrowserControlsConstraint(JNIEnv* env,
647 jint constraint,
648 jboolean animate) {
649 current_browser_controls_visibility_constraint_ =
650 static_cast<content::BrowserControlsState>(constraint);
651 // Passing BOTH here means that it doesn't matter what state the controls are
652 // currently in; don't change the current state unless it's incompatible with
653 // the new constraint.
654 UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_BOTH, animate);
655 }
656
GetGuid(JNIEnv * env)657 ScopedJavaLocalRef<jstring> TabImpl::GetGuid(JNIEnv* env) {
658 return base::android::ConvertUTF8ToJavaString(AttachCurrentThread(),
659 GetGuid());
660 }
661
PrepareForCaptureScreenShot(float scale,content::RenderWidgetHostView ** rwhv,gfx::Rect * src_rect,gfx::Size * output_size)662 TabImpl::ScreenShotErrors TabImpl::PrepareForCaptureScreenShot(
663 float scale,
664 content::RenderWidgetHostView** rwhv,
665 gfx::Rect* src_rect,
666 gfx::Size* output_size) {
667 if (scale <= 0.f || scale > 1.f)
668 return ScreenShotErrors::kScaleOutOfRange;
669
670 if (!IsActive())
671 return ScreenShotErrors::kTabNotActive;
672
673 if (web_contents_->GetVisibility() != content::Visibility::VISIBLE)
674 return ScreenShotErrors::kWebContentsNotVisible;
675
676 if (!browser_ || !browser_->CompositorHasSurface())
677 return ScreenShotErrors::kNoSurface;
678
679 *rwhv = web_contents_->GetTopLevelRenderWidgetHostView();
680 if (!*rwhv)
681 return ScreenShotErrors::kNoRenderWidgetHostView;
682
683 if (!(*rwhv)->GetNativeView()->GetWindowAndroid())
684 return ScreenShotErrors::kNoWindowAndroid;
685
686 *src_rect =
687 gfx::Rect(web_contents_->GetNativeView()->GetPhysicalBackingSize());
688 if (src_rect->IsEmpty())
689 return ScreenShotErrors::kEmptyViewport;
690
691 const int reduced_height =
692 src_rect->height() -
693 top_controls_container_view_->GetContentHeightDelta() -
694 bottom_controls_container_view_->GetContentHeightDelta();
695 if (reduced_height <= 0)
696 return ScreenShotErrors::kHiddenByControls;
697 src_rect->set_height(reduced_height);
698
699 *output_size = gfx::ScaleToCeiledSize(src_rect->size(), scale, scale);
700 if (output_size->IsEmpty())
701 return ScreenShotErrors::kScaledToEmpty;
702 return ScreenShotErrors::kNone;
703 }
704
UpdateBrowserControlsState(content::BrowserControlsState new_state,bool animate)705 void TabImpl::UpdateBrowserControlsState(
706 content::BrowserControlsState new_state,
707 bool animate) {
708 if (base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest))
709 animate = false;
710 // The constraint is managed by Java code, so re-use the existing constraint
711 // and only update the desired state.
712 web_contents_->GetMainFrame()->UpdateBrowserControlsState(
713 current_browser_controls_visibility_constraint_, new_state, animate);
714 }
715
CaptureScreenShot(JNIEnv * env,jfloat scale,const base::android::JavaParamRef<jobject> & value_callback)716 void TabImpl::CaptureScreenShot(
717 JNIEnv* env,
718 jfloat scale,
719 const base::android::JavaParamRef<jobject>& value_callback) {
720 content::RenderWidgetHostView* rwhv = nullptr;
721 gfx::Rect src_rect;
722 gfx::Size output_size;
723 ScreenShotErrors error =
724 PrepareForCaptureScreenShot(scale, &rwhv, &src_rect, &output_size);
725 if (error != ScreenShotErrors::kNone) {
726 Java_TabImpl_runCaptureScreenShotCallback(
727 env, ScopedJavaLocalRef<jobject>(value_callback),
728 ScopedJavaLocalRef<jobject>(), static_cast<int>(error));
729 return;
730 }
731
732 rwhv->CopyFromSurface(
733 src_rect, output_size,
734 base::BindOnce(&OnScreenShotCaptured,
735 ScopedJavaGlobalRef<jobject>(value_callback)));
736 }
737
SetData(JNIEnv * env,const base::android::JavaParamRef<jobjectArray> & data)738 jboolean TabImpl::SetData(
739 JNIEnv* env,
740 const base::android::JavaParamRef<jobjectArray>& data) {
741 std::vector<std::string> flattened_map;
742 base::android::AppendJavaStringArrayToStringVector(env, data, &flattened_map);
743 std::map<std::string, std::string> data_map;
744 for (size_t i = 0; i < flattened_map.size(); i += 2) {
745 data_map.insert({flattened_map[i], flattened_map[i + 1]});
746 }
747 return SetDataInternal(data_map);
748 }
749
GetData(JNIEnv * env)750 base::android::ScopedJavaLocalRef<jobjectArray> TabImpl::GetData(JNIEnv* env) {
751 std::vector<std::string> flattened_map;
752 for (const auto& kv : data_) {
753 flattened_map.push_back(kv.first);
754 flattened_map.push_back(kv.second);
755 }
756 return base::android::ToJavaArrayOfStrings(env, flattened_map);
757 }
758
IsRendererControllingBrowserControlsOffsets(JNIEnv * env)759 jboolean TabImpl::IsRendererControllingBrowserControlsOffsets(JNIEnv* env) {
760 return browser_controls_navigation_state_handler_
761 ->IsRendererControllingOffsets();
762 }
763
RegisterWebMessageCallback(JNIEnv * env,const base::android::JavaParamRef<jstring> & js_object_name,const base::android::JavaParamRef<jobjectArray> & js_origins,const base::android::JavaParamRef<jobject> & client)764 base::android::ScopedJavaLocalRef<jstring> TabImpl::RegisterWebMessageCallback(
765 JNIEnv* env,
766 const base::android::JavaParamRef<jstring>& js_object_name,
767 const base::android::JavaParamRef<jobjectArray>& js_origins,
768 const base::android::JavaParamRef<jobject>& client) {
769 auto proxy = std::make_unique<WebMessageHostFactoryProxy>(client);
770 std::vector<std::string> origins;
771 base::android::AppendJavaStringArrayToStringVector(env, js_origins, &origins);
772 base::string16 result = AddWebMessageHostFactory(
773 std::move(proxy),
774 base::android::ConvertJavaStringToUTF16(env, js_object_name), origins);
775 return base::android::ConvertUTF16ToJavaString(env, result);
776 }
777
UnregisterWebMessageCallback(JNIEnv * env,const base::android::JavaParamRef<jstring> & js_object_name)778 void TabImpl::UnregisterWebMessageCallback(
779 JNIEnv* env,
780 const base::android::JavaParamRef<jstring>& js_object_name) {
781 base::string16 name;
782 base::android::ConvertJavaStringToUTF16(env, js_object_name, &name);
783 RemoveWebMessageHostFactory(name);
784 }
785
CanTranslate(JNIEnv * env)786 jboolean TabImpl::CanTranslate(JNIEnv* env) {
787 return TranslateClientImpl::FromWebContents(web_contents())
788 ->GetTranslateManager()
789 ->CanManuallyTranslate();
790 }
791
ShowTranslateUi(JNIEnv * env)792 void TabImpl::ShowTranslateUi(JNIEnv* env) {
793 TranslateClientImpl::FromWebContents(web_contents())
794 ->ManualTranslateWhenReady();
795 }
796
RemoveTabFromBrowserBeforeDestroying(JNIEnv * env)797 void TabImpl::RemoveTabFromBrowserBeforeDestroying(JNIEnv* env) {
798 DCHECK(browser_);
799 browser_->RemoveTabBeforeDestroyingFromJava(this);
800 }
801
SetTranslateTargetLanguage(JNIEnv * env,const base::android::JavaParamRef<jstring> & translate_target_lang)802 void TabImpl::SetTranslateTargetLanguage(
803 JNIEnv* env,
804 const base::android::JavaParamRef<jstring>& translate_target_lang) {
805 translate::TranslateManager* translate_manager =
806 TranslateClientImpl::FromWebContents(web_contents())
807 ->GetTranslateManager();
808 translate_manager->SetPredefinedTargetLanguage(
809 base::android::ConvertJavaStringToUTF8(env, translate_target_lang));
810 }
811
SetDesktopUserAgentEnabled(JNIEnv * env,jboolean enable)812 void TabImpl::SetDesktopUserAgentEnabled(JNIEnv* env, jboolean enable) {
813 if (desktop_user_agent_enabled_ == enable)
814 return;
815
816 desktop_user_agent_enabled_ = enable;
817
818 // Reset state that an earlier call to Navigation::SetUserAgentString()
819 // could have modified.
820 embedder_support::SetDesktopUserAgentOverride(web_contents_.get(),
821 GetUserAgentMetadata());
822 web_contents_->SetRendererInitiatedUserAgentOverrideOption(
823 content::NavigationController::UA_OVERRIDE_INHERIT);
824
825 content::NavigationEntry* entry =
826 web_contents_->GetController().GetLastCommittedEntry();
827 if (!entry)
828 return;
829
830 entry->SetIsOverridingUserAgent(enable);
831 web_contents_->NotifyPreferencesChanged();
832 web_contents_->GetController().Reload(
833 content::ReloadType::ORIGINAL_REQUEST_URL, true);
834 }
835
IsDesktopUserAgentEnabled(JNIEnv * env)836 jboolean TabImpl::IsDesktopUserAgentEnabled(JNIEnv* env) {
837 auto* entry = web_contents_->GetController().GetLastCommittedEntry();
838 if (!entry)
839 return false;
840
841 // The same user agent override mechanism is used for per-navigation user
842 // agent and desktop mode. Make sure not to return desktop mode for
843 // navigation entries which used a per-navigation user agent.
844 auto* entry_data = NavigationEntryData::Get(entry);
845 if (entry_data && entry_data->per_navigation_user_agent_override())
846 return false;
847
848 return entry->GetIsOverridingUserAgent();
849 }
850
Download(JNIEnv * env,jlong native_context_menu_params)851 void TabImpl::Download(JNIEnv* env, jlong native_context_menu_params) {
852 auto* context_menu_params =
853 reinterpret_cast<content::ContextMenuParams*>(native_context_menu_params);
854
855 bool is_link = context_menu_params->media_type !=
856 blink::ContextMenuDataMediaType::kImage &&
857 context_menu_params->media_type !=
858 blink::ContextMenuDataMediaType::kVideo;
859
860 download::CreateContextMenuDownload(web_contents_.get(), *context_menu_params,
861 std::string(), is_link);
862 }
863 #endif // OS_ANDROID
864
OpenURLFromTab(content::WebContents * source,const content::OpenURLParams & params)865 content::WebContents* TabImpl::OpenURLFromTab(
866 content::WebContents* source,
867 const content::OpenURLParams& params) {
868 if (blocked_content::ConsiderForPopupBlocking(params.disposition)) {
869 bool blocked = blocked_content::MaybeBlockPopup(
870 source, nullptr,
871 std::make_unique<PopupNavigationDelegateImpl>(
872 params, source, nullptr),
873 ¶ms, blink::mojom::WindowFeatures(),
874 HostContentSettingsMapFactory::GetForBrowserContext(
875 source->GetBrowserContext())) == nullptr;
876 if (blocked)
877 return nullptr;
878 }
879
880 if (params.disposition == WindowOpenDisposition::CURRENT_TAB) {
881 source->GetController().LoadURLWithParams(
882 content::NavigationController::LoadURLParams(params));
883 return source;
884 }
885
886 // All URLs not opening in the current tab will get a new tab.
887 std::unique_ptr<content::WebContents> new_tab_contents =
888 content::WebContents::Create(content::WebContents::CreateParams(
889 web_contents()->GetBrowserContext()));
890 WebContentsTracker tracker(new_tab_contents.get());
891 bool was_blocked = false;
892 AddNewContents(web_contents(), std::move(new_tab_contents), params.url,
893 params.disposition, {}, params.user_gesture, &was_blocked);
894 if (was_blocked || !tracker.web_contents())
895 return nullptr;
896 tracker.web_contents()->GetController().LoadURLWithParams(
897 content::NavigationController::LoadURLParams(params));
898 return tracker.web_contents();
899 }
900
ShowRepostFormWarningDialog(content::WebContents * source)901 void TabImpl::ShowRepostFormWarningDialog(content::WebContents* source) {
902 #if defined(OS_ANDROID)
903 Java_TabImpl_showRepostFormWarningDialog(base::android::AttachCurrentThread(),
904 java_impl_);
905 #else
906 source->GetController().CancelPendingReload();
907 #endif
908 }
909
NavigationStateChanged(content::WebContents * source,content::InvalidateTypes changed_flags)910 void TabImpl::NavigationStateChanged(content::WebContents* source,
911 content::InvalidateTypes changed_flags) {
912 DCHECK_EQ(web_contents_.get(), source);
913 if (changed_flags & content::INVALIDATE_TYPE_URL) {
914 for (auto& observer : observers_)
915 observer.DisplayedUrlChanged(source->GetVisibleURL());
916 UpdateBrowserVisibleSecurityStateIfNecessary();
917 }
918
919 // TODO(crbug.com/1064582): INVALIDATE_TYPE_TITLE is called only when a title
920 // is set on the active navigation entry, but not when the active entry
921 // changes, so check INVALIDATE_TYPE_LOAD here as well. However this should
922 // be fixed and INVALIDATE_TYPE_LOAD should be removed.
923 if (changed_flags &
924 (content::INVALIDATE_TYPE_TITLE | content::INVALIDATE_TYPE_LOAD)) {
925 base::string16 title = web_contents_->GetTitle();
926 if (title_ != title) {
927 title_ = title;
928 for (auto& observer : observers_)
929 observer.OnTitleUpdated(title);
930 }
931 }
932 }
933
GetJavaScriptDialogManager(content::WebContents * web_contents)934 content::JavaScriptDialogManager* TabImpl::GetJavaScriptDialogManager(
935 content::WebContents* web_contents) {
936 #if defined(OS_ANDROID)
937 return javascript_dialogs::TabModalDialogManager::FromWebContents(
938 web_contents);
939 #else
940 return nullptr;
941 #endif
942 }
943
OpenColorChooser(content::WebContents * web_contents,SkColor color,const std::vector<blink::mojom::ColorSuggestionPtr> & suggestions)944 content::ColorChooser* TabImpl::OpenColorChooser(
945 content::WebContents* web_contents,
946 SkColor color,
947 const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions) {
948 #if defined(OS_ANDROID)
949 return new web_contents_delegate_android::ColorChooserAndroid(
950 web_contents, color, suggestions);
951 #else
952 return nullptr;
953 #endif
954 }
955
CreateSmsPrompt(content::RenderFrameHost * render_frame_host,const url::Origin & origin,const std::string & one_time_code,base::OnceClosure on_confirm,base::OnceClosure on_cancel)956 void TabImpl::CreateSmsPrompt(content::RenderFrameHost* render_frame_host,
957 const url::Origin& origin,
958 const std::string& one_time_code,
959 base::OnceClosure on_confirm,
960 base::OnceClosure on_cancel) {
961 #if defined(OS_ANDROID)
962 auto* web_contents =
963 content::WebContents::FromRenderFrameHost(render_frame_host);
964 sms::SmsInfoBar::Create(
965 web_contents, InfoBarService::FromWebContents(web_contents),
966 InfoBarService::GetResourceIdMapper(), origin, one_time_code,
967 std::move(on_confirm), std::move(on_cancel));
968 #else
969 NOTREACHED();
970 #endif
971 }
972
RunFileChooser(content::RenderFrameHost * render_frame_host,scoped_refptr<content::FileSelectListener> listener,const blink::mojom::FileChooserParams & params)973 void TabImpl::RunFileChooser(
974 content::RenderFrameHost* render_frame_host,
975 scoped_refptr<content::FileSelectListener> listener,
976 const blink::mojom::FileChooserParams& params) {
977 FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
978 params);
979 }
980
GetTopControlsHeight()981 int TabImpl::GetTopControlsHeight() {
982 #if defined(OS_ANDROID)
983 return top_controls_container_view_
984 ? top_controls_container_view_->GetControlsHeight()
985 : 0;
986 #else
987 return 0;
988 #endif
989 }
990
GetTopControlsMinHeight()991 int TabImpl::GetTopControlsMinHeight() {
992 #if defined(OS_ANDROID)
993 return top_controls_container_view_
994 ? top_controls_container_view_->GetMinHeight()
995 : 0;
996 #else
997 return 0;
998 #endif
999 }
1000
GetBottomControlsHeight()1001 int TabImpl::GetBottomControlsHeight() {
1002 #if defined(OS_ANDROID)
1003 return bottom_controls_container_view_
1004 ? bottom_controls_container_view_->GetControlsHeight()
1005 : 0;
1006 #else
1007 return 0;
1008 #endif
1009 }
1010
DoBrowserControlsShrinkRendererSize(content::WebContents * web_contents)1011 bool TabImpl::DoBrowserControlsShrinkRendererSize(
1012 content::WebContents* web_contents) {
1013 #if defined(OS_ANDROID)
1014 TRACE_EVENT0("weblayer", "Java_TabImpl_doBrowserControlsShrinkRendererSize");
1015 return Java_TabImpl_doBrowserControlsShrinkRendererSize(AttachCurrentThread(),
1016 java_impl_);
1017 #else
1018 return false;
1019 #endif
1020 }
1021
ShouldAnimateBrowserControlsHeightChanges()1022 bool TabImpl::ShouldAnimateBrowserControlsHeightChanges() {
1023 #if defined(OS_ANDROID)
1024 return top_controls_container_view_
1025 ? top_controls_container_view_
1026 ->ShouldAnimateBrowserControlsHeightChanges()
1027 : false;
1028 #else
1029 return false;
1030 #endif
1031 }
1032
OnlyExpandTopControlsAtPageTop()1033 bool TabImpl::OnlyExpandTopControlsAtPageTop() {
1034 #if defined(OS_ANDROID)
1035 return top_controls_container_view_
1036 ? top_controls_container_view_->OnlyExpandControlsAtPageTop()
1037 : false;
1038 #else
1039 return false;
1040 #endif
1041 }
1042
RequestMediaAccessPermission(content::WebContents * web_contents,const content::MediaStreamRequest & request,content::MediaResponseCallback callback)1043 void TabImpl::RequestMediaAccessPermission(
1044 content::WebContents* web_contents,
1045 const content::MediaStreamRequest& request,
1046 content::MediaResponseCallback callback) {
1047 #if defined(OS_ANDROID)
1048 MediaStreamManager::FromWebContents(web_contents)
1049 ->RequestMediaAccessPermission(request, std::move(callback));
1050 #else
1051 std::move(callback).Run(
1052 {}, blink::mojom::MediaStreamRequestResult::NOT_SUPPORTED, nullptr);
1053 #endif
1054 }
1055
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type)1056 bool TabImpl::CheckMediaAccessPermission(
1057 content::RenderFrameHost* render_frame_host,
1058 const GURL& security_origin,
1059 blink::mojom::MediaStreamType type) {
1060 DCHECK(type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
1061 type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
1062 ContentSettingsType content_settings_type =
1063 type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE
1064 ? ContentSettingsType::MEDIASTREAM_MIC
1065 : ContentSettingsType::MEDIASTREAM_CAMERA;
1066 return PermissionManagerFactory::GetForBrowserContext(
1067 content::WebContents::FromRenderFrameHost(render_frame_host)
1068 ->GetBrowserContext())
1069 ->GetPermissionStatusForFrame(content_settings_type,
1070 render_frame_host, security_origin)
1071 .content_setting == CONTENT_SETTING_ALLOW;
1072 }
1073
EnterFullscreenModeForTab(content::RenderFrameHost * requesting_frame,const blink::mojom::FullscreenOptions & options)1074 void TabImpl::EnterFullscreenModeForTab(
1075 content::RenderFrameHost* requesting_frame,
1076 const blink::mojom::FullscreenOptions& options) {
1077 // TODO: support |options|.
1078 is_fullscreen_ = true;
1079 auto exit_fullscreen_closure = base::BindOnce(&TabImpl::OnExitFullscreen,
1080 weak_ptr_factory_.GetWeakPtr());
1081 base::AutoReset<bool> reset(&processing_enter_fullscreen_, true);
1082 fullscreen_delegate_->EnterFullscreen(std::move(exit_fullscreen_closure));
1083 #if defined(OS_ANDROID)
1084 // Make sure browser controls cannot show when the tab is fullscreen.
1085 SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
1086 content::BROWSER_CONTROLS_STATE_HIDDEN);
1087 #endif
1088 }
1089
ExitFullscreenModeForTab(content::WebContents * web_contents)1090 void TabImpl::ExitFullscreenModeForTab(content::WebContents* web_contents) {
1091 is_fullscreen_ = false;
1092 fullscreen_delegate_->ExitFullscreen();
1093 #if defined(OS_ANDROID)
1094 // Attempt to show browser controls when exiting fullscreen.
1095 SetBrowserControlsConstraint(ControlsVisibilityReason::kFullscreen,
1096 content::BROWSER_CONTROLS_STATE_BOTH);
1097 #endif
1098 }
1099
IsFullscreenForTabOrPending(const content::WebContents * web_contents)1100 bool TabImpl::IsFullscreenForTabOrPending(
1101 const content::WebContents* web_contents) {
1102 return is_fullscreen_;
1103 }
1104
GetDisplayMode(const content::WebContents * web_contents)1105 blink::mojom::DisplayMode TabImpl::GetDisplayMode(
1106 const content::WebContents* web_contents) {
1107 return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen
1108 : blink::mojom::DisplayMode::kBrowser;
1109 }
1110
AddNewContents(content::WebContents * source,std::unique_ptr<content::WebContents> new_contents,const GURL & target_url,WindowOpenDisposition disposition,const gfx::Rect & initial_rect,bool user_gesture,bool * was_blocked)1111 void TabImpl::AddNewContents(content::WebContents* source,
1112 std::unique_ptr<content::WebContents> new_contents,
1113 const GURL& target_url,
1114 WindowOpenDisposition disposition,
1115 const gfx::Rect& initial_rect,
1116 bool user_gesture,
1117 bool* was_blocked) {
1118 if (!new_tab_delegate_) {
1119 *was_blocked = true;
1120 return;
1121 }
1122
1123 // At this point the |new_contents| is beyond the popup blocker, but we use
1124 // the same logic for determining if the popup tracker needs to be attached.
1125 if (source && blocked_content::ConsiderForPopupBlocking(disposition)) {
1126 blocked_content::PopupTracker::CreateForWebContents(new_contents.get(),
1127 source, disposition);
1128 }
1129
1130 new_tab_delegate_->OnNewTab(browser_->CreateTab(std::move(new_contents)),
1131 NewTabTypeFromWindowDisposition(disposition));
1132 }
1133
CloseContents(content::WebContents * source)1134 void TabImpl::CloseContents(content::WebContents* source) {
1135 // The only time that |browser_| is null is during shutdown, and this callback
1136 // shouldn't come in at that time.
1137 DCHECK(browser_);
1138
1139 #if defined(OS_ANDROID)
1140 JNIEnv* env = AttachCurrentThread();
1141 Java_TabImpl_handleCloseFromWebContents(env, java_impl_);
1142 // The above call resulted in the destruction of this; nothing to do but
1143 // return.
1144 #else
1145 browser_->DestroyTab(this);
1146 #endif
1147 }
1148
FindReply(content::WebContents * web_contents,int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)1149 void TabImpl::FindReply(content::WebContents* web_contents,
1150 int request_id,
1151 int number_of_matches,
1152 const gfx::Rect& selection_rect,
1153 int active_match_ordinal,
1154 bool final_update) {
1155 GetFindTabHelper()->HandleFindReply(request_id, number_of_matches,
1156 selection_rect, active_match_ordinal,
1157 final_update);
1158 }
1159
1160 #if defined(OS_ANDROID)
1161 // FindMatchRectsReply and OnFindResultAvailable forward find-related results to
1162 // the Java TabImpl. The find actions themselves are initiated directly from
1163 // Java via FindInPageBridge.
FindMatchRectsReply(content::WebContents * web_contents,int version,const std::vector<gfx::RectF> & rects,const gfx::RectF & active_rect)1164 void TabImpl::FindMatchRectsReply(content::WebContents* web_contents,
1165 int version,
1166 const std::vector<gfx::RectF>& rects,
1167 const gfx::RectF& active_rect) {
1168 JNIEnv* env = AttachCurrentThread();
1169 // Create the details object.
1170 ScopedJavaLocalRef<jobject> details_object =
1171 Java_TabImpl_createFindMatchRectsDetails(
1172 env, version, rects.size(),
1173 ScopedJavaLocalRef<jobject>(Java_TabImpl_createRectF(
1174 env, active_rect.x(), active_rect.y(), active_rect.right(),
1175 active_rect.bottom())));
1176
1177 // Add the rects.
1178 for (size_t i = 0; i < rects.size(); ++i) {
1179 const gfx::RectF& rect = rects[i];
1180 Java_TabImpl_setMatchRectByIndex(
1181 env, details_object, i,
1182 ScopedJavaLocalRef<jobject>(Java_TabImpl_createRectF(
1183 env, rect.x(), rect.y(), rect.right(), rect.bottom())));
1184 }
1185
1186 Java_TabImpl_onFindMatchRectsAvailable(env, java_impl_, details_object);
1187 }
1188 #endif
1189
RenderProcessGone(base::TerminationStatus status)1190 void TabImpl::RenderProcessGone(base::TerminationStatus status) {
1191 #if defined(OS_ANDROID)
1192 // If a renderer process is lost when the tab is not visible, indicate to the
1193 // WebContents that it should automatically reload the next time it becomes
1194 // visible.
1195 JNIEnv* env = AttachCurrentThread();
1196 if (Java_TabImpl_willAutomaticallyReloadAfterCrashImpl(env, java_impl_))
1197 web_contents()->GetController().SetNeedsReload();
1198 #endif
1199
1200 for (auto& observer : observers_)
1201 observer.OnRenderProcessGone();
1202 }
1203
OnFindResultAvailable(content::WebContents * web_contents)1204 void TabImpl::OnFindResultAvailable(content::WebContents* web_contents) {
1205 #if defined(OS_ANDROID)
1206 const find_in_page::FindNotificationDetails& find_result =
1207 GetFindTabHelper()->find_result();
1208 JNIEnv* env = AttachCurrentThread();
1209 Java_TabImpl_onFindResultAvailable(
1210 env, java_impl_, find_result.number_of_matches(),
1211 find_result.active_match_ordinal(), find_result.final_update());
1212 #endif
1213 }
1214
1215 #if defined(OS_ANDROID)
OnBrowserControlsStateStateChanged(ControlsVisibilityReason reason,content::BrowserControlsState state)1216 void TabImpl::OnBrowserControlsStateStateChanged(
1217 ControlsVisibilityReason reason,
1218 content::BrowserControlsState state) {
1219 SetBrowserControlsConstraint(reason, state);
1220 }
1221
OnUpdateBrowserControlsStateBecauseOfProcessSwitch(bool did_commit)1222 void TabImpl::OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
1223 bool did_commit) {
1224 // This matches the logic of updateAfterRendererProcessSwitch() and
1225 // updateEnabledState() in Chrome's TabBrowserControlsConstraintsHelper.
1226 if (did_commit &&
1227 current_browser_controls_visibility_constraint_ ==
1228 content::BROWSER_CONTROLS_STATE_SHOWN &&
1229 top_controls_container_view_ &&
1230 top_controls_container_view_->IsFullyVisible()) {
1231 // The top-control is fully visible, don't animate this else the controls
1232 // bounce around.
1233 UpdateBrowserControlsState(content::BROWSER_CONTROLS_STATE_SHOWN, false);
1234 } else {
1235 if (did_commit && current_browser_controls_visibility_constraint_ ==
1236 content::BROWSER_CONTROLS_STATE_BOTH) {
1237 // If the current state is BROWSER_CONTROLS_STATE_BOTH, then
1238 // TabImpl::UpdateBrowserControlsState() is going to call
1239 // WebContents::UpdateBrowserControlsState() with both current and
1240 // constraints set to BROWSER_CONTROLS_STATE_BOTH. cc does
1241 // nothing in this case. During a navigation the top-view needs to be
1242 // shown. To force the top-view to show, supply
1243 // BROWSER_CONTROLS_STATE_SHOWN. This path is only hit if top-view
1244 // is configured to only-expand-at-top, as in this case the top-view isn't
1245 // forced shown during a page load.
1246 //
1247 // It's entirely possible the scroll offset is changed as part of the
1248 // loading process (such as happens with back/forward navigation or
1249 // links part way down a page). Trying to detect this and compensate
1250 // here is likely to be racy, so the top-view is always shown.
1251 const bool animate =
1252 !base::FeatureList::IsEnabled(kImmediatelyHideBrowserControlsForTest);
1253 web_contents_->GetMainFrame()->UpdateBrowserControlsState(
1254 content::BROWSER_CONTROLS_STATE_BOTH,
1255 content::BROWSER_CONTROLS_STATE_SHOWN, animate);
1256 // This falls through to call UpdateBrowserControlsState() again to
1257 // ensure the constraint is set back to BOTH.
1258 }
1259 UpdateBrowserControlsState(
1260 content::BROWSER_CONTROLS_STATE_BOTH,
1261 current_browser_controls_visibility_constraint_ !=
1262 content::BROWSER_CONTROLS_STATE_HIDDEN);
1263 }
1264 }
1265
1266 #endif
1267
DidChangeVisibleSecurityState()1268 void TabImpl::DidChangeVisibleSecurityState() {
1269 UpdateBrowserVisibleSecurityStateIfNecessary();
1270 }
1271
UpdateBrowserVisibleSecurityStateIfNecessary()1272 void TabImpl::UpdateBrowserVisibleSecurityStateIfNecessary() {
1273 if (browser_ && browser_->GetActiveTab() == this)
1274 browser_->VisibleSecurityStateOfActiveTabChanged();
1275 }
1276
OnExitFullscreen()1277 void TabImpl::OnExitFullscreen() {
1278 // If |processing_enter_fullscreen_| is true, it means the callback is being
1279 // called while processing EnterFullscreenModeForTab(). WebContents doesn't
1280 // deal well with this. FATAL as Android generally doesn't run with DCHECKs.
1281 LOG_IF(FATAL, processing_enter_fullscreen_)
1282 << "exiting fullscreen while entering fullscreen is not supported";
1283 web_contents_->ExitFullscreen(/* will_cause_resize */ false);
1284 }
1285
UpdateRendererPrefs(bool should_sync_prefs)1286 void TabImpl::UpdateRendererPrefs(bool should_sync_prefs) {
1287 blink::RendererPreferences* prefs = web_contents_->GetMutableRendererPrefs();
1288 content::UpdateFontRendererPreferencesFromSystemSettings(prefs);
1289 prefs->accept_languages = i18n::GetAcceptLangs();
1290 if (should_sync_prefs)
1291 web_contents_->SyncRendererPrefs();
1292 }
1293
1294 #if defined(OS_ANDROID)
SetBrowserControlsConstraint(ControlsVisibilityReason reason,content::BrowserControlsState constraint)1295 void TabImpl::SetBrowserControlsConstraint(
1296 ControlsVisibilityReason reason,
1297 content::BrowserControlsState constraint) {
1298 Java_TabImpl_setBrowserControlsVisibilityConstraint(
1299 base::android::AttachCurrentThread(), java_impl_,
1300 static_cast<int>(reason), constraint);
1301 }
1302 #endif
1303
InitializeAutofillForTests(std::unique_ptr<autofill::AutofillProvider> provider)1304 void TabImpl::InitializeAutofillForTests(
1305 std::unique_ptr<autofill::AutofillProvider> provider) {
1306 DCHECK(!autofill_provider_);
1307
1308 autofill_provider_ = std::move(provider);
1309 InitializeAutofill();
1310 }
1311
InitializeAutofill()1312 void TabImpl::InitializeAutofill() {
1313 DCHECK(autofill_provider_);
1314
1315 content::WebContents* web_contents = web_contents_.get();
1316 DCHECK(
1317 !autofill::ContentAutofillDriverFactory::FromWebContents(web_contents));
1318
1319 AutofillClientImpl::CreateForWebContents(web_contents);
1320 autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
1321 web_contents, AutofillClientImpl::FromWebContents(web_contents),
1322 i18n::GetApplicationLocale(),
1323 autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER,
1324 autofill_provider_.get());
1325 }
1326
GetFindTabHelper()1327 find_in_page::FindTabHelper* TabImpl::GetFindTabHelper() {
1328 return find_in_page::FindTabHelper::FromWebContents(web_contents_.get());
1329 }
1330
1331 // static
GetSessionServiceTabHelperDelegate(content::WebContents * web_contents)1332 sessions::SessionTabHelperDelegate* TabImpl::GetSessionServiceTabHelperDelegate(
1333 content::WebContents* web_contents) {
1334 TabImpl* tab = FromWebContents(web_contents);
1335 return (tab && tab->browser_) ? tab->browser_->browser_persister() : nullptr;
1336 }
1337
SetDataInternal(const std::map<std::string,std::string> & data)1338 bool TabImpl::SetDataInternal(const std::map<std::string, std::string>& data) {
1339 int total_size = 0;
1340 for (const auto& kv : data)
1341 total_size += kv.first.size() + kv.second.size();
1342 if (total_size > kMaxDataSize)
1343 return false;
1344 data_ = data;
1345 for (auto& observer : data_observers_)
1346 observer.OnDataChanged(this, data_);
1347 return true;
1348 }
1349
1350 } // namespace weblayer
1351