|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef COMPONENTS_WEB_VIEW_FRAME_H_ | 
|  | #define COMPONENTS_WEB_VIEW_FRAME_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <map> | 
|  | #include <vector> | 
|  |  | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/time/time.h" | 
|  | #include "components/mus/common/types.h" | 
|  | #include "components/mus/public/cpp/window_observer.h" | 
|  | #include "components/web_view/public/interfaces/frame.mojom.h" | 
|  | #include "mojo/public/cpp/bindings/binding.h" | 
|  |  | 
|  | class GURL; | 
|  |  | 
|  | namespace web_view { | 
|  |  | 
|  | class FrameTest; | 
|  | class FrameTree; | 
|  | class FrameUserData; | 
|  |  | 
|  | namespace mojom { | 
|  | class FrameClient; | 
|  | } | 
|  |  | 
|  | enum class WindowOwnership { | 
|  | OWNS_WINDOW, | 
|  | DOESNT_OWN_WINDOW, | 
|  | }; | 
|  |  | 
|  | // Frame represents an embedding in a frame. Frames own their children. | 
|  | // Frames automatically delete themself if the Window the frame is associated | 
|  | // with is deleted. | 
|  | // | 
|  | // In general each Frame has a Window. When a new Frame is created by a client | 
|  | // there may be a small amount of time where the Window is not yet known | 
|  | // (separate pipes are used for the window and frame, resulting in undefined | 
|  | // message ordering). In this case the window is null and will be set once we | 
|  | // see the window (OnTreeChanged()). | 
|  | // | 
|  | // Each frame has an identifier of the app providing the FrameClient | 
|  | // (|app_id|). This id is used when servicing a request to navigate the frame. | 
|  | // When navigating, if the id of the new app matches that of the existing app, | 
|  | // then it is expected that the new FrameClient will take over rendering to the | 
|  | // existing window. Because of this a new WindowTreeClient is not obtained and | 
|  | // Embed() is not invoked on the Window. The FrameClient can detect this case by | 
|  | // the argument |reuse_existing_view| supplied to OnConnect(). Typically the id | 
|  | // is that of content handler id, but this is left up to the FrameTreeDelegate | 
|  | // to decide. | 
|  | class Frame : public mus::WindowObserver, public mojom::Frame { | 
|  | public: | 
|  | using ClientPropertyMap = std::map<std::string, std::vector<uint8_t>>; | 
|  | using FindCallback = mojo::Callback<void(bool)>; | 
|  |  | 
|  | Frame(FrameTree* tree, | 
|  | mus::Window* window, | 
|  | uint32_t frame_id, | 
|  | uint32_t app_id, | 
|  | WindowOwnership window_ownership, | 
|  | mojom::FrameClient* frame_client, | 
|  | scoped_ptr<FrameUserData> user_data, | 
|  | const ClientPropertyMap& client_properties); | 
|  | ~Frame() override; | 
|  |  | 
|  | void Init(Frame* parent, | 
|  | mus::mojom::WindowTreeClientPtr window_tree_client, | 
|  | mojo::InterfaceRequest<mojom::Frame> frame_request, | 
|  | base::TimeTicks navigation_start_time); | 
|  |  | 
|  | // Walks the Window tree starting at |window| going up returning the first | 
|  | // Frame that is associated with |window|. For example, if |window| | 
|  | // has a Frame associated with it, then that is returned. Otherwise | 
|  | // this checks window->parent() and so on. | 
|  | static Frame* FindFirstFrameAncestor(mus::Window* window); | 
|  |  | 
|  | FrameTree* tree() { return tree_; } | 
|  |  | 
|  | Frame* parent() { return parent_; } | 
|  | const Frame* parent() const { return parent_; } | 
|  |  | 
|  | mus::Window* window() { return window_; } | 
|  | const mus::Window* window() const { return window_; } | 
|  |  | 
|  | uint32_t id() const { return id_; } | 
|  |  | 
|  | uint32_t app_id() const { return app_id_; } | 
|  |  | 
|  | bool loading() const { return loading_; } | 
|  |  | 
|  | const ClientPropertyMap& client_properties() const { | 
|  | return client_properties_; | 
|  | } | 
|  |  | 
|  | // Finds the descendant with the specified id. | 
|  | Frame* FindFrame(uint32_t id) { | 
|  | return const_cast<Frame*>(const_cast<const Frame*>(this)->FindFrame(id)); | 
|  | } | 
|  | const Frame* FindFrame(uint32_t id) const; | 
|  |  | 
|  | bool HasAncestor(const Frame* frame) const; | 
|  |  | 
|  | FrameUserData* user_data() { return user_data_.get(); } | 
|  |  | 
|  | const std::vector<Frame*>& children() const { return children_; } | 
|  |  | 
|  | // Returns true if this Frame or any child Frame is loading. | 
|  | bool IsLoading() const; | 
|  |  | 
|  | // Returns the sum total of loading progress from this Frame and all of its | 
|  | // children, as well as the number of Frames accumulated. | 
|  | double GatherProgress(int* frame_count) const; | 
|  |  | 
|  | void Find(int32_t request_id, | 
|  | const mojo::String& search_text, | 
|  | mojom::FindOptionsPtr options, | 
|  | bool wrap_within_frame, | 
|  | const FindCallback& callback); | 
|  | void StopFinding(bool clear_selection); | 
|  | void HighlightFindResults(int32_t request_id, | 
|  | const mojo::String& search_text, | 
|  | mojom::FindOptionsPtr options, | 
|  | bool reset); | 
|  | void StopHighlightingFindResults(); | 
|  |  | 
|  | private: | 
|  | friend class FrameTest; | 
|  | friend class FrameTree; | 
|  |  | 
|  | // Identifies whether the FrameClient is from the same app or a different | 
|  | // app. | 
|  | enum class ClientType { | 
|  | // The client is either the root frame, or navigating an existing frame | 
|  | // to a different app. | 
|  | EXISTING_FRAME_NEW_APP, | 
|  |  | 
|  | // The client is the result of navigating an existing frame in the same | 
|  | // app. | 
|  | EXISTING_FRAME_SAME_APP, | 
|  |  | 
|  | // The client is the result of a new frame (not the root). | 
|  | NEW_CHILD_FRAME | 
|  | }; | 
|  |  | 
|  | struct FrameUserDataAndBinding; | 
|  |  | 
|  | // Initializes the client by sending it the state of the tree. | 
|  | // |data_and_binding| contains the current FrameUserDataAndBinding (if any) | 
|  | // and is destroyed after the connection responds to OnConnect(). | 
|  | // | 
|  | // If |client_type| is SAME_APP we can't destroy the existing client | 
|  | // (and related data) until we get back the ack from OnConnect(). This way | 
|  | // we know the client has completed the switch. If we did not do this it | 
|  | // would be possible for the app to see it's existing Frame connection lost | 
|  | // (and assume the frame is being torn down) before the OnConnect(). | 
|  | void InitClient(ClientType client_type, | 
|  | scoped_ptr<FrameUserDataAndBinding> data_and_binding, | 
|  | mus::mojom::WindowTreeClientPtr window_tree_client, | 
|  | mojo::InterfaceRequest<mojom::Frame> frame_request, | 
|  | base::TimeTicks navigation_start_time); | 
|  |  | 
|  | // Callback from OnConnect(). This does nothing (other than destroying | 
|  | // |data_and_binding|). See InitClient() for details as to why destruction of | 
|  | // |data_and_binding| happens after OnConnect(). | 
|  | static void OnConnectAck( | 
|  | scoped_ptr<FrameUserDataAndBinding> data_and_binding); | 
|  |  | 
|  | // Callback from OnEmbed(). | 
|  | void OnEmbedAck(bool success, mus::ConnectionSpecificId connection_id); | 
|  |  | 
|  | // Callback from Frame::OnWillNavigate(). Completes navigation. | 
|  | void OnWillNavigateAck(mojom::FrameClient* frame_client, | 
|  | scoped_ptr<FrameUserData> user_data, | 
|  | mus::mojom::WindowTreeClientPtr window_tree_client, | 
|  | uint32_t app_id, | 
|  | base::TimeTicks navigation_start_time); | 
|  |  | 
|  | // Completes a navigation request; swapping the existing FrameClient to the | 
|  | // supplied arguments. | 
|  | void ChangeClient(mojom::FrameClient* frame_client, | 
|  | scoped_ptr<FrameUserData> user_data, | 
|  | mus::mojom::WindowTreeClientPtr window_tree_client, | 
|  | uint32_t app_id, | 
|  | base::TimeTicks navigation_start_time); | 
|  |  | 
|  | void SetWindow(mus::Window* window); | 
|  |  | 
|  | // Adds this to |frames| and recurses through the children calling the | 
|  | // same function. | 
|  | void BuildFrameTree(std::vector<const Frame*>* frames) const; | 
|  |  | 
|  | void Add(Frame* node); | 
|  | void Remove(Frame* node); | 
|  |  | 
|  | // Starts a new navigation to |request|. The navigation proceeds as long | 
|  | // as there is a Window and once OnWillNavigate() has returned. If there is | 
|  | // no Window the navigation waits until the Window is available. | 
|  | void StartNavigate(mojo::URLRequestPtr request); | 
|  | void OnCanNavigateFrame(const GURL& url, | 
|  | base::TimeTicks navigation_start_time, | 
|  | uint32_t app_id, | 
|  | mojom::FrameClient* frame_client, | 
|  | scoped_ptr<FrameUserData> user_data, | 
|  | mus::mojom::WindowTreeClientPtr window_tree_client); | 
|  |  | 
|  | // Notifies the client and all descendants as appropriate. | 
|  | void NotifyAdded(const Frame* source, | 
|  | const Frame* added_node, | 
|  | uint32_t change_id); | 
|  | void NotifyRemoved(const Frame* source, | 
|  | const Frame* removed_node, | 
|  | uint32_t change_id); | 
|  | void NotifyClientPropertyChanged(const Frame* source, | 
|  | const mojo::String& name, | 
|  | const mojo::Array<uint8_t>& value); | 
|  | void NotifyFrameLoadingStateChanged(const Frame* frame, bool loading); | 
|  | void NotifyDispatchFrameLoadEvent(const Frame* frame); | 
|  |  | 
|  | // mus::WindowObserver: | 
|  | void OnTreeChanged(const TreeChangeParams& params) override; | 
|  | void OnWindowDestroying(mus::Window* window) override; | 
|  | void OnWindowEmbeddedAppDisconnected(mus::Window* window) override; | 
|  |  | 
|  | // mojom::Frame: | 
|  | void PostMessageEventToFrame(uint32_t target_frame_id, | 
|  | mojom::HTMLMessageEventPtr event) override; | 
|  | void LoadingStateChanged(bool loading, double progress) override; | 
|  | void TitleChanged(const mojo::String& title) override; | 
|  | void DidCommitProvisionalLoad() override; | 
|  | void SetClientProperty(const mojo::String& name, | 
|  | mojo::Array<uint8_t> value) override; | 
|  | void OnCreatedFrame( | 
|  | mojo::InterfaceRequest<mojom::Frame> frame_request, | 
|  | mojom::FrameClientPtr client, | 
|  | uint32_t frame_id, | 
|  | mojo::Map<mojo::String, mojo::Array<uint8_t>> client_properties) override; | 
|  | void RequestNavigate(mojom::NavigationTargetType target_type, | 
|  | uint32_t target_frame_id, | 
|  | mojo::URLRequestPtr request) override; | 
|  | void DidNavigateLocally(const mojo::String& url) override; | 
|  | void DispatchLoadEventToParent() override; | 
|  | void OnFindInFrameCountUpdated(int32_t request_id, | 
|  | int32_t count, | 
|  | bool final_update) override; | 
|  | void OnFindInPageSelectionUpdated(int32_t request_id, | 
|  | int32_t active_match_ordinal) override; | 
|  |  | 
|  | FrameTree* const tree_; | 
|  | // WARNING: this may be null. See class description for details. | 
|  | mus::Window* window_; | 
|  | // The connection id returned from WindowManager::Embed(). Frames created by | 
|  | // way of OnCreatedFrame() inherit the id from the parent. | 
|  | mus::ConnectionSpecificId embedded_connection_id_; | 
|  | // ID for the frame, which is the same as that of the window. | 
|  | const uint32_t id_; | 
|  | // ID of the app providing the FrameClient and WindowTreeClient. | 
|  | uint32_t app_id_; | 
|  | Frame* parent_; | 
|  | WindowOwnership window_ownership_; | 
|  | std::vector<Frame*> children_; | 
|  | scoped_ptr<FrameUserData> user_data_; | 
|  |  | 
|  | mojom::FrameClient* frame_client_; | 
|  |  | 
|  | bool loading_; | 
|  | double progress_; | 
|  |  | 
|  | ClientPropertyMap client_properties_; | 
|  |  | 
|  | // StartNavigate() stores the request here if the window isn't available at | 
|  | // the time of StartNavigate(). | 
|  | mojo::URLRequestPtr pending_navigate_; | 
|  |  | 
|  | scoped_ptr<mojo::Binding<mojom::Frame>> frame_binding_; | 
|  |  | 
|  | // True if waiting on callback from FrameClient::OnWillNavigate(). | 
|  | bool waiting_for_on_will_navigate_ack_; | 
|  |  | 
|  | base::WeakPtrFactory<Frame> embed_weak_ptr_factory_; | 
|  |  | 
|  | base::WeakPtrFactory<Frame> navigate_weak_ptr_factory_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(Frame); | 
|  | }; | 
|  |  | 
|  | }  // namespace web_view | 
|  |  | 
|  | #endif  // COMPONENTS_WEB_VIEW_FRAME_H_ |