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 #ifndef WEBLAYER_BROWSER_TAB_IMPL_H_
6 #define WEBLAYER_BROWSER_TAB_IMPL_H_
7 
8 #include <memory>
9 #include <set>
10 
11 #include "base/callback_forward.h"
12 #include "base/macros.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/observer_list.h"
15 #include "base/strings/string16.h"
16 #include "build/build_config.h"
17 #include "components/find_in_page/find_result_observer.h"
18 #include "content/public/browser/web_contents_delegate.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/browser_controls_state.h"
21 #include "weblayer/browser/i18n_util.h"
22 #include "weblayer/public/tab.h"
23 
24 #if defined(OS_ANDROID)
25 #include "base/android/scoped_java_ref.h"
26 #include "weblayer/browser/browser_controls_navigation_state_handler_delegate.h"
27 #endif
28 
29 namespace js_injection {
30 class JsCommunicationHost;
31 }
32 
33 namespace autofill {
34 class AutofillProvider;
35 }  // namespace autofill
36 
37 namespace blink {
38 namespace web_pref {
39 struct WebPreferences;
40 }
41 }  // namespace blink
42 
43 namespace content {
44 class RenderWidgetHostView;
45 class WebContents;
46 struct ContextMenuParams;
47 }
48 
49 namespace gfx {
50 class Rect;
51 class Size;
52 }  // namespace gfx
53 
54 namespace sessions {
55 class SessionTabHelperDelegate;
56 }
57 
58 namespace weblayer {
59 class BrowserControlsNavigationStateHandler;
60 class BrowserImpl;
61 class FullscreenDelegate;
62 class NavigationControllerImpl;
63 class NewTabDelegate;
64 class ProfileImpl;
65 
66 #if defined(OS_ANDROID)
67 class BrowserControlsContainerView;
68 enum class ControlsVisibilityReason;
69 class WebMessageHostFactoryProxy;
70 #endif
71 
72 class TabImpl : public Tab,
73                 public content::WebContentsDelegate,
74                 public content::WebContentsObserver,
75 #if defined(OS_ANDROID)
76                 public BrowserControlsNavigationStateHandlerDelegate,
77 #endif
78                 public find_in_page::FindResultObserver {
79  public:
80   enum class ScreenShotErrors {
81     kNone = 0,
82     kScaleOutOfRange,
83     kTabNotActive,
84     kWebContentsNotVisible,
85     kNoSurface,
86     kNoRenderWidgetHostView,
87     kNoWindowAndroid,
88     kEmptyViewport,
89     kHiddenByControls,
90     kScaledToEmpty,
91     kCaptureFailed,
92     kBitmapAllocationFailed,
93   };
94 
95   class DataObserver {
96    public:
97     // Called when SetData() is called on |tab|.
98     virtual void OnDataChanged(
99         TabImpl* tab,
100         const std::map<std::string, std::string>& data) = 0;
101   };
102 
103   // TODO(sky): investigate a better way to not have so many ifdefs.
104 #if defined(OS_ANDROID)
105   TabImpl(ProfileImpl* profile,
106           const base::android::JavaParamRef<jobject>& java_impl,
107           std::unique_ptr<content::WebContents> web_contents);
108 #endif
109   explicit TabImpl(ProfileImpl* profile,
110                    std::unique_ptr<content::WebContents> web_contents,
111                    const std::string& guid = std::string());
112   ~TabImpl() override;
113 
114   // Returns the TabImpl from the specified WebContents (which may be null), or
115   // null if |web_contents| was not created by a TabImpl.
116   static TabImpl* FromWebContents(content::WebContents* web_contents);
117 
118   static std::set<TabImpl*> GetAllTabImpl();
119 
profile()120   ProfileImpl* profile() { return profile_; }
121 
set_browser(BrowserImpl * browser)122   void set_browser(BrowserImpl* browser) { browser_ = browser; }
browser()123   BrowserImpl* browser() { return browser_; }
124 
web_contents()125   content::WebContents* web_contents() const { return web_contents_.get(); }
126 
has_new_tab_delegate()127   bool has_new_tab_delegate() const { return new_tab_delegate_ != nullptr; }
new_tab_delegate()128   NewTabDelegate* new_tab_delegate() const { return new_tab_delegate_; }
129 
130   // Called from Browser when this Tab is losing active status.
131   void OnLosingActive();
132 
133   bool IsActive();
134 
135   void ShowContextMenu(const content::ContextMenuParams& params);
136 
137 #if defined(OS_ANDROID)
GetJavaTab()138   base::android::ScopedJavaGlobalRef<jobject> GetJavaTab() {
139     return java_impl_;
140   }
141 
desktop_user_agent_enabled()142   bool desktop_user_agent_enabled() { return desktop_user_agent_enabled_; }
143 
144   // Call this method to disable integration with the system-level Autofill
145   // infrastructure. Useful in conjunction with InitializeAutofillForTests().
146   // Should be called early in the lifetime of WebLayer, and in
147   // particular, must be called before the TabImpl is attached to the browser
148   // on the Java side to have the desired effect.
149   static void DisableAutofillSystemIntegrationForTesting();
150 
151   base::android::ScopedJavaLocalRef<jobject> GetWebContents(JNIEnv* env);
152   void SetBrowserControlsContainerViews(
153       JNIEnv* env,
154       jlong native_top_browser_controls_container_view,
155       jlong native_bottom_browser_controls_container_view);
156   void ExecuteScript(JNIEnv* env,
157                      const base::android::JavaParamRef<jstring>& script,
158                      bool use_separate_isolate,
159                      const base::android::JavaParamRef<jobject>& callback);
160   void SetJavaImpl(JNIEnv* env,
161                    const base::android::JavaParamRef<jobject>& impl);
162 
163   // Invoked every time that the Java-side AutofillProvider instance is
164   // changed (set to null or to a new object). On first invocation with a non-
165   // null object initializes the native Autofill infrastructure. On
166   // subsequent invocations updates the association of that native
167   // infrastructure with its Java counterpart.
168   void OnAutofillProviderChanged(
169       JNIEnv* env,
170       const base::android::JavaParamRef<jobject>& autofill_provider);
171   void UpdateBrowserControlsConstraint(JNIEnv* env,
172                                        jint constraint,
173                                        jboolean animate);
174 
175   base::android::ScopedJavaLocalRef<jstring> GetGuid(JNIEnv* env);
176   void CaptureScreenShot(
177       JNIEnv* env,
178       jfloat scale,
179       const base::android::JavaParamRef<jobject>& value_callback);
180 
181   jboolean SetData(JNIEnv* env,
182                    const base::android::JavaParamRef<jobjectArray>& data);
183   base::android::ScopedJavaLocalRef<jobjectArray> GetData(JNIEnv* env);
184   jboolean IsRendererControllingBrowserControlsOffsets(JNIEnv* env);
185   base::android::ScopedJavaLocalRef<jstring> RegisterWebMessageCallback(
186       JNIEnv* env,
187       const base::android::JavaParamRef<jstring>& js_object_name,
188       const base::android::JavaParamRef<jobjectArray>& origins,
189       const base::android::JavaParamRef<jobject>& client);
190   void UnregisterWebMessageCallback(
191       JNIEnv* env,
192       const base::android::JavaParamRef<jstring>& js_object_name);
193   jboolean CanTranslate(JNIEnv* env);
194   void ShowTranslateUi(JNIEnv* env);
195   void RemoveTabFromBrowserBeforeDestroying(JNIEnv* env);
196   void SetTranslateTargetLanguage(
197       JNIEnv* env,
198       const base::android::JavaParamRef<jstring>& translate_target_lang);
199   void SetDesktopUserAgentEnabled(JNIEnv* env, jboolean enable);
200   jboolean IsDesktopUserAgentEnabled(JNIEnv* env);
201   void Download(JNIEnv* env, jlong native_context_menu_params);
202 #endif
203 
error_page_delegate()204   ErrorPageDelegate* error_page_delegate() { return error_page_delegate_; }
205 
206   void AddDataObserver(DataObserver* observer);
207   void RemoveDataObserver(DataObserver* observer);
208 
google_accounts_delegate()209   GoogleAccountsDelegate* google_accounts_delegate() {
210     return google_accounts_delegate_;
211   }
212 
213   // Tab:
214   Browser* GetBrowser() override;
215   void SetErrorPageDelegate(ErrorPageDelegate* delegate) override;
216   void SetFullscreenDelegate(FullscreenDelegate* delegate) override;
217   void SetNewTabDelegate(NewTabDelegate* delegate) override;
218   void SetGoogleAccountsDelegate(GoogleAccountsDelegate* delegate) override;
219   void AddObserver(TabObserver* observer) override;
220   void RemoveObserver(TabObserver* observer) override;
221   NavigationController* GetNavigationController() override;
222   void ExecuteScript(const base::string16& script,
223                      bool use_separate_isolate,
224                      JavaScriptResultCallback callback) override;
225   const std::string& GetGuid() override;
226   void SetData(const std::map<std::string, std::string>& data) override;
227   const std::map<std::string, std::string>& GetData() override;
228   base::string16 AddWebMessageHostFactory(
229       std::unique_ptr<WebMessageHostFactory> factory,
230       const base::string16& js_object_name,
231       const std::vector<std::string>& js_origins) override;
232   void RemoveWebMessageHostFactory(
233       const base::string16& js_object_name) override;
234   std::unique_ptr<FaviconFetcher> CreateFaviconFetcher(
235       FaviconFetcherDelegate* delegate) override;
236 #if !defined(OS_ANDROID)
237   void AttachToView(views::WebView* web_view) override;
238 #endif
239 
240   void WebPreferencesChanged();
241   void SetWebPreferences(blink::web_pref::WebPreferences* prefs);
242 
243   // Executes |script| with a user gesture.
244   void ExecuteScriptWithUserGestureForTests(const base::string16& script);
245 
246   // Initializes the autofill system with |provider| for tests.
247   void InitializeAutofillForTests(
248       std::unique_ptr<autofill::AutofillProvider> provider);
249 
250  private:
251   // content::WebContentsDelegate:
252   content::WebContents* OpenURLFromTab(
253       content::WebContents* source,
254       const content::OpenURLParams& params) override;
255   void ShowRepostFormWarningDialog(content::WebContents* source) override;
256   void NavigationStateChanged(content::WebContents* source,
257                               content::InvalidateTypes changed_flags) override;
258   content::JavaScriptDialogManager* GetJavaScriptDialogManager(
259       content::WebContents* web_contents) override;
260   content::ColorChooser* OpenColorChooser(
261       content::WebContents* web_contents,
262       SkColor color,
263       const std::vector<blink::mojom::ColorSuggestionPtr>& suggestions)
264       override;
265   void RunFileChooser(content::RenderFrameHost* render_frame_host,
266                       scoped_refptr<content::FileSelectListener> listener,
267                       const blink::mojom::FileChooserParams& params) override;
268   void CreateSmsPrompt(content::RenderFrameHost*,
269                        const url::Origin&,
270                        const std::string& one_time_code,
271                        base::OnceClosure on_confirm,
272                        base::OnceClosure on_cancel) override;
273   int GetTopControlsHeight() override;
274   int GetTopControlsMinHeight() override;
275   int GetBottomControlsHeight() override;
276   bool DoBrowserControlsShrinkRendererSize(
277       content::WebContents* web_contents) override;
278   bool OnlyExpandTopControlsAtPageTop() override;
279   bool ShouldAnimateBrowserControlsHeightChanges() override;
280   void RequestMediaAccessPermission(
281       content::WebContents* web_contents,
282       const content::MediaStreamRequest& request,
283       content::MediaResponseCallback callback) override;
284   bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
285                                   const GURL& security_origin,
286                                   blink::mojom::MediaStreamType type) override;
287   void EnterFullscreenModeForTab(
288       content::RenderFrameHost* requesting_frame,
289       const blink::mojom::FullscreenOptions& options) override;
290   void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
291   bool IsFullscreenForTabOrPending(
292       const content::WebContents* web_contents) override;
293   blink::mojom::DisplayMode GetDisplayMode(
294       const content::WebContents* web_contents) override;
295   void AddNewContents(content::WebContents* source,
296                       std::unique_ptr<content::WebContents> new_contents,
297                       const GURL& target_url,
298                       WindowOpenDisposition disposition,
299                       const gfx::Rect& initial_rect,
300                       bool user_gesture,
301                       bool* was_blocked) override;
302   void CloseContents(content::WebContents* source) override;
303   void FindReply(content::WebContents* web_contents,
304                  int request_id,
305                  int number_of_matches,
306                  const gfx::Rect& selection_rect,
307                  int active_match_ordinal,
308                  bool final_update) override;
309 #if defined(OS_ANDROID)
310   void FindMatchRectsReply(content::WebContents* web_contents,
311                            int version,
312                            const std::vector<gfx::RectF>& rects,
313                            const gfx::RectF& active_rect) override;
314 
315   // Pointer arguments are outputs. Check the preconditions for capturing a
316   // screenshot and either set all outputs, or return an error code, in which
317   // case the state of output arguments is undefined.
318   ScreenShotErrors PrepareForCaptureScreenShot(
319       float scale,
320       content::RenderWidgetHostView** rwhv,
321       gfx::Rect* src_rect,
322       gfx::Size* output_size);
323 
324   void UpdateBrowserControlsState(content::BrowserControlsState new_state,
325                                   bool animate);
326 #endif
327 
328   // content::WebContentsObserver:
329   void RenderProcessGone(base::TerminationStatus status) override;
330   void DidChangeVisibleSecurityState() override;
331 
332   // find_in_page::FindResultObserver:
333   void OnFindResultAvailable(content::WebContents* web_contents) override;
334 
335 #if defined(OS_ANDROID)
336   // BrowserControlsNavigationStateHandlerDelegate:
337   void OnBrowserControlsStateStateChanged(
338       ControlsVisibilityReason reason,
339       content::BrowserControlsState state) override;
340   void OnUpdateBrowserControlsStateBecauseOfProcessSwitch(
341       bool did_commit) override;
342 #endif
343 
344   // Called from closure supplied to delegate to exit fullscreen.
345   void OnExitFullscreen();
346 
347   void UpdateRendererPrefs(bool should_sync_prefs);
348 
349   void InitializeAutofill();
350 
351   // Returns the FindTabHelper for the page, or null if none exists.
352   find_in_page::FindTabHelper* GetFindTabHelper();
353 
354   static sessions::SessionTabHelperDelegate* GetSessionServiceTabHelperDelegate(
355       content::WebContents* web_contents);
356 
357 #if defined(OS_ANDROID)
358   void SetBrowserControlsConstraint(ControlsVisibilityReason reason,
359                                     content::BrowserControlsState constraint);
360 #endif
361 
362   void UpdateBrowserVisibleSecurityStateIfNecessary();
363 
364   bool SetDataInternal(const std::map<std::string, std::string>& data);
365 
366   BrowserImpl* browser_ = nullptr;
367   ErrorPageDelegate* error_page_delegate_ = nullptr;
368   FullscreenDelegate* fullscreen_delegate_ = nullptr;
369   NewTabDelegate* new_tab_delegate_ = nullptr;
370   GoogleAccountsDelegate* google_accounts_delegate_ = nullptr;
371   ProfileImpl* profile_;
372   std::unique_ptr<content::WebContents> web_contents_;
373   std::unique_ptr<NavigationControllerImpl> navigation_controller_;
374   base::ObserverList<TabObserver>::Unchecked observers_;
375   std::unique_ptr<i18n::LocaleChangeSubscription> locale_change_subscription_;
376 
377 #if defined(OS_ANDROID)
378   BrowserControlsContainerView* top_controls_container_view_ = nullptr;
379   BrowserControlsContainerView* bottom_controls_container_view_ = nullptr;
380   base::android::ScopedJavaGlobalRef<jobject> java_impl_;
381   std::unique_ptr<BrowserControlsNavigationStateHandler>
382       browser_controls_navigation_state_handler_;
383 
384   // Last value supplied to UpdateBrowserControlsConstraint(). This *constraint*
385   // can be SHOWN, if for example a modal dialog is forcing the controls to be
386   // visible, HIDDEN, if for example fullscreen is forcing the controls to be
387   // hidden, or BOTH, if either state is viable (e.g. during normal browsing).
388   // When BOTH, the actual current state could be showing or hidden.
389   content::BrowserControlsState
390       current_browser_controls_visibility_constraint_ =
391           content::BROWSER_CONTROLS_STATE_SHOWN;
392 
393   std::map<std::string, std::unique_ptr<WebMessageHostFactoryProxy>>
394       js_name_to_proxy_;
395 
396   bool desktop_user_agent_enabled_ = false;
397 #endif
398 
399   bool is_fullscreen_ = false;
400   // Set to true doing EnterFullscreenModeForTab().
401   bool processing_enter_fullscreen_ = false;
402 
403   std::unique_ptr<autofill::AutofillProvider> autofill_provider_;
404 
405   const std::string guid_;
406 
407   std::map<std::string, std::string> data_;
408   base::ObserverList<DataObserver>::Unchecked data_observers_;
409 
410   base::string16 title_;
411 
412   std::unique_ptr<js_injection::JsCommunicationHost> js_communication_host_;
413 
414   base::WeakPtrFactory<TabImpl> weak_ptr_factory_{this};
415 
416   DISALLOW_COPY_AND_ASSIGN(TabImpl);
417 };
418 
419 }  // namespace weblayer
420 
421 #endif  // WEBLAYER_BROWSER_TAB_IMPL_H_
422