// Copyright (c) 2006-2008 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 CHROME_BROWSER_RENDER_WIDGET_HOST_H_
#define CHROME_BROWSER_RENDER_WIDGET_HOST_H_

#include <windows.h>

#include "base/gfx/size.h"
#include "base/timer.h"
#include "chrome/common/ipc_channel.h"

namespace gfx {
class Rect;
}

class BackingStore;
class PaintObserver;
class RenderProcessHost;
class RenderWidgetHostView;
class WebInputEvent;
class WebKeyboardEvent;
class WebMouseEvent;
class WebMouseWheelEvent;
class WebCursor;
enum ViewHostMsg_ImeControl;
struct ViewHostMsg_PaintRect_Params;
struct ViewHostMsg_ScrollRect_Params;
struct WebPluginGeometry;

// This class manages the browser side of a browser<->renderer HWND connection.
// The HWND lives in the browser process, and windows events are sent over
// IPC to the corresponding object in the renderer.  The renderer paints into
// shared memory, which we transfer to a backing store and blit to the screen
// when Windows sends us a WM_PAINT message.
//
// How Shutdown Works
//
// There are two situations in which this object, a RenderWidgetHost, can be
// instantiated:
//
// 1. By a WebContents as the communication conduit for a rendered web page.
//    The WebContents instantiates a derived class: RenderViewHost.
// 2. By a WebContents as the communication conduit for a select widget. The
//    WebContents instantiates the RenderWidgetHost directly.
//
// For every WebContents there are several objects in play that need to be
// properly destroyed or cleaned up when certain events occur.
//
// - WebContents - the TabContents itself, and its associated HWND.
// - RenderViewHost - representing the communication conduit with the child
//   process.
// - RenderWidgetHostHWND - the view of the web page content, message handler,
//   and plugin root.
//
// Normally, the WebContents contains a child RenderWidgetHostHWND that renders
// the contents of the loaded page. It has a WS_CLIPCHILDREN style so that it
// does no painting of its own.
//
// The lifetime of the RenderWidgetHostHWND is tied to the render process. If
// the render process dies, the RenderWidgetHostHWND goes away and all
// references to it must become NULL. If the WebContents finds itself without a
// RenderWidgetHostHWND, it paints Sad Tab instead.
//
// RenderViewHost (a RenderWidgetHost subclass) is the conduit used to
// communicate with the RenderView and is owned by the WebContents. If the
// render process crashes, the RenderViewHost remains and restarts the render
// process if needed to continue navigation.
//
// The WebContents is itself owned by the NavigationController in which it
// resides.
//
// Some examples of how shutdown works:
//
// When a tab is closed (either by the user, the web page calling window.close,
// etc) the TabStrip destroys the associated NavigationController, which calls
// Destroy on each TabContents it owns.
//
// For a WebContents, its Destroy method tells the RenderViewHost to
// shut down the render process and die.
//
// When the render process is destroyed it destroys the View: the
// RenderWidgetHostHWND, which destroys its HWND and deletes that object.
//
// For select popups, the situation is a little different. The RenderWidgetHost
// associated with the select popup owns the view and itself (is responsible
// for destroying itself when the view is closed). The WebContents's only
// responsibility is to select popups is to create them when it is told to. When
// the View is destroyed via an IPC message (for when WebCore destroys the
// popup, e.g. if the user selects one of the options), or because
// WM_CANCELMODE is received by the view, the View schedules the destruction of
// the render process. However in this case since there's no WebContents
// container, when the render process is destroyed, the RenderWidgetHost just
// deletes itself, which is safe because no one else should have any references
// to it (the WebContents does not).
//
// It should be noted that the RenderViewHost, not the RenderWidgetHost,
// handles IPC messages relating to the render process going away, since the
// way a RenderViewHost (WebContents) handles the process dying is different to
// the way a select popup does. As such the RenderWidgetHostHWND handles these
// messages for select popups. This placement is more out of convenience than
// anything else. When the view is live, these messages are forwarded to it by
// the RenderWidgetHost's IPC message map.
//
class RenderWidgetHost : public IPC::Channel::Listener {
 public:
  // routing_id can be MSG_ROUTING_NONE, in which case the next available
  // routing id is taken from the RenderProcessHost.
  RenderWidgetHost(RenderProcessHost* process, int routing_id);
  virtual ~RenderWidgetHost();

  // Gets/Sets the View of this RenderWidgetHost. Can be NULL, e.g. if the
  // RenderWidget is being destroyed or the render process crashed. You should
  // never cache this pointer since it can become NULL if the renderer crashes,
  // instead you should always ask for it using the accessor.
  void set_view(RenderWidgetHostView* view) { view_ = view; }
  RenderWidgetHostView* view() const { return view_; }

