<commit_before>// Copyright (c) 2009 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/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "net/base/net_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_dnd_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  if (tab_contents_->GetBookmarkDragDelegate()) {
    tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    static int supported_targets[] = {
      gtk_dnd_util::TEXT_PLAIN,
      gtk_dnd_util::TEXT_URI_LIST,
      gtk_dnd_util::TEXT_HTML,
      gtk_dnd_util::NETSCAPE_URL,
      gtk_dnd_util::CHROME_NAMED_URL,
      gtk_dnd_util::CHROME_BOOKMARK_ITEM,
      // TODO(estade): support image drags?
    };

    data_requests_ = arraysize(supported_targets);
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        gtk_dnd_util::GetAtomForTarget(supported_targets[i]),
                        time);
    }
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_dnd_util::GdkDragActionToWebDragOp(context->actions));
    if (tab_contents_->GetBookmarkDragDelegate())
      tab_contents_->GetBookmarkDragDelegate()->OnDragOver(bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          FilePath file_path;
          if (net::FileURLToFilePath(GURL(*uri_iter), &file_path))
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
        }
        // Also, write the first URI as the URL.
        if (uris[0])
          drop_data_->url = GURL(uris[0]);
        g_strfreev(uris);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL)) {
      gtk_dnd_util::ExtractNamedURL(data,
                                    &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  if (data->target ==
      gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM))  {
    if (data->data && data->length > 0) {
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              gtk_dnd_util::CHROME_BOOKMARK_ITEM,
              tab_contents_->profile(), NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(tab_contents_->profile());
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_dnd_util::GdkDragActionToWebDragOp(context->actions));

    // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_contents_->GetBookmarkDragDelegate()) {
      tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }

    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_contents_->GetBookmarkDragDelegate())
    tab_contents_->GetBookmarkDragDelegate()->OnDrop(bookmark_drag_data_);

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<commit_msg>Don't populate WebDropData with file URLs when dragging files.<commit_after>// Copyright (c) 2009 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/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "net/base/net_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_dnd_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  if (tab_contents_->GetBookmarkDragDelegate()) {
    tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    // text/plain must come before text/uri-list. This is a hack that works in
    // conjunction with OnDragDataReceived. Since some file managers populate
    // text/plain with file URLs when dragging files, we want to handle
    // text/uri-list after text/plain so that the plain text can be cleared if
    // it's a file drag.
    static int supported_targets[] = {
      gtk_dnd_util::TEXT_PLAIN,
      gtk_dnd_util::TEXT_URI_LIST,
      gtk_dnd_util::TEXT_HTML,
      gtk_dnd_util::NETSCAPE_URL,
      gtk_dnd_util::CHROME_NAMED_URL,
      gtk_dnd_util::CHROME_BOOKMARK_ITEM,
      // TODO(estade): support image drags?
    };

    data_requests_ = arraysize(supported_targets);
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        gtk_dnd_util::GetAtomForTarget(supported_targets[i]),
                        time);
    }
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_dnd_util::GdkDragActionToWebDragOp(context->actions));
    if (tab_contents_->GetBookmarkDragDelegate())
      tab_contents_->GetBookmarkDragDelegate()->OnDragOver(bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        drop_data_->url = GURL();
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // Most file managers populate text/uri-list with file URLs when
          // dragging files. To avoid exposing file system paths to web content,
          // file URLs are never set as the URL content for the drop.
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          FilePath file_path;
          if (net::FileURLToFilePath(GURL(*uri_iter), &file_path)) {
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
            // This is a hack. Some file managers also populate text/plain with
            // a file URL when dragging files, so we clear it to avoid exposing
            // it to the web content.
            drop_data_->plain_text.clear();
          } else if (!drop_data_->url.is_valid()) {
            // Also set the first non-file URL as the URL content for the drop.
            drop_data_->url = GURL(*uri_iter);
          }
        }
        g_strfreev(uris);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL)) {
      gtk_dnd_util::ExtractNamedURL(data,
                                    &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  if (data->target ==
      gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM))  {
    if (data->data && data->length > 0) {
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              gtk_dnd_util::CHROME_BOOKMARK_ITEM,
              tab_contents_->profile(), NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(tab_contents_->profile());
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_dnd_util::GdkDragActionToWebDragOp(context->actions));

    // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_contents_->GetBookmarkDragDelegate()) {
      tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }

    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_contents_->GetBookmarkDragDelegate())
    tab_contents_->GetBookmarkDragDelegate()->OnDrop(bookmark_drag_data_);

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "net/base/net_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

namespace {

// Returns the bookmark target atom, based on the underlying toolkit.
//
// For GTK, bookmark drag data is encoded as pickle and associated with
// gtk_dnd_util::CHROME_BOOKMARK_ITEM. See
// bookmark_utils::WriteBookmarksToSelection() for details.
// For Views, bookmark drag data is encoded in the same format, and
// associated with a custom format. See BookmarkDragData::Write() for
// details.
GdkAtom GetBookmarkTargetAtom() {
#if defined(TOOLKIT_VIEWS)
  return BookmarkDragData::GetBookmarkCustomFormat();
#else
  return gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM);
#endif
}

}  // namespace

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  if (tab_contents_->GetBookmarkDragDelegate()) {
    tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    // text/plain must come before text/uri-list. This is a hack that works in
    // conjunction with OnDragDataReceived. Since some file managers populate
    // text/plain with file URLs when dragging files, we want to handle
    // text/uri-list after text/plain so that the plain text can be cleared if
    // it's a file drag.
    static int supported_targets[] = {
      gtk_dnd_util::TEXT_PLAIN,
      gtk_dnd_util::TEXT_URI_LIST,
      gtk_dnd_util::TEXT_HTML,
      gtk_dnd_util::NETSCAPE_URL,
      gtk_dnd_util::CHROME_NAMED_URL,
      // TODO(estade): support image drags?
    };

    // Add the bookmark target as well.
    data_requests_ = arraysize(supported_targets) + 1;
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        gtk_dnd_util::GetAtomForTarget(supported_targets[i]),
                        time);
    }

    gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time);
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));
    if (tab_contents_->GetBookmarkDragDelegate())
      tab_contents_->GetBookmarkDragDelegate()->OnDragOver(bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        drop_data_->url = GURL();
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // Most file managers populate text/uri-list with file URLs when
          // dragging files. To avoid exposing file system paths to web content,
          // file URLs are never set as the URL content for the drop.
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          FilePath file_path;
          if (net::FileURLToFilePath(GURL(*uri_iter), &file_path)) {
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
            // This is a hack. Some file managers also populate text/plain with
            // a file URL when dragging files, so we clear it to avoid exposing
            // it to the web content.
            drop_data_->plain_text.clear();
          } else if (!drop_data_->url.is_valid()) {
            // Also set the first non-file URL as the URL content for the drop.
            drop_data_->url = GURL(*uri_iter);
          }
        }
        g_strfreev(uris);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL)) {
      gtk_dnd_util::ExtractNamedURL(data,
                                    &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  // Note that bookmark drag data is encoded in the same format for both
  // GTK and Views, hence we can share the same logic here.
  if (data->target == GetBookmarkTargetAtom()) {
    if (data->data && data->length > 0) {
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              gtk_dnd_util::CHROME_BOOKMARK_ITEM,
              tab_contents_->profile(), NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(tab_contents_->profile());
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));

    // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_contents_->GetBookmarkDragDelegate()) {
      tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }

    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_contents_->GetBookmarkDragDelegate())
    tab_contents_->GetBookmarkDragDelegate()->OnDrop(bookmark_drag_data_);

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<commit_msg>Fix file URL detection in WebDragDestGtk.<commit_after>// Copyright (c) 2009 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/tab_contents/web_drag_dest_gtk.h"

