<commit_before>// 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.

#include "chrome/browser/instant/instant_loader.h"

#include <algorithm>
#include <utility>

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/renderer_preferences.h"
#include "gfx/codec/png_codec.h"
#include "ipc/ipc_message.h"

namespace {
// Number of ms to delay before updating the omnibox bounds. This is a bit long
// as updating the bounds ends up being quite expensive.
const int kUpdateBoundsDelayMS = 500;
}  // namespace

// FrameLoadObserver is responsible for determining if the page supports
// instant after it has loaded.
class InstantLoader::FrameLoadObserver : public NotificationObserver {
 public:
  FrameLoadObserver(TabContents* tab_contents,
                    const string16& text,
                    bool verbatim)
      : tab_contents_(tab_contents),
        text_(text),
        verbatim_(verbatim),
        unique_id_(tab_contents_->controller().pending_entry()->unique_id()) {
    registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
                   Source<TabContents>(tab_contents_));
  }

  // Sets the text to send to the page.
  void set_text(const string16& text) { text_ = text; }

  // Sets whether verbatim results are obtained rather than predictive.
  void set_verbatim(bool verbatim) { verbatim_ = verbatim; }

  // NotificationObserver:
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::LOAD_COMPLETED_MAIN_FRAME: {
        int page_id = *(Details<int>(details).ptr());
        NavigationEntry* active_entry =
            tab_contents_->controller().GetActiveEntry();
        if (!active_entry || active_entry->page_id() != page_id ||
            active_entry->unique_id() != unique_id_) {
          return;
        }
        tab_contents_->render_view_host()->DetermineIfPageSupportsInstant(
            text_, verbatim_);
        break;
      }
      default:
        NOTREACHED();
        break;
    }
  }

 private:
  // The TabContents we're listening for changes on.
  TabContents* tab_contents_;

  // Text to send down to the page.
  string16 text_;

  // Whether verbatim results are obtained.
  bool verbatim_;

  // unique_id of the NavigationEntry we're waiting on.
  const int unique_id_;

  // Registers and unregisters us for notifications.
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(FrameLoadObserver);
};

// PaintObserver implementation. When the RenderWidgetHost paints itself this
// notifies the TabContentsDelegateImpl which ultimately notifies InstantLoader
// and shows the preview.
// The ownership of this class is tricky. It's created and
// tracked by TabContentsDelegateImpl, but owned by RenderWidgetHost. When
// deleted this notifies the TabContentsDelegateImpl so that it can clean
// up appropriately.
class InstantLoader::PaintObserverImpl
    : public RenderWidgetHost::PaintObserver {
 public:
  PaintObserverImpl(TabContentsDelegateImpl* delegate,
                    RenderWidgetHost* rwh)
      : delegate_(delegate),
        rwh_(rwh) {
    rwh_->set_paint_observer(this);
  }

  ~PaintObserverImpl();

  // Deletes this object by resetting the PaintObserver on the RenderWidgetHost.
  void Destroy() {
    rwh_->set_paint_observer(NULL);
  }

  virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rwh) {}

  virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh);

 private:
  TabContentsDelegateImpl* delegate_;
  RenderWidgetHost* rwh_;

  DISALLOW_COPY_AND_ASSIGN(PaintObserverImpl);
};

