blob: ffa3a63a230445ee4569a94d0912815fa5781cdb [file] [log] [blame]
// 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 HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_
#define HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include "base/observer_list.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "content/public/browser/devtools_agent_host_observer.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "headless/lib/browser/headless_window_tree_host.h"
#include "headless/public/headless_devtools_target.h"
#include "headless/public/headless_export.h"
#include "headless/public/headless_web_contents.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/compositor/external_begin_frame_client.h"
class SkBitmap;
namespace content {
class DevToolsAgentHost;
class DevToolsAgentHostClient;
class WebContents;
}
namespace gfx {
class Rect;
}
namespace headless {
class HeadlessBrowser;
class HeadlessBrowserImpl;
class HeadlessTabSocketImpl;
// Exported for tests.
class HEADLESS_EXPORT HeadlessWebContentsImpl
: public HeadlessWebContents,
public HeadlessDevToolsTarget,
public content::DevToolsAgentHostObserver,
public content::RenderProcessHostObserver,
public content::WebContentsObserver,
public ui::ExternalBeginFrameClient {
public:
~HeadlessWebContentsImpl() override;
static HeadlessWebContentsImpl* From(HeadlessWebContents* web_contents);
static HeadlessWebContentsImpl* From(HeadlessBrowser* browser,
content::WebContents* contents);
static std::unique_ptr<HeadlessWebContentsImpl> Create(
HeadlessWebContents::Builder* builder);
// Takes ownership of |child_contents|.
static std::unique_ptr<HeadlessWebContentsImpl> CreateForChildContents(
HeadlessWebContentsImpl* parent,
content::WebContents* child_contents);
// HeadlessWebContents implementation:
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
HeadlessDevToolsTarget* GetDevToolsTarget() override;
HeadlessTabSocket* GetHeadlessTabSocket() const override;
int GetMainFrameRenderProcessId() const override;
int GetMainFrameTreeNodeId() const override;
std::string GetMainFrameDevToolsId() const override;
// HeadlessDevToolsTarget implementation:
bool AttachClient(HeadlessDevToolsClient* client) override;
void ForceAttachClient(HeadlessDevToolsClient* client) override;
void DetachClient(HeadlessDevToolsClient* client) override;
bool IsAttached() override;
// content::DevToolsAgentHostObserver implementation:
void DevToolsAgentHostAttached(
content::DevToolsAgentHost* agent_host) override;
void DevToolsAgentHostDetached(
content::DevToolsAgentHost* agent_host) override;
// content::RenderProcessHostObserver implementation:
void RenderProcessExited(content::RenderProcessHost* host,
base::TerminationStatus status,
int exit_code) override;
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
// content::WebContentsObserver implementation:
void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void RenderViewReady() override;
void OnInterfaceRequestFromFrame(
content::RenderFrameHost* render_frame_host,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle* interface_pipe) override;
// ui::ExternalBeginFrameClient implementation:
void OnDisplayDidFinishFrame(const viz::BeginFrameAck& ack) override;
void OnNeedsExternalBeginFrames(bool needs_begin_frames) override;
content::WebContents* web_contents() const;
bool OpenURL(const GURL& url);
void Close() override;
std::string GetDevToolsAgentHostId();
HeadlessBrowserImpl* browser() const;
HeadlessBrowserContextImpl* browser_context() const;
void set_window_tree_host(std::unique_ptr<HeadlessWindowTreeHost> host) {
window_tree_host_ = std::move(host);
}
HeadlessWindowTreeHost* window_tree_host() const {
return window_tree_host_.get();
}
int window_id() const { return window_id_; }
void set_window_state(const std::string& state) {
DCHECK(state == "normal" || state == "minimized" || state == "maximized" ||
state == "fullscreen");
window_state_ = state;
}
const std::string& window_state() const { return window_state_; }
// Set bounds of WebContent's platform window.
void SetBounds(const gfx::Rect& bounds);
void CreateTabSocketMojoService(mojo::ScopedMessagePipeHandle handle);
bool begin_frame_control_enabled() const {
return begin_frame_control_enabled_;
}
bool needs_external_begin_frames() const {
return needs_external_begin_frames_;
}
void SetBeginFrameEventsEnabled(content::DevToolsAgentHostClient* client,
bool enabled);
using FrameFinishedCallback =
base::OnceCallback<void(bool /* has_damage */,
std::unique_ptr<SkBitmap>)>;
void BeginFrame(const base::TimeTicks& frame_timeticks,
const base::TimeTicks& deadline,
const base::TimeDelta& interval,
bool animate_only,
bool capture_screenshot,
FrameFinishedCallback frame_finished_callback);
bool HasPendingFrame() const { return !pending_frames_.empty(); }
private:
struct PendingFrame;
// Takes ownership of |web_contents|.
HeadlessWebContentsImpl(content::WebContents* web_contents,
HeadlessBrowserContextImpl* browser_context);
void InitializeWindow(const gfx::Rect& initial_bounds);
using MojoService = HeadlessWebContents::Builder::MojoService;
void CreateMojoService(
const MojoService::ServiceFactoryCallback& service_factory,
mojo::ScopedMessagePipeHandle handle);
void SendNeedsBeginFramesEvent(content::DevToolsAgentHostClient* client);
void PendingFrameReadbackComplete(PendingFrame* pending_frame,
const SkBitmap& bitmap);
uint64_t begin_frame_source_id_ = viz::BeginFrameArgs::kManualSourceId;
uint64_t begin_frame_sequence_number_ =
viz::BeginFrameArgs::kStartingFrameNumber;
bool begin_frame_control_enabled_ = false;
std::list<content::DevToolsAgentHostClient*>
begin_frame_events_enabled_clients_;
bool needs_external_begin_frames_ = false;
std::list<std::unique_ptr<PendingFrame>> pending_frames_;
class Delegate;
std::unique_ptr<Delegate> web_contents_delegate_;
std::unique_ptr<HeadlessWindowTreeHost> window_tree_host_;
int window_id_ = 0;
std::string window_state_;
std::unique_ptr<HeadlessTabSocketImpl> headless_tab_socket_;
std::unique_ptr<content::WebContents> web_contents_;
scoped_refptr<content::DevToolsAgentHost> agent_host_;
std::list<MojoService> mojo_services_;
bool inject_mojo_services_into_isolated_world_;
bool devtools_target_ready_notification_sent_ = false;
HeadlessBrowserContextImpl* browser_context_; // Not owned.
// TODO(alexclarke): With OOPIF there may be more than one renderer, we need
// to fix this. See crbug.com/715924
content::RenderProcessHost* render_process_host_; // Not owned.
base::ObserverList<HeadlessWebContents::Observer> observers_;
service_manager::BinderRegistry registry_;
base::WeakPtrFactory<HeadlessWebContentsImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(HeadlessWebContentsImpl);
};
} // namespace headless
#endif // HEADLESS_LIB_BROWSER_HEADLESS_WEB_CONTENTS_IMPL_H_