#include <string>

#include "app/gtk_dnd_util.h"
#include "base/file_path.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/bookmarks/bookmark_drag_data.h"
#include "chrome/browser/gtk/bookmark_utils_gtk.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"

using WebKit::WebDragOperation;
using WebKit::WebDragOperationNone;

namespace {

// Returns the bookmark target atom, based on the underlying toolkit.
//
// For GTK, bookmark drag data is encoded as pickle and associated with
// gtk_dnd_util::CHROME_BOOKMARK_ITEM. See
// bookmark_utils::WriteBookmarksToSelection() for details.
// For Views, bookmark drag data is encoded in the same format, and
// associated with a custom format. See BookmarkDragData::Write() for
// details.
GdkAtom GetBookmarkTargetAtom() {
#if defined(TOOLKIT_VIEWS)
  return BookmarkDragData::GetBookmarkCustomFormat();
#else
  return gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM);
#endif
}

}  // namespace

WebDragDestGtk::WebDragDestGtk(TabContents* tab_contents, GtkWidget* widget)
    : tab_contents_(tab_contents),
      widget_(widget),
      context_(NULL),
      method_factory_(this) {
  gtk_drag_dest_set(widget, static_cast<GtkDestDefaults>(0),
                    NULL, 0,
                    static_cast<GdkDragAction>(GDK_ACTION_COPY |
                                               GDK_ACTION_LINK |
                                               GDK_ACTION_MOVE));
  g_signal_connect(widget, "drag-motion",
                   G_CALLBACK(OnDragMotionThunk), this);
  g_signal_connect(widget, "drag-leave",
                   G_CALLBACK(OnDragLeaveThunk), this);
  g_signal_connect(widget, "drag-drop",
                   G_CALLBACK(OnDragDropThunk), this);
  g_signal_connect(widget, "drag-data-received",
                   G_CALLBACK(OnDragDataReceivedThunk), this);
  // TODO(tony): Need a drag-data-delete handler for moving content out of
  // the tab contents.  http://crbug.com/38989

  destroy_handler_ = g_signal_connect(
      widget, "destroy", G_CALLBACK(gtk_widget_destroyed), &widget_);
}

WebDragDestGtk::~WebDragDestGtk() {
  if (widget_) {
    gtk_drag_dest_unset(widget_);
    g_signal_handler_disconnect(widget_, destroy_handler_);
  }
}

void WebDragDestGtk::UpdateDragStatus(WebDragOperation operation) {
  if (context_) {
    is_drop_target_ = operation != WebDragOperationNone;
    gdk_drag_status(context_, gtk_util::WebDragOpToGdkDragAction(operation),
                    drag_over_time_);
  }
}

void WebDragDestGtk::DragLeave() {
  tab_contents_->render_view_host()->DragTargetDragLeave();

  if (tab_contents_->GetBookmarkDragDelegate()) {
    tab_contents_->GetBookmarkDragDelegate()->OnDragLeave(bookmark_drag_data_);
  }
}

gboolean WebDragDestGtk::OnDragMotion(GtkWidget* sender,
                                      GdkDragContext* context,
                                      gint x, gint y,
                                      guint time) {
  if (context_ != context) {
    context_ = context;
    drop_data_.reset(new WebDropData);
    bookmark_drag_data_.Clear();
    is_drop_target_ = false;

    // text/plain must come before text/uri-list. This is a hack that works in
    // conjunction with OnDragDataReceived. Since some file managers populate
    // text/plain with file URLs when dragging files, we want to handle
    // text/uri-list after text/plain so that the plain text can be cleared if
    // it's a file drag.
    static int supported_targets[] = {
      gtk_dnd_util::TEXT_PLAIN,
      gtk_dnd_util::TEXT_URI_LIST,
      gtk_dnd_util::TEXT_HTML,
      gtk_dnd_util::NETSCAPE_URL,
      gtk_dnd_util::CHROME_NAMED_URL,
      // TODO(estade): support image drags?
    };

    // Add the bookmark target as well.
    data_requests_ = arraysize(supported_targets) + 1;
    for (size_t i = 0; i < arraysize(supported_targets); ++i) {
      gtk_drag_get_data(widget_, context,
                        gtk_dnd_util::GetAtomForTarget(supported_targets[i]),
                        time);
    }

    gtk_drag_get_data(widget_, context, GetBookmarkTargetAtom(), time);
  } else if (data_requests_ == 0) {
    tab_contents_->render_view_host()->
        DragTargetDragOver(
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));
    if (tab_contents_->GetBookmarkDragDelegate())
      tab_contents_->GetBookmarkDragDelegate()->OnDragOver(bookmark_drag_data_);
    drag_over_time_ = time;
  }

  // Pretend we are a drag destination because we don't want to wait for
  // the renderer to tell us if we really are or not.
  return TRUE;
}

void WebDragDestGtk::OnDragDataReceived(
    GtkWidget* sender, GdkDragContext* context, gint x, gint y,
    GtkSelectionData* data, guint info, guint time) {
  // We might get the data from an old get_data() request that we no longer
  // care about.
  if (context != context_)
    return;

  data_requests_--;

  // Decode the data.
  if (data->data && data->length > 0) {
    // If the source can't provide us with valid data for a requested target,
    // data->data will be NULL.
    if (data->target ==
        gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_PLAIN)) {
      guchar* text = gtk_selection_data_get_text(data);
      if (text) {
        drop_data_->plain_text =
            UTF8ToUTF16(std::string(reinterpret_cast<char*>(text),
                                    data->length));
        g_free(text);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_URI_LIST)) {
      gchar** uris = gtk_selection_data_get_uris(data);
      if (uris) {
        drop_data_->url = GURL();
        for (gchar** uri_iter = uris; *uri_iter; uri_iter++) {
          // Most file managers populate text/uri-list with file URLs when
          // dragging files. To avoid exposing file system paths to web content,
          // file URLs are never set as the URL content for the drop.
          // TODO(estade): Can the filenames have a non-UTF8 encoding?
          GURL url(*uri_iter);
          FilePath file_path;
          if (url.SchemeIs(chrome::kFileScheme) &&
              net::FileURLToFilePath(url, &file_path)) {
            drop_data_->filenames.push_back(UTF8ToUTF16(file_path.value()));
            // This is a hack. Some file managers also populate text/plain with
            // a file URL when dragging files, so we clear it to avoid exposing
            // it to the web content.
            drop_data_->plain_text.clear();
          } else if (!drop_data_->url.is_valid()) {
            // Also set the first non-file URL as the URL content for the drop.
            drop_data_->url = url;
          }
        }
        g_strfreev(uris);
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::TEXT_HTML)) {
      // TODO(estade): Can the html have a non-UTF8 encoding?
      drop_data_->text_html =
          UTF8ToUTF16(std::string(reinterpret_cast<char*>(data->data),
                                  data->length));
      // We leave the base URL empty.
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::NETSCAPE_URL)) {
      std::string netscape_url(reinterpret_cast<char*>(data->data),
                               data->length);
      size_t split = netscape_url.find_first_of('\n');
      if (split != std::string::npos) {
        drop_data_->url = GURL(netscape_url.substr(0, split));
        if (split < netscape_url.size() - 1)
          drop_data_->url_title = UTF8ToUTF16(netscape_url.substr(split + 1));
      }
    } else if (data->target ==
               gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_NAMED_URL)) {
      gtk_dnd_util::ExtractNamedURL(data,
                                    &drop_data_->url, &drop_data_->url_title);
    }
  }

  // For CHROME_BOOKMARK_ITEM, we have to handle the case where the drag source
  // doesn't have any data available for us. In this case we try to synthesize a
  // URL bookmark.
  // Note that bookmark drag data is encoded in the same format for both
  // GTK and Views, hence we can share the same logic here.
  if (data->target == GetBookmarkTargetAtom()) {
    if (data->data && data->length > 0) {
      bookmark_drag_data_.ReadFromVector(
          bookmark_utils::GetNodesFromSelection(
              NULL, data,
              gtk_dnd_util::CHROME_BOOKMARK_ITEM,
              tab_contents_->profile(), NULL, NULL));
      bookmark_drag_data_.SetOriginatingProfile(tab_contents_->profile());
    } else {
      bookmark_drag_data_.ReadFromTuple(drop_data_->url,
                                        drop_data_->url_title);
    }
  }

  if (data_requests_ == 0) {
    // Tell the renderer about the drag.
    // |x| and |y| are seemingly arbitrary at this point.
    tab_contents_->render_view_host()->
        DragTargetDragEnter(*drop_data_.get(),
            gtk_util::ClientPoint(widget_),
            gtk_util::ScreenPoint(widget_),
            gtk_util::GdkDragActionToWebDragOp(context->actions));

    // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
    // support for (at the moment experimental) drag and drop extensions.
    if (tab_contents_->GetBookmarkDragDelegate()) {
      tab_contents_->GetBookmarkDragDelegate()->OnDragEnter(
          bookmark_drag_data_);
    }

    drag_over_time_ = time;
  }
}

