Bug 760802 - Add JS nativeHandler attribute for nsIBaseWindow. r=roc
authorfoudfou <foudil.newbie+bugzilla.mozilla.org@gmail.com>
Tue, 24 Jul 2012 21:35:32 -0400
changeset 100367 9dcd7470dc0b8c887abc202c73ff5df98f0f7423
parent 100366 063027b49a09e61b069cf313d2ed497056f3e15d
child 100368 1c521e0a117e76b9e2f8983931e5f3f3965ecaec
push id955
push userprouget@mozilla.com
push dateWed, 25 Jul 2012 22:08:50 +0000
treeherderfx-team@7065b767f30d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs760802
milestone17.0a1
Bug 760802 - Add JS nativeHandler attribute for nsIBaseWindow. r=roc
docshell/base/nsDocShell.cpp
embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
embedding/browser/webBrowser/nsWebBrowser.cpp
widget/nsIBaseWindow.idl
widget/tests/Makefile.in
widget/tests/test_bug760802.html
xpfe/appshell/src/nsChromeTreeOwner.cpp
xpfe/appshell/src/nsContentTreeOwner.cpp
xpfe/appshell/src/nsXULWindow.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4897,16 +4897,23 @@ nsDocShell::GetParentNativeWindow(native
 
 NS_IMETHODIMP
 nsDocShell::SetParentNativeWindow(nativeWindow parentNativeWindow)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
+nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
+{
+    // the nativeHandle should be accessed from nsIXULWindow
+    return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDocShell::GetVisibility(bool * aVisibility)
 {
     NS_ENSURE_ARG_POINTER(aVisibility);
 
     *aVisibility = false;
 
     if (!mContentViewer)
         return NS_OK;
--- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp
@@ -579,16 +579,23 @@ nsDocShellTreeOwner::GetParentNativeWind
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 {
   return NS_ERROR_NULL_POINTER;
 }
 
 NS_IMETHODIMP
+nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle)
+{
+  // the nativeHandle should be accessed from nsIXULWindow
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDocShellTreeOwner::GetVisibility(bool* aVisibility)
 {
   nsCOMPtr<nsIEmbeddingSiteWindow> ownerWin = GetOwnerWin();
   if (ownerWin)
   {
     return ownerWin->GetVisibility(aVisibility);
   }
   return NS_ERROR_NULL_POINTER;
--- a/embedding/browser/webBrowser/nsWebBrowser.cpp
+++ b/embedding/browser/webBrowser/nsWebBrowser.cpp
@@ -1373,16 +1373,22 @@ NS_IMETHODIMP nsWebBrowser::SetParentNat
 {
    NS_ENSURE_STATE(!mDocShell);
 
    mParentNativeWindow = aParentNativeWindow;
 
    return NS_OK;
 }
 
+NS_IMETHODIMP nsWebBrowser::GetNativeHandle(nsAString& aNativeHandle)
+{
+   // the nativeHandle should be accessed from nsIXULWindow
+   return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 NS_IMETHODIMP nsWebBrowser::GetVisibility(bool* visibility)
 {
    NS_ENSURE_ARG_POINTER(visibility);
 
    if(!mDocShell)
       *visibility = mInitInfo->visible;
    else
       NS_ENSURE_SUCCESS(mDocShellAsWin->GetVisibility(visibility), NS_ERROR_FAILURE);
--- a/widget/nsIBaseWindow.idl
+++ b/widget/nsIBaseWindow.idl
@@ -148,16 +148,27 @@ interface nsIBaseWindow : nsISupports
 	implementations.
 
 	On controls that don't support setting nativeWindow parents, setting this
 	will return a NS_ERROR_NOT_IMPLEMENTED error.
 	*/
 	attribute nativeWindow parentNativeWindow;
 
 	/*
+	This is the handle (HWND, GdkWindow*, ...) to the native window of the
+	control, exposed as a DOMString.
+
+	@return DOMString in hex format with "0x" prepended, or empty string if
+	mainWidget undefined
+
+	@throws NS_ERROR_NOT_IMPLEMENTED for non-XULWindows
+	*/
+	readonly attribute DOMString nativeHandle;
+
+	/*
 	Attribute controls the visibility of the object behind this interface.
 	Setting this attribute to false will hide the control.  Setting it to 
 	true will show it.
 	*/
 	attribute boolean visibility;
 
     /*
     a disabled window should accept no user interaction; it's a dead window,
--- a/widget/tests/Makefile.in
+++ b/widget/tests/Makefile.in
@@ -25,16 +25,19 @@ endif
 # Test disabled because it requires the internal API.  Re-enabling this test is
 # bug 652123.
 #CPP_UNIT_TESTS += TestChromeMargin.cpp  \
 #                 $(NULL)
 endif
 
 CPP_UNIT_TESTS += TestAppShellSteadyState.cpp
 
+MOCHITEST_FILES =	test_bug760802.html \
+		$(NULL)
+
 MOCHITEST_CHROME_FILES =	test_bug343416.xul \
 		test_bug429954.xul \
 		window_bug429954.xul \
 		test_bug444800.xul \
 		test_bug462106.xul \
 		test_bug478536.xul \
 		window_bug478536.xul \
 		test_bug517396.xul \
@@ -87,21 +90,21 @@ MOCHITEST_CHROME_FILES  += taskbar_previ
 		taskbar_progress.xul \
 		test_chrome_context_menus_win.xul \
 		test_plugin_input_event.html \
 		chrome_context_menus_win.xul \
 		test_mouse_scroll.xul \
 		window_mouse_scroll_win.html \
 		$(NULL)
 
-MOCHITEST_FILES =	test_bug565392.html \
+MOCHITEST_FILES +=	test_bug565392.html \
 		test_picker_no_crash.html \
 		window_picker_no_crash_child.html \
 		$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
-MOCHITEST_FILES = 	plugin_scroll_invalidation.html \
+MOCHITEST_FILES += 	plugin_scroll_invalidation.html \
 		test_plugin_scroll_invalidation.html \
 		$(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/widget/tests/test_bug760802.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=760802
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 760802</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=760802">Mozilla Bug 760802</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<iframe id="iframe_not_editable" width="300" height="150"
+        src="data:text/html,&lt;html&gt;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;"></iframe><br/>
+<pre id="test">
+<script type="application/javascript">
+
+netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function getBaseWindowInterface(win) {
+  return win.QueryInterface(Ci.nsIInterfaceRequestor)
+    .getInterface(Ci.nsIWebNavigation)
+    .QueryInterface(Ci.nsIDocShellTreeItem)
+    .treeOwner
+    .QueryInterface(Ci.nsIInterfaceRequestor)
+    .nsIBaseWindow;
+}
+
+function shouldThrow(fun) {
+  try {
+    fun.call();
+    return false;
+  } catch (e) {
+    return true;
+  }
+}
+function doesntThrow(fun) !shouldThrow(fun)
+
+
+var baseWindow = getBaseWindowInterface(window);
+var nativeHandle = baseWindow.nativeHandle;
+$("display").innerHTML = "found nativeHandle for this window: "+nativeHandle;
+
+var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+var win = wm.getMostRecentWindow("navigator:browser");
+var docShell = win.gBrowser.docShell;
+
+ok(
+  shouldThrow(function(){docShell.getInterface(Ci.nsIBaseWindow).nativeHandle;}),
+  "nativeHandle should not be implemented for nsDocShell"
+);
+
+ok(typeof(nativeHandle) === "string", "nativeHandle should be a string");
+ok(nativeHandle.match(/^0x[0-9a-f]+$/), "nativeHandle should have a memory address format");
+
+var iWin = window.document.getElementById("iframe_not_editable").contentWindow;
+is(getBaseWindowInterface(iWin).nativeHandle, nativeHandle,
+              "the nativeHandle of an iframe should be its parent's nativeHandle");
+
+var dialog = window.openDialog("data:text/plain,this is an active window.", "_blank",
+                               "chrome,dialog=yes,width=100,height=100");
+
+isnot(getBaseWindowInterface(dialog).nativeHandle, "",
+      "the nativeHandle of a dialog should not be empty");
+
+dialog.close();
+
+todo(false, "the nativeHandle of a window without a mainWidget should be empty"); // how to build a window without a mainWidget ?
+
+</script>
+</pre>
+</body>
+</html>
--- a/xpfe/appshell/src/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/src/nsChromeTreeOwner.cpp
@@ -413,16 +413,22 @@ NS_IMETHODIMP nsChromeTreeOwner::GetPare
 }
 
 NS_IMETHODIMP nsChromeTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 {
    NS_ASSERTION(false, "You can't call this");
    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP nsChromeTreeOwner::GetNativeHandle(nsAString& aNativeHandle)
+{
+   NS_ENSURE_STATE(mXULWindow);
+   return mXULWindow->GetNativeHandle(aNativeHandle);
+}
+
 NS_IMETHODIMP nsChromeTreeOwner::GetVisibility(bool* aVisibility)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetVisibility(aVisibility);
 }
 
 NS_IMETHODIMP nsChromeTreeOwner::SetVisibility(bool aVisibility)
 {
--- a/xpfe/appshell/src/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/src/nsContentTreeOwner.cpp
@@ -630,16 +630,22 @@ NS_IMETHODIMP nsContentTreeOwner::GetPar
 }
 
 NS_IMETHODIMP nsContentTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 {
    NS_ASSERTION(false, "You can't call this");
    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP nsContentTreeOwner::GetNativeHandle(nsAString& aNativeHandle)
+{
+   NS_ENSURE_STATE(mXULWindow);
+   return mXULWindow->GetNativeHandle(aNativeHandle);
+}
+
 NS_IMETHODIMP nsContentTreeOwner::GetVisibility(bool* aVisibility)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->GetVisibility(aVisibility);
 }
 
 NS_IMETHODIMP nsContentTreeOwner::SetVisibility(bool aVisibility)
 {
--- a/xpfe/appshell/src/nsXULWindow.cpp
+++ b/xpfe/appshell/src/nsXULWindow.cpp
@@ -3,16 +3,17 @@
 /* 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/. */
 
 // Local includes
 #include "nsXULWindow.h"
 
 // Helper classes
+#include "nsPrintfCString.h"
 #include "nsString.h"
 #include "nsWidgetsCID.h"
 #include "prprf.h"
 #include "nsCRT.h"
 #include "nsThreadUtils.h"
 #include "nsNetCID.h"
 
 //Interfaces needed to be included
@@ -733,16 +734,32 @@ NS_IMETHODIMP nsXULWindow::GetParentNati
 
 NS_IMETHODIMP nsXULWindow::SetParentNativeWindow(nativeWindow aParentNativeWindow)
 {
   //XXX First Check In
   NS_ASSERTION(false, "Not Yet Implemented");
   return NS_OK;
 }
 
+NS_IMETHODIMP nsXULWindow::GetNativeHandle(nsAString& aNativeHandle)
+{
+  nsCOMPtr<nsIWidget> mainWidget;
+  NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(mainWidget)), NS_ERROR_FAILURE);
+
+  if (mainWidget) {
+    nativeWindow nativeWindowPtr = mainWidget->GetNativeData(NS_NATIVE_WINDOW);
+    /* the nativeWindow pointer is converted to and exposed as a string. This
+       is a more reliable way not to lose information (as opposed to JS
+       |Number| for instance) */
+    aNativeHandle = NS_ConvertASCIItoUTF16(nsPrintfCString("0x%p", nativeWindowPtr));
+  }
+
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsXULWindow::GetVisibility(bool* aVisibility)
 {
   NS_ENSURE_ARG_POINTER(aVisibility);
 
   // Always claim to be visible for now. See bug
   // https://bugzilla.mozilla.org/show_bug.cgi?id=306245.
 
   *aVisibility = true;