Bug 807222 part 6. Fix getOwnPropertyNames to work correctly on Window. r=jst
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 01 Nov 2012 13:51:57 -0400
changeset 112387 3c8992f602ddb4dd3e05a6325c1adb446f062d09
parent 112386 d9110621e468a1e3263038898dd4e3e33d11dd23
child 112388 8f5204fb76c86b08a54aad5a6e1f423c5415de9f
push id23812
push useremorley@mozilla.com
push dateTue, 06 Nov 2012 14:01:34 +0000
treeherdermozilla-central@f4aeed115e54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs807222
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 807222 part 6. Fix getOwnPropertyNames to work correctly on Window. r=jst One note: it might be better to change the signature of Enumerate() to indicate whether we're enumerating just the enumerable properties or all of them, so we can skip doing this when someone does for...in on the window.
browser/devtools/webconsole/test/browser_webconsole_completion.js
dom/base/nsDOMClassInfo.cpp
dom/base/nsScriptNameSpaceManager.cpp
dom/base/nsScriptNameSpaceManager.h
dom/base/test/Makefile.in
dom/base/test/test_window_enumeration.html
--- a/browser/devtools/webconsole/test/browser_webconsole_completion.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_completion.js
@@ -45,23 +45,24 @@ function testCompletion(hud) {
   jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
   yield;
 
   is(input.value, "document", "'docu' tab completion");
   is(input.selectionStart, 8, "start selection is alright");
   is(input.selectionEnd, 8, "end selection is alright");
   is(jsterm.completeNode.value.replace(/ /g, ""), "", "'docu' completed");
 
-  // Test typing 'window.O' and press tab.
-  input.value = "window.O";
-  input.setSelectionRange(8, 8);
+  // Test typing 'window.Ob' and press tab.  Just 'window.O' is
+  // ambiguous: could be window.Object, window.Option, etc.
+  input.value = "window.Ob";
+  input.setSelectionRange(9, 9);
   jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
   yield;
 
-  is(input.value, "window.Object", "'window.O' tab completion");
+  is(input.value, "window.Object", "'window.Ob' tab completion");
 
   // Test typing 'document.getElem'.
   input.value = "document.getElem";
   input.setSelectionRange(16, 16);
   jsterm.complete(jsterm.COMPLETE_FORWARD, testNext);
   yield;
 
   is(input.value, "document.getElem", "'document.getElem' completion");
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5588,22 +5588,58 @@ nsWindowSH::GetProperty(nsIXPConnectWrap
     obj = JS_ObjectToOuterObject(cx, obj);
     *vp = OBJECT_TO_JSVAL(obj);
     return NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return NS_OK;
 }
 
+struct ResolveGlobalNameClosure
+{
+  JSContext* cx;
+  JSObject* obj;
+  bool* retval;
+};
+
+static PLDHashOperator
+ResolveGlobalName(const nsAString& aName, void* aClosure)
+{
+  ResolveGlobalNameClosure* closure =
+    static_cast<ResolveGlobalNameClosure*>(aClosure);
+  JS::Value dummy;
+  bool ok = JS_LookupUCProperty(closure->cx, closure->obj,
+                                aName.BeginReading(), aName.Length(),
+                                &dummy);
+  if (!ok) {
+    *closure->retval = false;
+    return PL_DHASH_STOP;
+  }
+  return PL_DHASH_NEXT;
+}
+
 NS_IMETHODIMP
 nsWindowSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                       JSObject *obj, bool *_retval)
 {
   if (!ObjectIsNativeWrapper(cx, obj)) {
     *_retval = JS_EnumerateStandardClasses(cx, obj);
+    if (!*_retval) {
+      return NS_OK;
+    }
+
+    // Now resolve everything from the namespace manager
+    nsScriptNameSpaceManager *nameSpaceManager =
+      nsJSRuntime::GetNameSpaceManager();
+    if (!nameSpaceManager) {
+      NS_ERROR("Can't get namespace manager.");
+      return NS_ERROR_UNEXPECTED;
+    }
+    ResolveGlobalNameClosure closure = { cx, obj, _retval };
+    nameSpaceManager->EnumerateGlobalNames(ResolveGlobalName, &closure);
   }
 
   return NS_OK;
 }
 
 static nsDOMConstructorFunc
 FindConstructorFunc(const nsDOMClassInfoData *aDOMClassInfoData)
 {
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -797,16 +797,39 @@ nsScriptNameSpaceManager::RegisterDefine
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mDefineDOMInterface = aDefineDOMInterface;
     s->mPrefEnabled = aPrefEnabled;
   }
 }
 
+struct GlobalNameClosure
+{
+  nsScriptNameSpaceManager::GlobalNameEnumerator enumerator;
+  void* closure;
+};
+
+static PLDHashOperator
+EnumerateGlobalName(PLDHashTable*, PLDHashEntryHdr *hdr, uint32_t,
+                    void* aClosure)
+{
+  GlobalNameMapEntry *entry = static_cast<GlobalNameMapEntry *>(hdr);
+  GlobalNameClosure* closure = static_cast<GlobalNameClosure*>(aClosure);
+  return closure->enumerator(entry->mKey, closure->closure);
+}
+
+void
+nsScriptNameSpaceManager::EnumerateGlobalNames(GlobalNameEnumerator aEnumerator,
+                                               void* aClosure)
+{
+  GlobalNameClosure closure = { aEnumerator, aClosure };
+  PL_DHashTableEnumerate(&mGlobalNames, EnumerateGlobalName, &closure);
+}
+
 static size_t
 SizeOfEntryExcludingThis(PLDHashEntryHdr *aHdr, nsMallocSizeOfFun aMallocSizeOf,
                          void *aArg)
 {
     GlobalNameMapEntry* entry = static_cast<GlobalNameMapEntry*>(aHdr);
     return entry->SizeOfExcludingThis(aMallocSizeOf);
 }
 
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -138,16 +138,22 @@ public:
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
   void RegisterDefineDOMInterface(const nsAFlatString& aName,
     mozilla::dom::DefineInterface aDefineDOMInterface,
     mozilla::dom::PrefEnabled aPrefEnabled);
 
+  typedef PLDHashOperator
+  (* GlobalNameEnumerator)(const nsAString& aGlobalName, void* aClosure);
+
+  void EnumerateGlobalNames(GlobalNameEnumerator aEnumerator,
+                            void* aClosure);
+
   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
--- a/dom/base/test/Makefile.in
+++ b/dom/base/test/Makefile.in
@@ -12,16 +12,17 @@ include $(DEPTH)/config/autoconf.mk
 
 MOCHITEST_FILES = \
   test_domrequest.html \
   test_gsp-standards.html \
   test_gsp-quirks.html \
   test_gsp-qualified.html \
   test_nondomexception.html \
   test_screen_orientation.html \
+  test_window_enumeration.html \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
    test_bug715041.xul \
    test_bug715041_removal.xul \
    $(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_window_enumeration.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=807222
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 807222</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=807222">Mozilla Bug 807222</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 807222 **/
+var expectedProps = [ "Image", "Audio", "Option", "USSDReceivedEvent",
+                      "PerformanceTiming", "CSS2Properties", "SVGElement" ];
+var actualProps = Object.getOwnPropertyNames(window);
+
+for (var i = 0; i < expectedProps.length; ++i) {
+  isnot(actualProps.indexOf(expectedProps[i]), -1,
+        "getOwnPropertyNames should include " + expectedProps[i]);
+}
+</script>
+</pre>
+</body>
+</html>