class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
 public:
  explicit TabContentsDelegateImpl(InstantLoader* loader)
      : loader_(loader),
        paint_observer_(NULL),
        waiting_for_new_page_(true),
        is_mouse_down_from_activate_(false),
        user_typed_before_load_(false) {
  }

  // Invoked prior to loading a new URL.
  void PrepareForNewLoad() {
    user_typed_before_load_ = false;
    waiting_for_new_page_ = true;
    add_page_vector_.clear();
    DestroyPaintObserver();
  }

  // Invoked when removed as the delegate. Gives a chance to do any necessary
  // cleanup.
  void Reset() {
    is_mouse_down_from_activate_ = false;
    DestroyPaintObserver();
  }

  // Invoked when the preview paints. Invokes PreviewPainted on the loader.
  void PreviewPainted() {
    loader_->PreviewPainted();
  }

  // Invoked when the PaintObserverImpl is deleted.
  void PaintObserverDestroyed(PaintObserverImpl* observer) {
    if (observer == paint_observer_)
      paint_observer_ = NULL;
  }

  bool is_mouse_down_from_activate() const {
    return is_mouse_down_from_activate_;
  }

  void set_user_typed_before_load() { user_typed_before_load_ = true; }

  // Commits the currently buffered history.
  void CommitHistory() {
    TabContents* tab = loader_->preview_contents()->tab_contents();
    if (tab->profile()->IsOffTheRecord())
      return;

    for (size_t i = 0; i < add_page_vector_.size(); ++i)
      tab->UpdateHistoryForNavigation(add_page_vector_[i].get());

    NavigationEntry* active_entry = tab->controller().GetActiveEntry();
    DCHECK(active_entry);
    tab->UpdateHistoryPageTitle(*active_entry);

    FaviconService* favicon_service =
        tab->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);

    if (favicon_service && active_entry->favicon().is_valid() &&
        !active_entry->favicon().bitmap().empty()) {
      std::vector<unsigned char> image_data;
      gfx::PNGCodec::EncodeBGRASkBitmap(active_entry->favicon().bitmap(), false,
                                        &image_data);
      favicon_service->SetFavicon(active_entry->url(),
                                  active_entry->favicon().url(),
                                  image_data);
    }
  }

  virtual void OpenURLFromTab(TabContents* source,
                              const GURL& url, const GURL& referrer,
                              WindowOpenDisposition disposition,
                              PageTransition::Type transition) {}
  virtual void NavigationStateChanged(const TabContents* source,
                                      unsigned changed_flags) {
    if (!loader_->ready() && !paint_observer_ &&
        source->controller().entry_count()) {<commit_msg>Work around for a crash. I can't narrow down the circumstances when this would happen.<commit_after>// 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.

#include "chrome/browser/instant/instant_loader.h"

#include <algorithm>
#include <utility>

#include "app/l10n_util.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/timer.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/history/history_marshaling.h"
#include "chrome/browser/instant/instant_loader_delegate.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/tab_contents/navigation_controller.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/renderer_preferences.h"
#include "gfx/codec/png_codec.h"
#include "ipc/ipc_message.h"

namespace {
// Number of ms to delay before updating the omnibox bounds. This is a bit long
// as updating the bounds ends up being quite expensive.
const int kUpdateBoundsDelayMS = 500;
}  // namespace

// FrameLoadObserver is responsible for determining if the page supports
// instant after it has loaded.
class InstantLoader::FrameLoadObserver : public NotificationObserver {
 public:
  FrameLoadObserver(TabContents* tab_contents,
                    const string16& text,
                    bool verbatim)
      : tab_contents_(tab_contents),
        text_(text),
        verbatim_(verbatim),
        unique_id_(tab_contents_->controller().pending_entry()->unique_id()) {
    registrar_.Add(this, NotificationType::LOAD_COMPLETED_MAIN_FRAME,
                   Source<TabContents>(tab_contents_));
  }

  // Sets the text to send to the page.
  void set_text(const string16& text) { text_ = text; }

  // Sets whether verbatim results are obtained rather than predictive.
  void set_verbatim(bool verbatim) { verbatim_ = verbatim; }

  // NotificationObserver:
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    switch (type.value) {
      case NotificationType::LOAD_COMPLETED_MAIN_FRAME: {
        int page_id = *(Details<int>(details).ptr());
        NavigationEntry* active_entry =
            tab_contents_->controller().GetActiveEntry();
        if (!active_entry || active_entry->page_id() != page_id ||
            active_entry->unique_id() != unique_id_) {
          return;
        }
        tab_contents_->render_view_host()->DetermineIfPageSupportsInstant(
            text_, verbatim_);
        break;
      }
      default:
        NOTREACHED();
        break;
    }
  }

 private:
  // The TabContents we're listening for changes on.
  TabContents* tab_contents_;

  // Text to send down to the page.
  string16 text_;

  // Whether verbatim results are obtained.
  bool verbatim_;

  // unique_id of the NavigationEntry we're waiting on.
  const int unique_id_;

  // Registers and unregisters us for notifications.
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(FrameLoadObserver);
};

// PaintObserver implementation. When the RenderWidgetHost paints itself this
// notifies the TabContentsDelegateImpl which ultimately notifies InstantLoader
// and shows the preview.
// The ownership of this class is tricky. It's created and
// tracked by TabContentsDelegateImpl, but owned by RenderWidgetHost. When
// deleted this notifies the TabContentsDelegateImpl so that it can clean
// up appropriately.
class InstantLoader::PaintObserverImpl
    : public RenderWidgetHost::PaintObserver {
 public:
  PaintObserverImpl(TabContentsDelegateImpl* delegate,
                    RenderWidgetHost* rwh)
      : delegate_(delegate),
        rwh_(rwh) {
    rwh_->set_paint_observer(this);
  }

  ~PaintObserverImpl();

  // Deletes this object by resetting the PaintObserver on the RenderWidgetHost.
  void Destroy() {
    rwh_->set_paint_observer(NULL);
  }

  virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rwh) {}

  virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh);

 private:
  TabContentsDelegateImpl* delegate_;
  RenderWidgetHost* rwh_;

  DISALLOW_COPY_AND_ASSIGN(PaintObserverImpl);
};