// The drag has left our widget; forward this information to the renderer.
void WebDragDestGtk::OnDragLeave(GtkWidget* sender, GdkDragContext* context,
                                 guint time) {
  // Set |context_| to NULL to make sure we will recognize the next DragMotion
  // as an enter.
  context_ = NULL;
  drop_data_.reset();
  // When GTK sends us a drag-drop signal, it is shortly (and synchronously)
  // preceded by a drag-leave. The renderer doesn't like getting the signals
  // in this order so delay telling it about the drag-leave till we are sure
  // we are not getting a drop as well.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&WebDragDestGtk::DragLeave));
}

// Called by GTK when the user releases the mouse, executing a drop.
gboolean WebDragDestGtk::OnDragDrop(GtkWidget* sender, GdkDragContext* context,
                                    gint x, gint y, guint time) {
  // Cancel that drag leave!
  method_factory_.RevokeAll();

  tab_contents_->render_view_host()->
      DragTargetDrop(gtk_util::ClientPoint(widget_),
                     gtk_util::ScreenPoint(widget_));

  // This is non-null if tab_contents_ is showing an ExtensionDOMUI with
  // support for (at the moment experimental) drag and drop extensions.
  if (tab_contents_->GetBookmarkDragDelegate())
    tab_contents_->GetBookmarkDragDelegate()->OnDrop(bookmark_drag_data_);

  // The second parameter is just an educated guess as to whether or not the
  // drag succeeded, but at least we will get the drag-end animation right
  // sometimes.
  gtk_drag_finish(context, is_drop_target_, FALSE, time);
  return TRUE;
}
<|endoftext|>


<commit_before>#include <highgui.h>
#include <cxcore.h>
#include <vector>
#include "utils.hpp"

struct PointAngle{
	CvPoint p;
	float angle;
};

int comp_point_with_angle(const void * a, const void * b) {
	if ( ((PointAngle*)a)->angle <  ((PointAngle*)b)->angle ) return -1;
	else if ( ((PointAngle*)a)->angle > ((PointAngle*)b)->angle ) return 1;
	else //if ( ((PointAngle*)a)->angle == ((PointAngle*)b)->angle ) return 0;
		return 0;
}

const char * title = "Convex Polygon Intersection";
class UIPolyIntersection {
	float _resolution;
	int _nb_grid;
	int _width ;
	int _height;
	std::vector<CvPoint> _poly[2];
	std::vector<CvPoint> _inter;
	std::vector<CvPoint *> _all;
	IplImage * curr_rgb;
	CvPoint pCurr;
	int key;
	int selected_point;
	int hover_point;
	static void mouseCallback(int event, int x, int y, int flags, void* param) {
		static_cast<UIPolyIntersection*>(param)->mouseEvent(event, x, y, flags,param);
	}
public:

	UIPolyIntersection(int width) {
		_width = width;
		_height = _width*9/16;
		hover_point = selected_point = -1;
		curr_rgb = cvCreateImage(cvSize(_width,_height),8,3);
		pCurr = cvPoint(0,0);

		initRandom();
		cvZero(curr_rgb);
		cvNamedWindow(title, CV_WINDOW_AUTOSIZE);
		cvSetMouseCallback(title, &UIPolyIntersection::mouseCallback , this );
	}

	~UIPolyIntersection() {
		cvReleaseImage(&curr_rgb);
	}

	void initRandom() {
		for (int j = 0 ; j < 2 ; j++ ) {
			int n = 5;
			_poly[j].reserve(n);
			_poly[j].clear();
			for (int i = 0 ; i < n ; i++ ) {
				CvPoint p = cvPoint(rand()%_width,rand()%_height);
				_poly[j].push_back(p);
				_all.push_back(&_poly[j][i]);
			}
		}
		_nb_grid = 50;
		_resolution = _width /(float)_nb_grid;
		updateIntersection();
	}

	void mouseEvent( int event, int x, int y, int flags, void* ) {
		pCurr = cvPoint(x,y);
		hover_point = -1;
		for(size_t i  = 0 ; i < _all.size() ; i++ ){
			if(distPoint(pCurr,*_all[i]) < 5) {
				hover_point = i ;break;
			}
		}
		if( event == CV_EVENT_LBUTTONDOWN && hover_point != -1 ) {
			selected_point = hover_point;
		} else if(event == CV_EVENT_MOUSEMOVE && selected_point != -1 ) {
			_all[selected_point]->x = pCurr.x;
			_all[selected_point]->y = pCurr.y;
		} else if(event == CV_EVENT_LBUTTONUP ) {
			if(selected_point != -1) {
				updateIntersection();
				selected_point  = -1;
			} else {

			}
		}
	}

	void drawGrid() {
		for (int r = 0 ; r < _nb_grid ; r++ ) {
			int var = (int)(_resolution * r);
			cvDrawLine(curr_rgb,cvPoint(0,var),cvPoint(_width,var),CV_RGB(50,50,50));
			cvDrawLine(curr_rgb,cvPoint(var,0),cvPoint(var,_width),CV_RGB(50,50,50));
		}
	}

	void drawPoints() {
		char buff[128];
		CvFont font = cvFont(1,1);
		CvScalar c[3];
		c[0] = CV_RGB(255,0,0);
		c[1] = CV_RGB(84,255,0);
		c[2] = CV_RGB(0,169,255);

		for (int j = 0 ; j < 2 ; j++ ) {
			for (size_t i = 0 ; i < _poly[j].size() ; i++ ) {
				cvDrawLine(curr_rgb,_poly[j][i],_poly[j][(i+1)%_poly[j].size()],c[j],1,CV_AA);
				sprintf(buff,"%d",i); cvPutText(curr_rgb,buff,_poly[j][i],&font,c[j]);
			}
			float area = computeArea(&_poly[j][0],(int)_poly[j].size());
			CvPoint center = getCenter(&_poly[j][0],(int)_poly[j].size());
			sprintf(buff,"Area = %0.1f",area/(_resolution*_resolution)); cvPutText(curr_rgb,buff,center,&font,c[j]);
		}

		for (size_t i = 0 ; i < _all.size() ; i++ ) {
			cvDrawCircle(curr_rgb,*_all[i],5,CV_RGB(0,255,255),1,CV_AA);
		}

		for (size_t i = 0 ; i < _inter.size() ; i++ ) {
			cvDrawLine(curr_rgb,_inter[i],_inter[(i+1)%_inter.size()],c[2],2,CV_AA);
		}

		for (size_t i = 0 ; i < _inter.size() ; i++ ) {
			cvDrawCircle(curr_rgb,_inter[i],1,CV_RGB(250,250,250),2,CV_AA);
		}
		if( _inter.size() ) {
			float area = computeArea(&_inter[0],(int)_inter.size());
			CvPoint center = getCenter(&_inter[0],(int)_inter.size());
			sprintf(buff,"Area intersected = %0.1f",area/(_resolution*_resolution)); cvPutText(curr_rgb,buff,center,&font,c[2]);
		}
	}

