summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authormad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 00:37:31 +0000
committermad@chromium.org <mad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-03 00:37:31 +0000
commit1c1c77a5021be0b902240a4f78009a8d8f71d1ac (patch)
treec1afb46b67de923afaac68340ddb0113b7306193 /chrome/renderer
parent23b3f6c67270a6aff5020c9a7279f4ed84192a02 (diff)
downloadchromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.zip
chromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.tar.gz
chromium_src-1c1c77a5021be0b902240a4f78009a8d8f71d1ac.tar.bz2
Submitting change from http://codereview.chromium.org/276029/show
BUG=none TEST=none git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30778 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc92
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js93
2 files changed, 171 insertions, 14 deletions
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index 2a69afd..fee736a 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -102,6 +102,9 @@ static L10nMessagesMap* GetL10nMessagesMap(const std::string extension_id) {
}
}
+// A RenderViewVisitor class that iterates through the set of available
+// views, looking for a view of the given type, in the given browser window
+// and within the given extension.
// Used to accumulate the list of views associated with an extension.
class ExtensionViewAccumulator : public RenderViewVisitor {
public:
@@ -115,6 +118,8 @@ class ExtensionViewAccumulator : public RenderViewVisitor {
index_(0) {
}
+ v8::Local<v8::Array> views() { return views_; }
+
virtual bool Visit(RenderView* render_view) {
if (!ViewTypeMatches(render_view->view_type(), view_type_))
return true;
@@ -135,17 +140,26 @@ class ExtensionViewAccumulator : public RenderViewVisitor {
if (!context.IsEmpty()) {
v8::Local<v8::Value> window = context->Global();
DCHECK(!window.IsEmpty());
- views_->Set(v8::Integer::New(index_), window);
- index_++;
- if (view_type_ == ViewType::EXTENSION_BACKGROUND_PAGE)
- return false; // There can be only one...
+
+ if (!OnMatchedView(window))
+ return false;
}
return true;
}
- v8::Local<v8::Array> views() { return views_; }
-
private:
+ // Called on each view found matching the search criteria. Returns false
+ // to terminate the iteration.
+ bool OnMatchedView(const v8::Local<v8::Value>& view_window) {
+ views_->Set(v8::Integer::New(index_), view_window);
+ index_++;
+
+ if (view_type_ == ViewType::EXTENSION_BACKGROUND_PAGE)
+ return false; // There can be only one...
+
+ return true;
+ }
+
// Returns true is |type| "isa" |match|.
static bool ViewTypeMatches(ViewType::Type type, ViewType::Type match) {
if (type == match)
@@ -215,6 +229,10 @@ class ExtensionImpl : public ExtensionBase {
return v8::FunctionTemplate::New(GetRenderViewId);
} else if (name->Equals(v8::String::New("GetL10nMessage"))) {
return v8::FunctionTemplate::New(GetL10nMessage);
+ } else if (name->Equals(v8::String::New("GetPopupView"))) {
+ return v8::FunctionTemplate::New(GetPopupView);
+ } else if (name->Equals(v8::String::New("GetPopupAnchorView"))) {
+ return v8::FunctionTemplate::New(GetPopupAnchorView);
} else if (name->Equals(v8::String::New("SetExtensionActionIcon"))) {
return v8::FunctionTemplate::New(SetExtensionActionIcon);
}
@@ -228,6 +246,53 @@ class ExtensionImpl : public ExtensionBase {
return v8::String::New(GetStringResource<IDR_EXTENSION_API_JSON>());
}
+ static v8::Handle<v8::Value> PopupViewFinder(
+ const v8::Arguments& args,
+ ViewType::Type viewtype_to_find) {
+ // TODO(twiz) Correct the logic that ties the ownership of the pop-up view
+ // to the hosting view. At the moment we assume that there may only be
+ // a single pop-up view for a given extension. By doing so, we can find
+ // the pop-up view by simply searching for the only pop-up view present.
+ // We also assume that if the current view is a pop-up, we can find the
+ // hosting view by searching for a TOOLSTRIP view.
+ if (args.Length() != 0)
+ return v8::Undefined();
+
+ if (viewtype_to_find != ViewType::EXTENSION_POPUP &&
+ viewtype_to_find != ViewType::EXTENSION_TOOLSTRIP) {
+ NOTREACHED() << L"Requesting invalid view type.";
+ }
+
+ // Disallow searching for a host view if we are a popup view, and likewise
+ // if we are a toolstrip view.
+ RenderView* render_view = bindings_utils::GetRenderViewForCurrentContext();
+ if (!render_view ||
+ render_view->view_type() == viewtype_to_find) {
+ return v8::Undefined();
+ }
+
+ int browser_window_id = render_view->browser_window_id();
+ ExtensionViewAccumulator popup_matcher(ExtensionIdForCurrentContext(),
+ browser_window_id,
+ viewtype_to_find);
+ RenderView::ForEach(&popup_matcher);
+
+ if (0 == popup_matcher.views()->Length())
+ return v8::Undefined();
+ DCHECK(popup_matcher.views()->Has(0));
+
+ // Return the first view found.
+ return popup_matcher.views()->Get(v8::Integer::New(0));
+ }
+
+ static v8::Handle<v8::Value> GetPopupView(const v8::Arguments& args) {
+ return PopupViewFinder(args, ViewType::EXTENSION_POPUP);
+ }
+
+ static v8::Handle<v8::Value> GetPopupAnchorView(const v8::Arguments& args) {
+ return PopupViewFinder(args, ViewType::EXTENSION_TOOLSTRIP);
+ }
+
static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args) {
if (args.Length() != 2)
return v8::Undefined();
@@ -242,15 +307,17 @@ class ExtensionImpl : public ExtensionBase {
std::string view_type_string = *v8::String::Utf8Value(args[1]->ToString());
// |view_type| == ViewType::INVALID means getting any type of views.
ViewType::Type view_type = ViewType::INVALID;
- if (view_type_string == "TOOLSTRIP") {
+ if (view_type_string == ViewType::kToolstrip) {
view_type = ViewType::EXTENSION_TOOLSTRIP;
- } else if (view_type_string == "MOLE") {
+ } else if (view_type_string == ViewType::kMole) {
view_type = ViewType::EXTENSION_MOLE;
- } else if (view_type_string == "BACKGROUND") {
+ } else if (view_type_string == ViewType::kBackgroundPage) {
view_type = ViewType::EXTENSION_BACKGROUND_PAGE;
- } else if (view_type_string == "TAB") {
+ } else if (view_type_string == ViewType::kTabContents) {
view_type = ViewType::TAB_CONTENTS;
- } else if (view_type_string != "ALL") {
+ } else if (view_type_string == ViewType::kPopup) {
+ view_type = ViewType::EXTENSION_POPUP;
+ } else if (view_type_string != ViewType::kAll) {
return v8::Undefined();
}
@@ -414,7 +481,8 @@ class ExtensionImpl : public ExtensionBase {
// A special request for setting the extension action icon. This function
// accepts a canvas ImageData object, so it needs to do extra processing
// before sending the request to the browser.
- static v8::Handle<v8::Value> SetExtensionActionIcon(const v8::Arguments& args) {
+ static v8::Handle<v8::Value> SetExtensionActionIcon(
+ const v8::Arguments& args) {
v8::Local<v8::Object> details = args[1]->ToObject();
v8::Local<v8::Object> image_data =
details->Get(v8::String::New("imageData"))->ToObject();
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 3d3fb88..6a0584b 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -16,6 +16,8 @@ var chrome = chrome || {};
native function OpenChannelToTab();
native function GetRenderViewId();
native function GetL10nMessage();
+ native function GetPopupAnchorView();
+ native function GetPopupView();
native function SetExtensionActionIcon();
if (!chrome)
@@ -187,6 +189,48 @@ var chrome = chrome || {};
};
}
+ // Helper function for positioning pop-up windows relative to DOM objects.
+ // Returns the absolute position of the given element relative to the hosting
+ // browser frame.
+ function findAbsolutePosition(domElement) {
+ var curleft = curtop = 0;
+ var parentNode = domElement.parentNode
+
+ // Ascend through the parent hierarchy, taking into account object nesting
+ // and scoll positions.
+ if (domElement.offsetParent) {
+ do {
+ if (domElement.offsetLeft) curleft += domElement.offsetLeft;
+ if (domElement.offsetTop) curtop += domElement.offsetTop;
+
+ if (domElement.scrollLeft) curleft -= domElement.scrollLeft;
+ if (domElement.scrollTop) curtop -= domElement.scrollTop;
+
+ if (parentNode != domElement.offsetParent) {
+ while(parentNode != null && parentNode != domElement.offsetParent) {
+ if (parentNode.scrollLeft) curleft -= parentNode.scrollLeft;
+ if (parentNode.scrollTop) curtop -= parentNode.scrollTop;
+ parentNode = parentNode.parentNode;
+ }
+ }
+ } while ((domElement = domElement.offsetParent) != null);
+ }
+
+ return {
+ top: curtop,
+ left: curleft
+ };
+ }
+
+ // Returns the coordiates of the rectangle encompassing the domElement,
+ // in browser coordinates relative to the frame hosting the element.
+ function getAbsoluteRect(domElement) {
+ var rect = findAbsolutePosition(domElement);
+ rect.width = domElement.width || 0;
+ rect.height = domElement.height || 0;
+ return rect;
+ }
+
// --- Setup additional api's not currently handled in common/extensions/api
// Page action events send (pageActionId, {tabId, tabUrl}).
@@ -221,6 +265,12 @@ var chrome = chrome || {};
new chrome.Event("toolstrip.onCollapsed." + renderViewId);
}
+ function setupPopupEvents(renderViewId) {
+ chrome.experimental.popup = chrome.experimental.popup || {};
+ chrome.experimental.popup.onClosed =
+ new chrome.Event("experimental.popup.onClosed." + renderViewId);
+ }
+
chromeHidden.onLoad.addListener(function (extensionId) {
chrome.initExtension(extensionId);
@@ -266,13 +316,23 @@ var chrome = chrome || {};
apiFunctions[apiFunction.name] = apiFunction;
module[functionDef.name] = bind(apiFunction, function() {
- chromeHidden.validate(arguments, this.definition.parameters);
+ // If the function is marked with a custom handler, then bypass
+ // validation of the arguments. This flag is required for
+ // extensions taking DOM objects as arguments. DOM objects
+ // cannot be described using the type system in extension_api.json,
+ // and so cannot be validated.
+ // A good practice is to extract the primitive data needed to
+ // service the request, and then invoke validate against that data.
+ // See popup.show(...) for an example.
+ if (!functionDef.customHandler) {
+ chromeHidden.validate(arguments, this.definition.parameters);
+ }
if (this.handleRequest)
return this.handleRequest.apply(this, arguments);
else
return sendRequest(this.name, arguments,
- this.definition.parameters);
+ this.definition.parameters);
});
});
}
@@ -358,6 +418,34 @@ var chrome = chrome || {};
return GetL10nMessage(message_name, placeholders);
}
+ apiFunctions["experimental.popup.show"].handleRequest =
+ function(url, showDetails, callback) {
+ if (!showDetails || !showDetails.relativeTo) {
+ throw new Error("showDetails.relativeTo argument missing.");
+ }
+
+ var position = getAbsoluteRect(showDetails.relativeTo);
+ var popUpInfo = {
+ "url": url
+ };
+ var domAnchor = position;
+ var modifiedArgs = [popUpInfo, domAnchor, callback];
+ chromeHidden.validate(modifiedArgs, this.definition.parameters);
+
+ return sendRequest(this.name, modifiedArgs,
+ this.definition.parameters);
+ }
+
+ apiFunctions["experimental.extension.getPopupView"].handleRequest =
+ function() {
+ return GetPopupView();
+ }
+
+ apiFunctions["experimental.popup.getAnchorWindow"].handleRequest =
+ function() {
+ return GetPopupAnchorView();
+ }
+
var canvas;
function setIconCommon(details, name, parameters) {
var EXTENSION_ACTION_ICON_SIZE = 19;
@@ -425,6 +513,7 @@ var chrome = chrome || {};
setupBrowserActionEvent(extensionId);
setupPageActionEvents(extensionId);
setupToolstripEvents(GetRenderViewId());
+ setupPopupEvents(GetRenderViewId());
});
if (!chrome.experimental)