class InstantLoader::TabContentsDelegateImpl : public TabContentsDelegate {
 public:
  explicit TabContentsDelegateImpl(InstantLoader* loader)
      : loader_(loader),
        paint_observer_(NULL),
        waiting_for_new_page_(true),
        is_mouse_down_from_activate_(false),
        user_typed_before_load_(false) {
  }

  // Invoked prior to loading a new URL.
  void PrepareForNewLoad() {
    user_typed_before_load_ = false;
    waiting_for_new_page_ = true;
    add_page_vector_.clear();
    DestroyPaintObserver();
  }

  // Invoked when removed as the delegate. Gives a chance to do any necessary
  // cleanup.
  void Reset() {
    is_mouse_down_from_activate_ = false;
    DestroyPaintObserver();
  }

  // Invoked when the preview paints. Invokes PreviewPainted on the loader.
  void PreviewPainted() {
    loader_->PreviewPainted();
  }

  // Invoked when the PaintObserverImpl is deleted.
  void PaintObserverDestroyed(PaintObserverImpl* observer) {
    if (observer == paint_observer_)
      paint_observer_ = NULL;
  }

  bool is_mouse_down_from_activate() const {
    return is_mouse_down_from_activate_;
  }

  void set_user_typed_before_load() { user_typed_before_load_ = true; }

  // Commits the currently buffered history.
  void CommitHistory() {
    TabContents* tab = loader_->preview_contents()->tab_contents();
    if (tab->profile()->IsOffTheRecord())
      return;

    for (size_t i = 0; i < add_page_vector_.size(); ++i)
      tab->UpdateHistoryForNavigation(add_page_vector_[i].get());

    NavigationEntry* active_entry = tab->controller().GetActiveEntry();
    if (!active_entry) {
      // It appears to be possible to get here with no active entry. This seems
      // to be possible with an auth dialog, but I can't narrow down the
      // circumstances. If you hit this, file a bug with the steps you did and
      // assign it to me (sky).
      NOTREACHED();
      return;
    }
    tab->UpdateHistoryPageTitle(*active_entry);

    FaviconService* favicon_service =
        tab->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);

    if (favicon_service && active_entry->favicon().is_valid() &&
        !active_entry->favicon().bitmap().empty()) {
      std::vector<unsigned char> image_data;
      gfx::PNGCodec::EncodeBGRASkBitmap(active_entry->favicon().bitmap(), false,
                                        &image_data);
      favicon_service->SetFavicon(active_entry->url(),
                                  active_entry->favicon().url(),
                                  image_data);
    }
  }

  virtual void OpenURLFromTab(TabContents* source,
                              const GURL& url, const GURL& referrer,
                              WindowOpenDisposition disposition,
                              PageTransition::Type transition) {}
  virtual void NavigationStateChanged(const TabContents* source,
                                      unsigned changed_flags) {
    if (!loader_->ready() && !paint_observer_ &&
        source->controller().entry_count()) {
{'fraction_non_alphanumeric': 0.09796199049762441, 'fraction_numerical': 0.002000500125031258, 'mean_word_length': 3.4948019106490587, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4998402', 'n_tokens_mistral': 4713, 'n_tokens_neox': 4519, 'n_words': 1073}