	void paintImage() {
		cvZero(curr_rgb);
		drawGrid();
		cvDrawLine(curr_rgb,cvPoint(pCurr.x,0),cvPoint(pCurr.x,curr_rgb->height),CV_RGB(255,0,255));
		cvDrawLine(curr_rgb,cvPoint(0,pCurr.y),cvPoint(curr_rgb->width,pCurr.y),CV_RGB(255,0,255));
		drawPoints();

		if( hover_point != -1) {
			cvDrawCircle(curr_rgb,*_all[hover_point],10,CV_RGB(255,255,0),1,CV_AA,0);
		}

		if( selected_point != -1) {
			cvDrawCircle(curr_rgb,*_all[selected_point],10,CV_RGB(255,255,0),1,CV_AA,0);
		}
	}

	CvPoint getCenter(CvPoint * points,int n) {
		CvPoint center;
		center.x = 0;
		center.y = 0;
		for (int i = 0 ; i < n ; i++ ) {
			center.x += points[i].x;
			center.y += points[i].y;
		}
		center.x /= n;
		center.y /= n;
		return center;
	}

	float computeArea(const CvPoint * points,int n) {
		float area0 = 0.;
		for (int i = 0 ; i < n ; i++ ) {
			int j = (i+1)%n;
			area0 += points[i].x * points[j].y;
			area0 -= points[i].y * points[j].x;
		}
		return 0.5f * abs(area0);
	}

	void pointsOrdered(CvPoint * points,int n) {
		CvPoint center = getCenter(points,n);
		PointAngle pc[400];
		for (int i = 0 ; i < n ; i++ ) {
			pc[i].p.x = points[i].x;
			pc[i].p.y = points[i].y;
			pc[i].angle = atan2f((float)(points[i].y - center.y),(float)(points[i].x - center.x));
		}
		qsort(pc,n,sizeof(PointAngle),comp_point_with_angle);
		for (int i = 0 ; i < n ; i++ ) {
			points[i].x = pc[i].p.x;
			points[i].y = pc[i].p.y;
		}
	}

	void updateIntersection() {
		for (int j = 0 ; j < 2 ; j++ ) {
			pointsOrdered(&_poly[j][0],(int)_poly[j].size());
		}

		_inter.clear();
		for (size_t i = 0 ; i < _poly[0].size() ;i++) {
			if( pointInPolygon(_poly[0][i],&_poly[1][0],(int)_poly[1].size()) )
				_inter.push_back(_poly[0][i]);
		}

		for (size_t i = 0 ; i < _poly[1].size() ;i++) {
			if( pointInPolygon(_poly[1][i],&_poly[0][0],(int)_poly[0].size()) )
				_inter.push_back(_poly[1][i]);
		}

		for (size_t i = 0 ; i < _poly[0].size() ;i++) {
			CvPoint p0,p1,p2,p3;
			p0 = _poly[0][i];
			p1 = _poly[0][(i+1)%_poly[0].size()];
			for (size_t j = 0 ; j < _poly[1].size() ;j++) {
				p2 = _poly[1][j];
				p3 = _poly[1][(j+1)%_poly[1].size()];
				CvPoint inter;
				if(segementIntersection(p0,p1,p2,p3,&inter)) {
					_inter.push_back(inter);
				}
			}
		}
		if(_inter.size())pointsOrdered(&_inter[0],(int)_inter.size());
	}

	void run() {
		while(true) {
			try {
				paintImage();
			} catch (std::exception &e) {
				printf("Err : %s\n",e.what());
			}
			cvShowImage(title,curr_rgb);
			switch( key = cvWaitKey(30)) {
			case 'r' : initRandom();break;
			case 27  : return ;
			}
		}
	}
};

int main(int argc,char **argv) {
	try {
		UIPolyIntersection ui(1280);
		ui.run();
	} catch (std::exception &e) {
		printf("Err : %s\n",e.what());
	}
	return 1;
}<commit_msg>move correctly init data in constructor.<commit_after>#include <highgui.h>
#include <cxcore.h>
#include <vector>
#include "utils.hpp"

struct PointAngle{
	CvPoint p;
	float angle;
};

int comp_point_with_angle(const void * a, const void * b) {
	if ( ((PointAngle*)a)->angle <  ((PointAngle*)b)->angle ) return -1;
	else if ( ((PointAngle*)a)->angle > ((PointAngle*)b)->angle ) return 1;
	else //if ( ((PointAngle*)a)->angle == ((PointAngle*)b)->angle ) return 0;
		return 0;
}

const char * title = "Convex Polygon Intersection";
class UIPolyIntersection {
	float _resolution;
	int _nb_grid;
	int _width ;
	int _height;
	std::vector<CvPoint> _poly[2];
	std::vector<CvPoint> _inter;
	std::vector<CvPoint *> _all;
	IplImage * curr_rgb;
	CvPoint pCurr;
	int key;
	int selected_point;
	int hover_point;
	static void mouseCallback(int event, int x, int y, int flags, void* param) {
		static_cast<UIPolyIntersection*>(param)->mouseEvent(event, x, y, flags,param);
	}
public:

	UIPolyIntersection(int width) {
		_nb_grid = 50;
		_width = width;
		_height = _width*9/16;
		hover_point = selected_point = -1;
		curr_rgb = cvCreateImage(cvSize(_width,_height),8,3);
		pCurr = cvPoint(0,0);
		_resolution = _width /(float)_nb_grid;
		initRandom();
		cvZero(curr_rgb);
		cvNamedWindow(title, CV_WINDOW_AUTOSIZE);
		cvSetMouseCallback(title, &UIPolyIntersection::mouseCallback , this );
	}

	~UIPolyIntersection() {
		cvReleaseImage(&curr_rgb);
	}

	void initRandom() {
		for (int j = 0 ; j < 2 ; j++ ) {
			int n = 5;
			_poly[j].reserve(n);
			_poly[j].clear();
			for (int i = 0 ; i < n ; i++ ) {
				CvPoint p = cvPoint(rand()%_width,rand()%_height);
				_poly[j].push_back(p);
				_all.push_back(&_poly[j][i]);
			}
		}
		updateIntersection();
	}

	void mouseEvent( int event, int x, int y, int flags, void* ) {
		pCurr = cvPoint(x,y);
		hover_point = -1;
		for(size_t i  = 0 ; i < _all.size() ; i++ ){
			if(distPoint(pCurr,*_all[i]) < 5) {
				hover_point = i ;break;
			}
		}
		if( event == CV_EVENT_LBUTTONDOWN && hover_point != -1 ) {
			selected_point = hover_point;
		} else if(event == CV_EVENT_MOUSEMOVE && selected_point != -1 ) {
			_all[selected_point]->x = pCurr.x;
			_all[selected_point]->y = pCurr.y;
		} else if(event == CV_EVENT_LBUTTONUP ) {
			if(selected_point != -1) {
				updateIntersection();
				selected_point  = -1;
			} else {

			}
		}
	}