  RenderProcessHost* process() const { return process_; }
  int routing_id() const { return routing_id_; }

  // Manual RTTI FTW. We are not hosting a web page.
  virtual bool IsRenderView() { return false; }

  // Called when a renderer object already been created for this host, and we
  // just need to be attached to it. Used for window.open, <select> dropdown
  // menus, and other times when the renderer initiates creating an object.
  virtual void Init();

  // IPC::Channel::Listener
  virtual void OnMessageReceived(const IPC::Message& msg);

  // Sends a message to the corresponding object in the renderer.
  bool Send(IPC::Message* msg);

  // Called to notify the RenderWidget that it has been hidden or restored from
  // having been hidden.
  void WasHidden();
  void WasRestored();

  // Called to notify the RenderWidget that it has been resized.
  void WasResized();

  // Tells the renderer to die and then calls Destroy().
  virtual void Shutdown();

  void Focus();
  void Blur();
  void LostCapture();

  // Notifies the RenderWidgetHost that the View was destroyed.
  void ViewDestroyed();

  // Indicates if the page has finished loading.
  virtual void SetIsLoading(bool is_loading);

  // Represents a device-dependent drawing surface used to hold the rendering
  // of a RenderWidgetHost.
  class BackingStore;

  // Manages a set of backing stores.
  class BackingStoreManager;

  // Get access to the widget's backing store.  If a resize is in progress,
  // then the current size of the backing store may be less than the size of
  // the widget's view.  This method returns NULL if the backing store could
  // not be created.
  BackingStore* GetBackingStore();

  // An interface that gets called when paints happen.
  // Used in performance tests.
  class PaintObserver;
  // Set the PaintObserver on this object.  Takes ownership.
  void SetPaintObserver(PaintObserver* paint_observer) {
    paint_observer_.reset(paint_observer);
  }

  // Checks to see if we can give  up focus to this  widget through a
  // javascript call.
  virtual bool CanBlur() const { return true; }

  // Restart the active hang monitor timeout. Clears all existing timeouts and
  // starts with a new one.  This can be because the renderer has become
  // active, the tab is being hidden, or the user has chosen to wait some more
  // to give the tab a chance to become active and we don't want to display a
  // warning too soon.
  void RestartHangMonitorTimeout();
  
  // Stops all existing hang monitor timeouts and assumes the renderer is
  // responsive.
  void StopHangMonitorTimeout();

  // Starts a hang monitor timeout. If there's already a hang monitor timeout
  // the new one will only fire if it has a shorter delay than the time
  // left on the existing timeouts.
  void StartHangMonitorTimeout(TimeDelta delay);

  // Called when we receive a notification indicating that the renderer
  // process has gone.
  void RendererExited();

  // Called when the system theme changes. At this time all existing native
  // theme handles are invalid and the renderer must obtain new ones and
  // repaint.
  void SystemThemeChanged();

 protected:
  // Called when we an InputEvent was not processed by the renderer.
  virtual void UnhandledInputEvent(const WebInputEvent& event) { }

  // IPC message handlers
  void OnMsgRendererReady();
  void OnMsgRendererGone();
  void OnMsgClose();
  void OnMsgRequestMove(const gfx::Rect& pos);
  void OnMsgResizeAck();
  void OnMsgPaintRect(const ViewHostMsg_PaintRect_Params& params);
  void OnMsgScrollRect(const ViewHostMsg_ScrollRect_Params& params);
  void OnMsgInputEventAck(const IPC::Message& message);
  void OnMsgFocus();
  void OnMsgBlur();
  void OnMsgSetCursor(const WebCursor& cursor);
  void OnMsgImeUpdateStatus(ViewHostMsg_ImeControl control, int x, int y);

  void MovePluginWindows(
      const std::vector<WebPluginGeometry>& plugin_window_moves);

  // TODO(beng): (Cleanup) remove this friendship once we expose a clean API to
  // RenderWidgetHost Views. This exists only to give RenderWidgetHostHWND
  // access to Forward*Event.
  friend class RenderWidgetHostHWND;

  void ForwardMouseEvent(const WebMouseEvent& mouse_event);
  void ForwardKeyboardEvent(const WebKeyboardEvent& key_event);
  void ForwardWheelEvent(const WebMouseWheelEvent& wheel_event);
  void ForwardInputEvent(const WebInputEvent& input_event, int event_size);

  // Called to paint a region of the backing store
  void PaintRect(HANDLE bitmap, const gfx::Rect& bitmap_rect,
                 const gfx::Size& view_size);

