// Copyright (c) 2010 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_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_H_
#define CHROME_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_H_

#include "build/build_config.h"

#include <map>
#include <queue>
#include <string>

#include "base/process.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/string16.h"
#include "base/timer.h"
#include "chrome/common/transport_dib.h"
#include "chrome/browser/child_process_launcher.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/notification_registrar.h"
#include "third_party/WebKit/WebKit/chromium/public/WebCache.h"

class AudioRendererHost;
class CommandLine;
class GURL;
class RendererMainThread;
class RenderWidgetHelper;
class TabContents;
class VisitedLinkUpdater;
class URLRequestContextGetter;

namespace gfx {
class Size;
}

// Implements a concrete RenderProcessHost for the browser process for talking
// to actual renderer processes (as opposed to mocks).
//
// Represents the browser side of the browser <--> renderer communication
// channel. There will be one RenderProcessHost per renderer process.
//
// This object is refcounted so that it can release its resources when all
// hosts using it go away.
//
// This object communicates back and forth with the RenderProcess object
// running in the renderer process. Each RenderProcessHost and RenderProcess
// keeps a list of RenderView (renderer) and TabContents (browser) which
// are correlated with IDs. This way, the Views and the corresponding ViewHosts
// communicate through the two process objects.
class BrowserRenderProcessHost : public RenderProcessHost,
                                 public NotificationObserver,
                                 public ChildProcessLauncher::Client {
 public:
  explicit BrowserRenderProcessHost(Profile* profile);
  ~BrowserRenderProcessHost();

  // RenderProcessHost implementation (public portion).
  virtual bool Init(bool is_extensions_process,
                    URLRequestContextGetter* request_context);
  virtual int GetNextRoutingID();
  virtual void CancelResourceRequests(int render_widget_id);
  virtual void CrossSiteClosePageACK(const ViewMsg_ClosePage_Params& params);
  virtual bool WaitForUpdateMsg(int render_widget_id,
                                const base::TimeDelta& max_delay,
                                IPC::Message* msg);
  virtual void ReceivedBadMessage(uint32 msg_type);
  virtual void WidgetRestored();
  virtual void WidgetHidden();
  virtual void ViewCreated();
  virtual void SendVisitedLinkTable(base::SharedMemory* table_memory);
  virtual void AddVisitedLinks(const VisitedLinkCommon::Fingerprints& links);
  virtual void ResetVisitedLinks();
  virtual bool FastShutdownIfPossible();
  virtual bool SendWithTimeout(IPC::Message* msg, int timeout_ms);
  virtual base::ProcessHandle GetHandle();
  virtual TransportDIB* GetTransportDIB(TransportDIB::Id dib_id);

  // IPC::Channel::Sender via RenderProcessHost.
  virtual bool Send(IPC::Message* msg);

  // IPC::Channel::Listener via RenderProcessHost.
  virtual void OnMessageReceived(const IPC::Message& msg);
  virtual void OnChannelConnected(int32 peer_pid);
  virtual void OnChannelError();

  // If the a process has sent a message that cannot be decoded, it is deemed
  // corrupted and thus needs to be terminated using this call. This function
  // can be safely called from any thread.
  static void BadMessageTerminateProcess(uint32 msg_type,
                                         base::ProcessHandle renderer);

  // NotificationObserver implementation.
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

  // ChildProcessLauncher::Client implementation.
  virtual void OnProcessLaunched();

 private:
  friend class VisitRelayingRenderProcessHost;

  // Control message handlers.
  void OnUpdatedCacheStats(const WebKit::WebCache::UsageStats& stats);
  void SuddenTerminationChanged(bool enabled);
  void OnExtensionAddListener(const std::string& event_name);
  void OnExtensionRemoveListener(const std::string& event_name);
  void OnExtensionCloseChannel(int port_id);

  // Initialize support for visited links. Send the renderer process its initial
  // set of visited links.
  void InitVisitedLinks();

  // Initialize support for user scripts. Send the renderer process its initial
  // set of scripts and listen for updates to scripts.
  void InitUserScripts();

  // Initialize support for extension APIs. Send the list of registered API
  // functions to thre renderer process.
  void InitExtensions();

  // Sends the renderer process a new set of user scripts.
  void SendUserScriptsUpdate(base::SharedMemory* shared_memory);

  // Generates a command line to be used to spawn a renderer and appends the
  // results to |*command_line|.
  void AppendRendererCommandLine(CommandLine* command_line) const;

  // Copies applicable command line switches from the given |browser_cmd| line
  // flags to the output |renderer_cmd| line flags. Not all switches will be
  // copied over.
  void PropagateBrowserCommandLineToRenderer(const CommandLine& browser_cmd,
                                             CommandLine* renderer_cmd) const;

  // Callers can reduce the RenderProcess' priority.
  // Returns true if the priority is backgrounded; false otherwise.
  void SetBackgrounded(bool boost);

  // The renderer has requested that we initialize its spellchecker. This should
  // generally only be called once per session, as after the first call, all
  // future renderers will be passed the initialization information on startup
  // (or when the dictionary changes in some way).
  void OnSpellCheckerRequestDictionary();

  // Tell the renderer of a new word that has been added to the custom
  // dictionary.
  void AddSpellCheckWord(const std::string& word);

  // Pass the renderer some basic intialization information. Note that the
  // renderer will not load Hunspell until it needs to.
  void InitSpellChecker();

  // Tell the renderer that auto spell correction has been enabled/disabled.
  void EnableAutoSpellCorrect(bool enable);

  NotificationRegistrar registrar_;

  // The count of currently visible widgets.  Since the host can be a container
  // for multiple widgets, it uses this count to determine when it should be
  // backgrounded.
  int32 visible_widgets_;

  // Does this process have backgrounded priority.
  bool backgrounded_;

  // Used to allow a RenderWidgetHost to intercept various messages on the
  // IO thread.
  scoped_refptr<RenderWidgetHelper> widget_helper_;

  // The host of audio renderers in the renderer process.
  scoped_refptr<AudioRendererHost> audio_renderer_host_;

  // A map of transport DIB ids to cached TransportDIBs
  std::map<TransportDIB::Id, TransportDIB*> cached_dibs_;
  enum {
    // This is the maximum size of |cached_dibs_|
    MAX_MAPPED_TRANSPORT_DIBS = 3,
  };

  // Map a transport DIB from its Id and return it. Returns NULL on error.
  TransportDIB* MapTransportDIB(TransportDIB::Id dib_id);

  void ClearTransportDIBCache();
  // This is used to clear our cache five seconds after the last use.
  base::DelayTimer<BrowserRenderProcessHost> cached_dibs_cleaner_;

  // Used in single-process mode.
  scoped_ptr<RendererMainThread> in_process_renderer_;

  // Buffer visited links and send them to to renderer.
  scoped_ptr<VisitedLinkUpdater> visited_link_updater_;

  // True iff this process is being used as an extension process. Not valid
  // when running in single-process mode.
  bool extension_process_;

  // Usedt to launch and terminate the process without blocking the UI thread.
  scoped_ptr<ChildProcessLauncher> child_process_;

  // Messages we queue while waiting for the process handle.  We queue them here
  // instead of in the channel so that we ensure they're sent after init related
  // messages that are sent once the process handle is available.  This is
  // because the queued messages may have dependencies on the init messages.
  std::queue<IPC::Message*> queued_messages_;

  DISALLOW_COPY_AND_ASSIGN(BrowserRenderProcessHost);
};

#endif  // CHROME_BROWSER_RENDERER_HOST_BROWSER_RENDER_PROCESS_HOST_H_