	void drawGrid() {
		for (int r = 0 ; r < _nb_grid ; r++ ) {
			int var = (int)(_resolution * r);
			cvDrawLine(curr_rgb,cvPoint(0,var),cvPoint(_width,var),CV_RGB(50,50,50));
			cvDrawLine(curr_rgb,cvPoint(var,0),cvPoint(var,_width),CV_RGB(50,50,50));
		}
	}

	void drawPoints() {
		char buff[128];
		CvFont font = cvFont(1,1);
		CvScalar c[3];
		c[0] = CV_RGB(255,0,0);
		c[1] = CV_RGB(84,255,0);
		c[2] = CV_RGB(0,169,255);

		for (int j = 0 ; j < 2 ; j++ ) {
			for (size_t i = 0 ; i < _poly[j].size() ; i++ ) {
				cvDrawLine(curr_rgb,_poly[j][i],_poly[j][(i+1)%_poly[j].size()],c[j],1,CV_AA);
				sprintf(buff,"%d",i); cvPutText(curr_rgb,buff,_poly[j][i],&font,c[j]);
			}
			float area = computeArea(&_poly[j][0],(int)_poly[j].size());
			CvPoint center = getCenter(&_poly[j][0],(int)_poly[j].size());
			sprintf(buff,"Area = %0.1f",area/(_resolution*_resolution)); cvPutText(curr_rgb,buff,center,&font,c[j]);
		}

		for (size_t i = 0 ; i < _all.size() ; i++ ) {
			cvDrawCircle(curr_rgb,*_all[i],5,CV_RGB(0,255,255),1,CV_AA);
		}

		for (size_t i = 0 ; i < _inter.size() ; i++ ) {
			cvDrawLine(curr_rgb,_inter[i],_inter[(i+1)%_inter.size()],c[2],2,CV_AA);
		}

		for (size_t i = 0 ; i < _inter.size() ; i++ ) {
			cvDrawCircle(curr_rgb,_inter[i],1,CV_RGB(250,250,250),2,CV_AA);
		}
		if( _inter.size() ) {
			float area = computeArea(&_inter[0],(int)_inter.size());
			CvPoint center = getCenter(&_inter[0],(int)_inter.size());
			sprintf(buff,"Area intersected = %0.1f",area/(_resolution*_resolution)); cvPutText(curr_rgb,buff,center,&font,c[2]);
		}
	}

	void paintImage() {
		cvZero(curr_rgb);
		drawGrid();
		cvDrawLine(curr_rgb,cvPoint(pCurr.x,0),cvPoint(pCurr.x,curr_rgb->height),CV_RGB(255,0,255));
		cvDrawLine(curr_rgb,cvPoint(0,pCurr.y),cvPoint(curr_rgb->width,pCurr.y),CV_RGB(255,0,255));
		drawPoints();

		if( hover_point != -1) {
			cvDrawCircle(curr_rgb,*_all[hover_point],10,CV_RGB(255,255,0),1,CV_AA,0);
		}

		if( selected_point != -1) {
			cvDrawCircle(curr_rgb,*_all[selected_point],10,CV_RGB(255,255,0),1,CV_AA,0);
		}
	}

	CvPoint getCenter(CvPoint * points,int n) {
		CvPoint center;
		center.x = 0;
		center.y = 0;
		for (int i = 0 ; i < n ; i++ ) {
			center.x += points[i].x;
			center.y += points[i].y;
		}
		center.x /= n;
		center.y /= n;
		return center;
	}

	float computeArea(const CvPoint * points,int n) {
		float area0 = 0.;
		for (int i = 0 ; i < n ; i++ ) {
			int j = (i+1)%n;
			area0 += points[i].x * points[j].y;
			area0 -= points[i].y * points[j].x;
		}
		return 0.5f * abs(area0);
	}

	void pointsOrdered(CvPoint * points,int n) {
		CvPoint center = getCenter(points,n);
		PointAngle pc[400];
		for (int i = 0 ; i < n ; i++ ) {
			pc[i].p.x = points[i].x;
			pc[i].p.y = points[i].y;
			pc[i].angle = atan2f((float)(points[i].y - center.y),(float)(points[i].x - center.x));
		}
		qsort(pc,n,sizeof(PointAngle),comp_point_with_angle);
		for (int i = 0 ; i < n ; i++ ) {
			points[i].x = pc[i].p.x;
			points[i].y = pc[i].p.y;
		}
	}

	void updateIntersection() {
		for (int j = 0 ; j < 2 ; j++ ) {
			pointsOrdered(&_poly[j][0],(int)_poly[j].size());
		}

		_inter.clear();
		for (size_t i = 0 ; i < _poly[0].size() ;i++) {
			if( pointInPolygon(_poly[0][i],&_poly[1][0],(int)_poly[1].size()) )
				_inter.push_back(_poly[0][i]);
		}

		for (size_t i = 0 ; i < _poly[1].size() ;i++) {
			if( pointInPolygon(_poly[1][i],&_poly[0][0],(int)_poly[0].size()) )
				_inter.push_back(_poly[1][i]);
		}

		for (size_t i = 0 ; i < _poly[0].size() ;i++) {
			CvPoint p0,p1,p2,p3;
			p0 = _poly[0][i];
			p1 = _poly[0][(i+1)%_poly[0].size()];
			for (size_t j = 0 ; j < _poly[1].size() ;j++) {
				p2 = _poly[1][j];
				p3 = _poly[1][(j+1)%_poly[1].size()];
				CvPoint inter;
				if(segementIntersection(p0,p1,p2,p3,&inter)) {
					_inter.push_back(inter);
				}
			}
		}
		if(_inter.size())pointsOrdered(&_inter[0],(int)_inter.size());
	}

	void run() {
		while(true) {
			try {
				paintImage();
			} catch (std::exception &e) {
				printf("Err : %s\n",e.what());
			}
			cvShowImage(title,curr_rgb);
			switch( key = cvWaitKey(30)) {
			case 'r' : initRandom();break;
			case 27  : return ;
			}
		}
	}
};

int main(int argc,char **argv) {
	try {
		UIPolyIntersection ui(1280);
		ui.run();
	} catch (std::exception &e) {
		printf("Err : %s\n",e.what());
	}
	return 1;
}<|endoftext|>


<commit_before>// Copyright (c) 2011 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/ui/webui/downloads_dom_handler.h"

#include <algorithm>
#include <functional>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/fileicon_source.h"
#include "chrome/browser/ui/webui/fileicon_source_cros.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/download/download_item.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/gfx/image/image.h"

namespace {

// Maximum number of downloads to show. TODO(glen): Remove this and instead
// stuff the downloads down the pipe slowly.
static const int kMaxDownloads = 150;

// Sort DownloadItems into descending order by their start time.
class DownloadItemSorter : public std::binary_function<DownloadItem*,
                                                       DownloadItem*,
                                                       bool> {
 public:
  bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
    return lhs->start_time() > rhs->start_time();
  }
};

}  // namespace

class DownloadsDOMHandler::OriginalDownloadManagerObserver
    : public DownloadManager::Observer {
 public:
  explicit OriginalDownloadManagerObserver(
      DownloadManager::Observer* observer,
      Profile* original_profile)
      : observer_(observer) {
    original_profile_download_manager_ = original_profile->GetDownloadManager();
    original_profile_download_manager_->AddObserver(this);
  }

  virtual ~OriginalDownloadManagerObserver() {
    if (original_profile_download_manager_)
      original_profile_download_manager_->RemoveObserver(this);
  }

  // Observer interface.
  virtual void ModelChanged() {
    observer_->ModelChanged();
  }

  virtual void ManagerGoingDown() {
    original_profile_download_manager_ = NULL;
  }

 private:
  // The DownloadsDOMHandler for the off-the-record profile.
  DownloadManager::Observer* observer_;

  // The original profile's download manager.
  DownloadManager* original_profile_download_manager_;
};

DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
    : search_text_(),
      download_manager_(dlm),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  // Create our fileicon data source.
  Profile::FromBrowserContext(dlm->browser_context())->
      GetChromeURLDataManager()->AddDataSource(
#if defined(OS_CHROMEOS)
      new FileIconSourceCros());
#else
      new FileIconSource());
#endif  // OS_CHROMEOS
}

DownloadsDOMHandler::~DownloadsDOMHandler() {
  ClearDownloadItems();
  download_manager_->RemoveObserver(this);
}

// DownloadsDOMHandler, public: -----------------------------------------------

void DownloadsDOMHandler::Init() {
  download_manager_->AddObserver(this);

  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  Profile* original_profile = profile->GetOriginalProfile();
  if (original_profile != profile) {
    original_download_manager_observer_.reset(
        new OriginalDownloadManagerObserver(this, original_profile));
  }
}

void DownloadsDOMHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getDownloads",
      NewCallback(this, &DownloadsDOMHandler::HandleGetDownloads));
  web_ui_->RegisterMessageCallback("openFile",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenFile));

  web_ui_->RegisterMessageCallback("drag",
      NewCallback(this, &DownloadsDOMHandler::HandleDrag));

  web_ui_->RegisterMessageCallback("saveDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleSaveDangerous));
  web_ui_->RegisterMessageCallback("discardDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleDiscardDangerous));
  web_ui_->RegisterMessageCallback("show",
      NewCallback(this, &DownloadsDOMHandler::HandleShow));
  web_ui_->RegisterMessageCallback("togglepause",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("resume",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("remove",
      NewCallback(this, &DownloadsDOMHandler::HandleRemove));
  web_ui_->RegisterMessageCallback("cancel",
      NewCallback(this, &DownloadsDOMHandler::HandleCancel));
  web_ui_->RegisterMessageCallback("clearAll",
      NewCallback(this, &DownloadsDOMHandler::HandleClearAll));
  web_ui_->RegisterMessageCallback("openDownloadsFolder",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenDownloadsFolder));
}

void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
  // Get the id for the download. Our downloads are sorted latest to first,
  // and the id is the index into that list. We should be careful of sync
  // errors between the UI and the download_items_ list (we may wish to use
  // something other than 'id').
  OrderedDownloads::iterator it = find(download_items_.begin(),
                                       download_items_.end(),
                                       download);
  if (it == download_items_.end())
    return;

  if (download->state() == DownloadItem::REMOVING) {
    (*it)->RemoveObserver(this);
    *it = NULL;
    // A later ModelChanged() notification will change the WebUI's
    // view of the downloads list.
    return;
  }

  const int id = static_cast<int>(it - download_items_.begin());

  ListValue results_value;
  results_value.Append(download_util::CreateDownloadItemValue(download, id));
  web_ui_->CallJavascriptFunction("downloadUpdated", results_value);
}

// A download has started or been deleted. Query our DownloadManager for the
// current set of downloads.
void DownloadsDOMHandler::ModelChanged() {
  ClearDownloadItems();
  download_manager_->SearchDownloads(WideToUTF16(search_text_),
                                     &download_items_);
  // If we have a parent profile, let it add its downloads to the results.
  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  if (profile->GetOriginalProfile() != profile) {
    profile->GetOriginalProfile()->GetDownloadManager()->SearchDownloads(
        WideToUTF16(search_text_), &download_items_);
  }

  sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());

  // Remove any extension downloads.
  for (size_t i = 0; i < download_items_.size();) {
    if (ChromeDownloadManagerDelegate::IsExtensionDownload(download_items_[i]))
      download_items_.erase(download_items_.begin() + i);
    else
      i++;
  }

  // Add ourself to all download items as an observer.
  for (OrderedDownloads::iterator it = download_items_.begin();
       it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
      break;

    // TODO(rdsmith): Convert to DCHECK()s when http://crbug.com/84508 is
    // fixed.
    // We should never see anything that isn't already in the history.
    CHECK(*it);
    CHECK_NE(DownloadItem::kUninitializedHandle, (*it)->db_handle());

    (*it)->AddObserver(this);
  }

  SendCurrentDownloads();
}

void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
  std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args));
  if (search_text_.compare(new_search) != 0) {
    search_text_ = new_search;
    ModelChanged();
  } else {
    SendCurrentDownloads();
  }

  download_manager_->CheckForHistoryFilesRemoval();
}

void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->OpenDownload();
}

void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    IconManager* im = g_browser_process->icon_manager();
    gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(),
                                      IconLoader::NORMAL);
    gfx::NativeView view = web_ui_->tab_contents()->GetNativeView();
    {
      // Enable nested tasks during DnD, while |DragDownload()| blocks.
      MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
      download_util::DragDownload(file, icon, view);
    }
  }
}

void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->DangerousDownloadValidated();
}

void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
}

void DownloadsDOMHandler::HandleShow(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->ShowDownloadInShell();
}

void DownloadsDOMHandler::HandlePause(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->TogglePause();
}

void DownloadsDOMHandler::HandleRemove(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    // TODO(rdsmith): Change to DCHECK when http://crbug.com/84508 is fixed.
    CHECK_NE(DownloadItem::kUninitializedHandle, file->db_handle());
    file->Remove();
  }
}

void DownloadsDOMHandler::HandleCancel(const ListValue* args) {
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Cancel(true);
}

void DownloadsDOMHandler::HandleClearAll(const ListValue* args) {
  download_manager_->RemoveAllDownloads();

  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  // If this is an incognito downloader, clear All should clear main download
  // manager as well.
  if (profile->GetOriginalProfile() != profile)
    profile->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads();
}

void DownloadsDOMHandler::HandleOpenDownloadsFolder(const ListValue* args) {
  FilePath path = DownloadPrefs::FromDownloadManager(download_manager_)->
      download_path();

#if defined(OS_MACOSX)
  // Must be called from the UI thread on Mac.
  platform_util::OpenItem(path);
#else
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableFunction(&platform_util::OpenItem, path));
#endif
}

// DownloadsDOMHandler, private: ----------------------------------------------

void DownloadsDOMHandler::SendCurrentDownloads() {
  ListValue results_value;
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    int index = static_cast<int>(it - download_items_.begin());
    if (index > kMaxDownloads)
      break;
    if (!*it)
      continue;
    results_value.Append(download_util::CreateDownloadItemValue(*it, index));
  }

  web_ui_->CallJavascriptFunction("downloadsList", results_value);
}

void DownloadsDOMHandler::ClearDownloadItems() {
  // Clear out old state and remove self as observer for each download.
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    if (!*it)
      continue;
    (*it)->RemoveObserver(this);
  }
  download_items_.clear();
}

DownloadItem* DownloadsDOMHandler::GetDownloadById(int id) {
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin() == id)) {
      return (*it);
    }
  }

  return NULL;
}

DownloadItem* DownloadsDOMHandler::GetDownloadByValue(const ListValue* args) {
  int id;
  if (ExtractIntegerValue(args, &id)) {
    return GetDownloadById(id);
  }
  return NULL;
}
<commit_msg>UMA in DownloadsDOMHandler<commit_after>// Copyright (c) 2011 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/ui/webui/downloads_dom_handler.h"

#include <algorithm>
#include <functional>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram.h"
#include "base/string_piece.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/chrome_download_manager_delegate.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_util.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/browser/ui/webui/fileicon_source.h"
#include "chrome/browser/ui/webui/fileicon_source_cros.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/browser/download/download_item.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "ui/gfx/image/image.h"