  // Called to scroll a region of the backing store
  void ScrollRect(HANDLE bitmap, const gfx::Rect& bitmap_rect, int dx, int dy,
                  const gfx::Rect& clip_rect, const gfx::Size& view_size);

  // Tell this object to destroy itself.
  void Destroy();

  // Callbacks for notification when the renderer becomes unresponsive to user
  // input events, and subsequently responsive again. The delegate can use
  // these notifications to show a warning.
  void CheckRendererIsUnresponsive();
  virtual void NotifyRendererUnresponsive() {}
  void RendererIsResponsive();
  virtual void NotifyRendererResponsive() {}

  // Created during construction but initialized during Init*(). Therefore, it
  // is guaranteed never to be NULL, but its channel may be NULL if the
  // renderer crashed, so you must always check that.
  RenderProcessHost* process_;

  // The ID of the corresponding object in the Renderer Instance.
  int routing_id_;

  bool resize_ack_pending_;  // True when waiting for RESIZE_ACK.
  gfx::Size current_size_;   // The current size of the RenderWidget.

  // True if a mouse move event was sent to the render view and we are waiting
  // for a corresponding ViewHostMsg_HandleInputEvent_ACK message.
  bool mouse_move_pending_;

  // The next mouse move event to send (only non-null while mouse_move_pending_
  // is true).
  scoped_ptr<WebMouseEvent> next_mouse_move_;

  // The View associated with the RenderViewHost. The lifetime of this object
  // is associated with the lifetime of the Render process. If the Renderer
  // crashes, its View is destroyed and this pointer becomes NULL, even though
  // render_view_host_ lives on to load another URL (creating a new View while
  // doing so).
  RenderWidgetHostView* view_;

  // The time when an input event was sent to the RenderWidget.
  TimeTicks input_event_start_time_;

  // Indicates whether a page is loading or not.
  bool is_loading_;
  // Indicates whether a page is hidden or not.
  bool is_hidden_;
  // If true, then we should not ask our view to repaint when our backingstore
  // is updated.
  bool suppress_view_updating_;

  // If true, then we should repaint when restoring even if we have a
  // backingstore.  This flag is set to true if we receive a paint message
  // while is_hidden_ to true.  Even though we tell the render widget to hide
  // itself, a paint message could already be in flight at that point.
  bool needs_repainting_on_restore_;

  // The following value indicates a time in the future when we would consider
  // the renderer hung if it does not generate an appropriate response message.
  Time time_when_considered_hung_;

  // This timer runs to check if time_when_considered_hung_ has past.
  base::OneShotTimer<RenderWidgetHost> hung_renderer_timer_;

  // This is true if the renderer is currently unresponsive.
  bool is_unresponsive_;

  // Optional observer that listens for notifications of painting.
  scoped_ptr<PaintObserver> paint_observer_;

  // Set when we call DidPaintRect/DidScrollRect on the view.
  bool view_being_painted_;

  // Set if we are waiting for a repaint ack for the view.
  bool repaint_ack_pending_;

  // Used for UMA histogram logging to measure the time for a repaint view
  // operation to finish.
  TimeTicks repaint_start_time_;

  DISALLOW_EVIL_CONSTRUCTORS(RenderWidgetHost);
};

class RenderWidgetHost::BackingStore {
 public:
  BackingStore(const gfx::Size& size);
  ~BackingStore();

  HDC dc() { return hdc_; }
  const gfx::Size& size() { return size_; }

  // Paints the bitmap from the renderer onto the backing store.
  bool Refresh(HANDLE process, HANDLE bitmap_section,
               const gfx::Rect& bitmap_rect);

 private:
  // Creates a dib conforming to the height/width/section parameters passed
  // in. The use_os_color_depth parameter controls whether we use the color
  // depth to create an appropriate dib or not.
  HANDLE CreateDIB(HDC dc, int width, int height, bool use_os_color_depth, 
                   HANDLE section);

  // The backing store dc.
  HDC hdc_;
  // The size of the backing store.
  gfx::Size size_;
  // Handle to the backing store dib.
  HANDLE backing_store_dib_;
  // Handle to the original bitmap in the dc.
  HANDLE original_bitmap_;

  DISALLOW_EVIL_CONSTRUCTORS(BackingStore);
};

class RenderWidgetHost::PaintObserver {
 public:
  virtual ~PaintObserver() {}

  // Called each time the RenderWidgetHost paints.
  virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh) = 0;
};

#endif  // #ifndef CHROME_BROWSER_RENDER_WIDGET_HOST_H_