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 CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
6 #define CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
7 
8 #include <deque>
9 #include <memory>
10 #include <set>
11 #include <string>
12 
13 #include "chromecast/browser/webview/js_channel_service.h"
14 #include "chromecast/browser/webview/proto/webview.pb.h"
15 #include "components/exo/surface.h"
16 #include "components/exo/surface_observer.h"
17 #include "content/public/browser/render_widget_host.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "ui/base/ime/input_method.h"
20 #include "ui/base/ime/input_method_observer.h"
21 #include "ui/events/gestures/gesture_recognizer_impl.h"
22 
23 namespace aura {
24 class Window;
25 }  // namespace aura
26 
27 namespace content {
28 class RenderFrameHost;
29 }  // namespace content
30 
31 namespace chromecast {
32 
33 class WebContentJsChannels;
34 
35 // Processes proto commands to control WebContents
36 class WebContentController
37     : public exo::SurfaceObserver,
38       public content::WebContentsObserver,
39       public content::RenderWidgetHost::InputEventObserver,
40       public JsClientInstance::Observer {
41  public:
42   class Client {
43    public:
~Client()44     virtual ~Client() {}
45     virtual void EnqueueSend(
46         std::unique_ptr<webview::WebviewResponse> response) = 0;
47     virtual void OnError(const std::string& error_message) = 0;
48   };
49   // Touch event information recorded so that acks can be sent in the same
50   // order. Stripped down from the normal event flow's TouchEventAckQueue.
51   struct TouchData {
52     uint32_t id;
53     content::RenderWidgetHostView* rwhv;
54     bool acked;
55     ui::EventResult result;
56   };
57 
58   explicit WebContentController(Client* client);
59   ~WebContentController() override;
60 
61   virtual void Destroy() = 0;
62 
63   virtual void ProcessRequest(const webview::WebviewRequest& request);
64 
65   // Attach this web contents to an aura window as a child.
66   void AttachTo(aura::Window* window, int window_id);
67 
68   // Invoked when the aura window becomes visible and is fully initialized.
69   void OnVisible(aura::Window* window);
70 
client()71   Client* client() const { return client_; }
72 
73  protected:
74   // content::WebContentsObserver
75   void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
76   void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
77   void RenderFrameHostChanged(content::RenderFrameHost* old_host,
78                               content::RenderFrameHost* new_host) override;
79   void MainFrameWasResized(bool width_changed) override;
80   void FrameSizeChanged(content::RenderFrameHost* render_frame_host,
81                         const gfx::Size& frame_size) override;
82   void RenderViewCreated(content::RenderViewHost* render_view_host) override;
83   void RenderViewDeleted(content::RenderViewHost* render_view_host) override;
84 
85   static void RegisterRenderWidgetInputObserverFromRenderFrameHost(
86       WebContentController* web_content_controller,
87       content::RenderFrameHost* render_frame_host);
88 
89   // Subclasses are expected to add/remove this as a WebContentsObserver on
90   // whatever WebContents this manages.
91   virtual content::WebContents* GetWebContents() = 0;
92   Client* client_;  // Not owned.
93   bool has_navigation_delegate_ = false;
94   std::unique_ptr<WebContentJsChannels> js_channels_;
95 
96  private:
97   void ProcessInputEvent(const webview::InputEvent& ev);
98   void RegisterRenderWidgetInputObserver(
99       content::RenderWidgetHost* render_widget_host);
100   void UnregisterRenderWidgetInputObserver(
101       content::RenderWidgetHost* render_widget_host);
102   void AckTouchEvent(content::RenderWidgetHostView* rhwv,
103                      uint32_t unique_event_id,
104                      ui::EventResult result);
105   void JavascriptCallback(int64_t id, base::Value result);
106   void HandleEvaluateJavascript(
107       int64_t id,
108       const webview::EvaluateJavascriptRequest& request);
109   void HandleAddJavascriptChannels(
110       const webview::AddJavascriptChannelsRequest& request);
111   void HandleRemoveJavascriptChannels(
112       const webview::RemoveJavascriptChannelsRequest& request);
113   void HandleGetCurrentUrl(int64_t id);
114   void HandleCanGoBack(int64_t id);
115   void HandleCanGoForward(int64_t id);
116   void HandleClearCache();
117   void HandleClearCookies(int64_t id);
118   void HandleGetTitle(int64_t id);
119   void HandleResize(const gfx::Size& size);
120   viz::SurfaceId GetSurfaceId();
121   void ChannelModified(content::RenderFrameHost* frame,
122                        const std::string& channel,
123                        bool added);
124   JsChannelCallback GetJsChannelCallback();
125   void SendInitialChannelSet(JsClientInstance* instance);
126 
127   // exo::SurfaceObserver
128   void OnSurfaceDestroying(exo::Surface* surface) override;
129 
130   // JsClientInstance::Observer
131   void OnJsClientInstanceRegistered(int process_id,
132                                     int routing_id,
133                                     JsClientInstance* instance) override;
134 
135   // content::RenderWidgetHost::InputEventObserver
136   void OnInputEventAck(blink::mojom::InputEventResultSource source,
137                        blink::mojom::InputEventResultState state,
138                        const blink::WebInputEvent&) override;
139 
140   ui::GestureRecognizerImpl gesture_recognizer_;
141   std::deque<TouchData> touch_queue_;
142 
143   exo::Surface* surface_ = nullptr;
144 
145   std::set<std::string> current_javascript_channel_set_;
146   std::set<content::RenderFrameHost*> current_render_frame_set_;
147   std::set<content::RenderWidgetHost*> current_render_widget_set_;
148 
149   // Observes the aura window and calls back to the controller for visibility
150   // events.
151   class WebviewWindowVisibilityObserver : public aura::WindowObserver {
152    public:
153     explicit WebviewWindowVisibilityObserver(aura::Window* window,
154                                              WebContentController* controller);
155     ~WebviewWindowVisibilityObserver() override;
156 
157     WebviewWindowVisibilityObserver(const WebviewWindowVisibilityObserver&) =
158         delete;
159     WebviewWindowVisibilityObserver& operator=(
160         const WebviewWindowVisibilityObserver&) = delete;
161 
162    private:
163     // aura::WindowObserver
164     void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
165     void OnWindowDestroyed(aura::Window* window) override;
166 
167     aura::Window* window_;
168     WebContentController* controller_;
169   };
170 
171   std::unique_ptr<WebviewWindowVisibilityObserver> window_visibility_observer_;
172   std::unique_ptr<ui::InputMethodObserver> input_method_observer_;
173 
174   base::WeakPtrFactory<WebContentController> weak_ptr_factory_{this};
175 
176   DISALLOW_COPY_AND_ASSIGN(WebContentController);
177 };
178 
179 class WebContentJsChannels
180     : public base::SupportsWeakPtr<WebContentJsChannels> {
181  public:
182   explicit WebContentJsChannels(WebContentController::Client* client);
183   ~WebContentJsChannels();
184 
185   void SendMessage(const std::string& channel, const std::string& message);
186 
187  private:
188   WebContentController::Client* client_;
189 
190   DISALLOW_COPY_AND_ASSIGN(WebContentJsChannels);
191 };
192 
193 }  // namespace chromecast
194 
195 #endif  // CHROMECAST_BROWSER_WEBVIEW_WEB_CONTENT_CONTROLLER_H_
196