namespace {

// Maximum number of downloads to show. TODO(glen): Remove this and instead
// stuff the downloads down the pipe slowly.
static const int kMaxDownloads = 150;

// Sort DownloadItems into descending order by their start time.
class DownloadItemSorter : public std::binary_function<DownloadItem*,
                                                       DownloadItem*,
                                                       bool> {
 public:
  bool operator()(const DownloadItem* lhs, const DownloadItem* rhs) {
    return lhs->start_time() > rhs->start_time();
  }
};

enum DownloadsDOMEvent {
  DOWNLOADS_DOM_EVENT_GET_DOWNLOADS = 0,
  DOWNLOADS_DOM_EVENT_OPEN_FILE = 1,
  DOWNLOADS_DOM_EVENT_DRAG = 2,
  DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS = 3,
  DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS = 4,
  DOWNLOADS_DOM_EVENT_SHOW = 5,
  DOWNLOADS_DOM_EVENT_PAUSE = 6,
  DOWNLOADS_DOM_EVENT_REMOVE = 7,
  DOWNLOADS_DOM_EVENT_CANCEL = 8,
  DOWNLOADS_DOM_EVENT_CLEAR_ALL = 9,
  DOWNLOADS_DOM_EVENT_OPEN_FOLDER = 10,
  DOWNLOADS_DOM_EVENT_MAX
};

void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
  UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
                            event,
                            DOWNLOADS_DOM_EVENT_MAX);
}

}  // namespace

class DownloadsDOMHandler::OriginalDownloadManagerObserver
    : public DownloadManager::Observer {
 public:
  explicit OriginalDownloadManagerObserver(
      DownloadManager::Observer* observer,
      Profile* original_profile)
      : observer_(observer) {
    original_profile_download_manager_ = original_profile->GetDownloadManager();
    original_profile_download_manager_->AddObserver(this);
  }

  virtual ~OriginalDownloadManagerObserver() {
    if (original_profile_download_manager_)
      original_profile_download_manager_->RemoveObserver(this);
  }

  // Observer interface.
  virtual void ModelChanged() {
    observer_->ModelChanged();
  }

  virtual void ManagerGoingDown() {
    original_profile_download_manager_ = NULL;
  }

 private:
  // The DownloadsDOMHandler for the off-the-record profile.
  DownloadManager::Observer* observer_;

  // The original profile's download manager.
  DownloadManager* original_profile_download_manager_;
};

DownloadsDOMHandler::DownloadsDOMHandler(DownloadManager* dlm)
    : search_text_(),
      download_manager_(dlm),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  // Create our fileicon data source.
  Profile::FromBrowserContext(dlm->browser_context())->
      GetChromeURLDataManager()->AddDataSource(
#if defined(OS_CHROMEOS)
      new FileIconSourceCros());
#else
      new FileIconSource());
#endif  // OS_CHROMEOS
}

DownloadsDOMHandler::~DownloadsDOMHandler() {
  ClearDownloadItems();
  download_manager_->RemoveObserver(this);
}

// DownloadsDOMHandler, public: -----------------------------------------------

void DownloadsDOMHandler::Init() {
  download_manager_->AddObserver(this);

  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  Profile* original_profile = profile->GetOriginalProfile();
  if (original_profile != profile) {
    original_download_manager_observer_.reset(
        new OriginalDownloadManagerObserver(this, original_profile));
  }
}

void DownloadsDOMHandler::RegisterMessages() {
  web_ui_->RegisterMessageCallback("getDownloads",
      NewCallback(this, &DownloadsDOMHandler::HandleGetDownloads));
  web_ui_->RegisterMessageCallback("openFile",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenFile));

  web_ui_->RegisterMessageCallback("drag",
      NewCallback(this, &DownloadsDOMHandler::HandleDrag));

  web_ui_->RegisterMessageCallback("saveDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleSaveDangerous));
  web_ui_->RegisterMessageCallback("discardDangerous",
      NewCallback(this, &DownloadsDOMHandler::HandleDiscardDangerous));
  web_ui_->RegisterMessageCallback("show",
      NewCallback(this, &DownloadsDOMHandler::HandleShow));
  web_ui_->RegisterMessageCallback("togglepause",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("resume",
      NewCallback(this, &DownloadsDOMHandler::HandlePause));
  web_ui_->RegisterMessageCallback("remove",
      NewCallback(this, &DownloadsDOMHandler::HandleRemove));
  web_ui_->RegisterMessageCallback("cancel",
      NewCallback(this, &DownloadsDOMHandler::HandleCancel));
  web_ui_->RegisterMessageCallback("clearAll",
      NewCallback(this, &DownloadsDOMHandler::HandleClearAll));
  web_ui_->RegisterMessageCallback("openDownloadsFolder",
      NewCallback(this, &DownloadsDOMHandler::HandleOpenDownloadsFolder));
}

void DownloadsDOMHandler::OnDownloadUpdated(DownloadItem* download) {
  // Get the id for the download. Our downloads are sorted latest to first,
  // and the id is the index into that list. We should be careful of sync
  // errors between the UI and the download_items_ list (we may wish to use
  // something other than 'id').
  OrderedDownloads::iterator it = find(download_items_.begin(),
                                       download_items_.end(),
                                       download);
  if (it == download_items_.end())
    return;

  if (download->state() == DownloadItem::REMOVING) {
    (*it)->RemoveObserver(this);
    *it = NULL;
    // A later ModelChanged() notification will change the WebUI's
    // view of the downloads list.
    return;
  }

  const int id = static_cast<int>(it - download_items_.begin());

  ListValue results_value;
  results_value.Append(download_util::CreateDownloadItemValue(download, id));
  web_ui_->CallJavascriptFunction("downloadUpdated", results_value);
}

// A download has started or been deleted. Query our DownloadManager for the
// current set of downloads.
void DownloadsDOMHandler::ModelChanged() {
  ClearDownloadItems();
  download_manager_->SearchDownloads(WideToUTF16(search_text_),
                                     &download_items_);
  // If we have a parent profile, let it add its downloads to the results.
  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  if (profile->GetOriginalProfile() != profile) {
    profile->GetOriginalProfile()->GetDownloadManager()->SearchDownloads(
        WideToUTF16(search_text_), &download_items_);
  }

  sort(download_items_.begin(), download_items_.end(), DownloadItemSorter());

  // Remove any extension downloads.
  for (size_t i = 0; i < download_items_.size();) {
    if (ChromeDownloadManagerDelegate::IsExtensionDownload(download_items_[i]))
      download_items_.erase(download_items_.begin() + i);
    else
      i++;
  }

  // Add ourself to all download items as an observer.
  for (OrderedDownloads::iterator it = download_items_.begin();
       it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin()) > kMaxDownloads)
      break;

    // TODO(rdsmith): Convert to DCHECK()s when http://crbug.com/84508 is
    // fixed.
    // We should never see anything that isn't already in the history.
    CHECK(*it);
    CHECK_NE(DownloadItem::kUninitializedHandle, (*it)->db_handle());

    (*it)->AddObserver(this);
  }

  SendCurrentDownloads();
}

void DownloadsDOMHandler::HandleGetDownloads(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_GET_DOWNLOADS);
  std::wstring new_search = UTF16ToWideHack(ExtractStringValue(args));
  if (search_text_.compare(new_search) != 0) {
    search_text_ = new_search;
    ModelChanged();
  } else {
    SendCurrentDownloads();
  }

  download_manager_->CheckForHistoryFilesRemoval();
}

void DownloadsDOMHandler::HandleOpenFile(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FILE);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->OpenDownload();
}

void DownloadsDOMHandler::HandleDrag(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DRAG);
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    IconManager* im = g_browser_process->icon_manager();
    gfx::Image* icon = im->LookupIcon(file->GetUserVerifiedFilePath(),
                                      IconLoader::NORMAL);
    gfx::NativeView view = web_ui_->tab_contents()->GetNativeView();
    {
      // Enable nested tasks during DnD, while |DragDownload()| blocks.
      MessageLoop::ScopedNestableTaskAllower allower(MessageLoop::current());
      download_util::DragDownload(file, icon, view);
    }
  }
}

void DownloadsDOMHandler::HandleSaveDangerous(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SAVE_DANGEROUS);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->DangerousDownloadValidated();
}

void DownloadsDOMHandler::HandleDiscardDangerous(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_DISCARD_DANGEROUS);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
}

void DownloadsDOMHandler::HandleShow(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_SHOW);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->ShowDownloadInShell();
}

void DownloadsDOMHandler::HandlePause(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_PAUSE);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->TogglePause();
}

void DownloadsDOMHandler::HandleRemove(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_REMOVE);
  DownloadItem* file = GetDownloadByValue(args);
  if (file) {
    // TODO(rdsmith): Change to DCHECK when http://crbug.com/84508 is fixed.
    CHECK_NE(DownloadItem::kUninitializedHandle, file->db_handle());
    file->Remove();
  }
}

void DownloadsDOMHandler::HandleCancel(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CANCEL);
  DownloadItem* file = GetDownloadByValue(args);
  if (file)
    file->Cancel(true);
}

void DownloadsDOMHandler::HandleClearAll(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_CLEAR_ALL);
  download_manager_->RemoveAllDownloads();

  Profile* profile =
      Profile::FromBrowserContext(download_manager_->browser_context());
  // If this is an incognito downloader, clear All should clear main download
  // manager as well.
  if (profile->GetOriginalProfile() != profile)
    profile->GetOriginalProfile()->GetDownloadManager()->RemoveAllDownloads();
}

void DownloadsDOMHandler::HandleOpenDownloadsFolder(const ListValue* args) {
  CountDownloadsDOMEvents(DOWNLOADS_DOM_EVENT_OPEN_FOLDER);
  FilePath path = DownloadPrefs::FromDownloadManager(download_manager_)->
      download_path();

#if defined(OS_MACOSX)
  // Must be called from the UI thread on Mac.
  platform_util::OpenItem(path);
#else
  BrowserThread::PostTask(
      BrowserThread::FILE, FROM_HERE,
      NewRunnableFunction(&platform_util::OpenItem, path));
#endif
}

// DownloadsDOMHandler, private: ----------------------------------------------

void DownloadsDOMHandler::SendCurrentDownloads() {
  ListValue results_value;
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    int index = static_cast<int>(it - download_items_.begin());
    if (index > kMaxDownloads)
      break;
    if (!*it)
      continue;
    results_value.Append(download_util::CreateDownloadItemValue(*it, index));
  }

  web_ui_->CallJavascriptFunction("downloadsList", results_value);
}

void DownloadsDOMHandler::ClearDownloadItems() {
  // Clear out old state and remove self as observer for each download.
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    if (!*it)
      continue;
    (*it)->RemoveObserver(this);
  }
  download_items_.clear();
}

DownloadItem* DownloadsDOMHandler::GetDownloadById(int id) {
  for (OrderedDownloads::iterator it = download_items_.begin();
      it != download_items_.end(); ++it) {
    if (static_cast<int>(it - download_items_.begin() == id)) {
      return (*it);
    }
  }

  return NULL;
}

DownloadItem* DownloadsDOMHandler::GetDownloadByValue(const ListValue* args) {
  int id;
  if (ExtractIntegerValue(args, &id)) {
    return GetDownloadById(id);
  }
  return NULL;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX
#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX

#include <resourcemodel/LoggedResources.hxx>
#include <boost/shared_ptr.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>

namespace writerfilter
{
namespace dmapper
{

/// Handler for floating table positioning
class TablePositionHandler
    : public LoggedProperties
{
    OUString m_aVertAnchor;
    OUString m_aYSpec;
    OUString m_aHorzAnchor;
    OUString m_aXSpec;
    sal_Int32 m_nY;
    sal_Int32 m_nX;
    sal_Int32 m_nLeftFromText;
    sal_Int32 m_nRightFromText;
    sal_Int32 m_nTopFromText;
    sal_Int32 m_nBottomFromText;

    // Properties
    virtual void lcl_attribute(Id Name, Value& val) SAL_OVERRIDE;
    virtual void lcl_sprm(Sprm& sprm) SAL_OVERRIDE;

public:
    int getY()
    {
        return m_nY;
    }
    int getX()
    {
        return m_nX;
    }
    int getLeftFromText()
    {
        return m_nLeftFromText;
    }
    int getRightFromText()
    {
        return m_nRightFromText;
    }
    int getTopFromText()
    {
        return m_nTopFromText;
    }
    int getBottomFromText()
    {
        return m_nBottomFromText;
    }

    OUString getVertAnchor()
    {
        return m_aVertAnchor;
    }
    OUString getYSpec()
    {
        return m_aYSpec;
    }
    OUString getHorzAnchor()
    {
        return m_aHorzAnchor;
    }
    OUString getXSpec()
    {
        return m_aXSpec;
    }

    TablePositionHandler();
    virtual ~TablePositionHandler();

    /** Compute the UNO properties for the frame containing the table based
        on the received tokens.

        Note that the properties will need to be adjusted with the table
        properties before actually using them.
      */
    com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> getTablePosition() const;

    bool operator== (const TablePositionHandler& rHandler) const;
};

typedef boost::shared_ptr<TablePositionHandler> TablePositionHandlerPtr;
} // namespace dmapper
} // namespace writerfilter

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>writerfilter: try to fix 32-bit builds<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX
#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX

#include <resourcemodel/LoggedResources.hxx>
#include <boost/shared_ptr.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>

namespace writerfilter
{
namespace dmapper
{

/// Handler for floating table positioning
class TablePositionHandler
    : public LoggedProperties
{
    OUString m_aVertAnchor;
    OUString m_aYSpec;
    OUString m_aHorzAnchor;
    OUString m_aXSpec;
    sal_Int32 m_nY;
    sal_Int32 m_nX;
    sal_Int32 m_nLeftFromText;
    sal_Int32 m_nRightFromText;
    sal_Int32 m_nTopFromText;
    sal_Int32 m_nBottomFromText;

    // Properties
    virtual void lcl_attribute(Id Name, Value& val) SAL_OVERRIDE;
    virtual void lcl_sprm(Sprm& sprm) SAL_OVERRIDE;

public:
    sal_Int32 getY()
    {
        return m_nY;
    }
    sal_Int32 getX()
    {
        return m_nX;
    }
    sal_Int32 getLeftFromText()
    {
        return m_nLeftFromText;
    }
    sal_Int32 getRightFromText()
    {
        return m_nRightFromText;
    }
    sal_Int32 getTopFromText()
    {
        return m_nTopFromText;
    }
    sal_Int32 getBottomFromText()
    {
        return m_nBottomFromText;
    }

    OUString getVertAnchor()
    {
        return m_aVertAnchor;
    }
    OUString getYSpec()
    {
        return m_aYSpec;
    }
    OUString getHorzAnchor()
    {
        return m_aHorzAnchor;
    }
    OUString getXSpec()
    {
        return m_aXSpec;
    }

    TablePositionHandler();
    virtual ~TablePositionHandler();

    /** Compute the UNO properties for the frame containing the table based
        on the received tokens.

        Note that the properties will need to be adjusted with the table
        properties before actually using them.
      */
    com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> getTablePosition() const;

    bool operator== (const TablePositionHandler& rHandler) const;
};

typedef boost::shared_ptr<TablePositionHandler> TablePositionHandlerPtr;
} // namespace dmapper
} // namespace writerfilter

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>