Bug 883002 - Add opensearch support to the mozbrowser API r=jlebar
authorFabrice Desré <fabrice@mozilla.com>
Sat, 20 Jul 2013 09:47:47 -0700
changeset 151689 5dfb22ea0888ef74eec1ccacf9babbfc6dd7fc98
parent 151688 4289e7eb182608209617480bff50360e4e4b49f4
child 151690 3e4af5448ba526f50581318c6d333b48891790f3
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs883002
milestone25.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 883002 - Add opensearch support to the mozbrowser API r=jlebar
dom/browser-element/BrowserElementChildPreload.js
dom/browser-element/BrowserElementParent.jsm
dom/browser-element/mochitest/Makefile.in
dom/browser-element/mochitest/browserElement_Opensearch.js
dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html
dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html
--- a/dom/browser-element/BrowserElementChildPreload.js
+++ b/dom/browser-element/BrowserElementChildPreload.js
@@ -166,17 +166,17 @@ BrowserElementChild.prototype = {
     this._shuttingDown = false;
 
     addEventListener('DOMTitleChanged',
                      this._titleChangedHandler.bind(this),
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
 
     addEventListener('DOMLinkAdded',
-                     this._iconChangedHandler.bind(this),
+                     this._linkAddedHandler.bind(this),
                      /* useCapture = */ true,
                      /* wantsUntrusted = */ false);
 
     // This listens to unload events from our message manager, but /not/ from
     // the |content| window.  That's because the window's unload event doesn't
     // bubble, and we're not using a capturing listener.  If we'd used
     // useCapture == true, we /would/ hear unload events from the window, which
     // is not what we want!
@@ -442,32 +442,55 @@ BrowserElementChild.prototype = {
       sendAsyncMsg('titlechange', { _payload_: e.target.title });
     }
     else {
       debug("Not top level!");
     }
   },
 
   _iconChangedHandler: function(e) {
-    debug("Got iconchanged: (" + e.target.href + ")");
-    var hasIcon = e.target.rel.split(' ').some(function(x) {
-      return x.toLowerCase() === 'icon';
-    });
+    debug('Got iconchanged: (' + e.target.href + ')');
+
+    sendAsyncMsg('iconchange', { _payload_: e.target.href });
+  },
+
+  _openSearchHandler: function(e) {
+    debug('Got opensearch: (' + e.target.href + ')');
+
+    if (e.target.type !== "application/opensearchdescription+xml") {
+      return;
+    }
+
+    sendAsyncMsg('opensearch', { title: e.target.title,
+                                 href: e.target.href });
+
+  },
 
-    if (hasIcon) {
-      var win = e.target.ownerDocument.defaultView;
-      // Ignore iconchanges which don't come from the top-level
-      // <iframe mozbrowser> window.
-      if (win == content) {
-        sendAsyncMsg('iconchange', { _payload_: e.target.href });
+  // Processes the "rel" field in <link> tags and forward to specific handlers.
+  _linkAddedHandler: function(e) {
+    let win = e.target.ownerDocument.defaultView;
+    // Ignore links which don't come from the top-level
+    // <iframe mozbrowser> window.
+    if (win != content) {
+      debug('Not top level!');
+      return;
+    }
+
+    let handlers = {
+      'icon': this._iconChangedHandler,
+      'search': this._openSearchHandler
+    };
+
+    debug('Got linkAdded: (' + e.target.href + ') ' + e.target.rel);
+    e.target.rel.split(' ').forEach(function(x) {
+      let token = x.toLowerCase();
+      if (handlers[token]) {
+        handlers[token](e);
       }
-      else {
-        debug("Not top level!");
-      }
-    }
+    }, this);
   },
 
   _addMozAfterPaintHandler: function(callback) {
     function onMozAfterPaint() {
       let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
       if (uri.spec != "about:blank") {
         debug("Got afterpaint event: " + uri.spec);
         removeEventListener('MozAfterPaint', onMozAfterPaint,
--- a/dom/browser-element/BrowserElementParent.jsm
+++ b/dom/browser-element/BrowserElementParent.jsm
@@ -108,16 +108,17 @@ function BrowserElementParent(frameLoade
     "hello": this._recvHello,
     "contextmenu": this._fireCtxMenuEvent,
     "locationchange": this._fireEventFromMsg,
     "loadstart": this._fireEventFromMsg,
     "loadend": this._fireEventFromMsg,
     "titlechange": this._fireEventFromMsg,
     "iconchange": this._fireEventFromMsg,
     "close": this._fireEventFromMsg,
+    "opensearch": this._fireEventFromMsg,
     "securitychange": this._fireEventFromMsg,
     "error": this._fireEventFromMsg,
     "scroll": this._fireEventFromMsg,
     "firstpaint": this._fireEventFromMsg,
     "documentfirstpaint": this._fireEventFromMsg,
     "nextpaint": this._recvNextPaint,
     "keyevent": this._fireKeyEvent,
     "showmodalprompt": this._handleShowModalPrompt,
--- a/dom/browser-element/mochitest/Makefile.in
+++ b/dom/browser-element/mochitest/Makefile.in
@@ -37,17 +37,19 @@ MOCHITEST_FILES = \
 		test_browserElement_inproc_TopBarrier.html \
 		browserElement_AppWindowNamespace.js \
 		test_browserElement_inproc_AppWindowNamespace.html \
 		file_browserElement_AppWindowNamespace.html \
 		browserElement_BrowserWindowNamespace.js \
 		test_browserElement_inproc_BrowserWindowNamespace.html \
 		file_browserElement_BrowserWindowNamespace.html \
 		browserElement_Iconchange.js \
+		browserElement_Opensearch.js \
 		test_browserElement_inproc_Iconchange.html \
+		test_browserElement_inproc_Opensearch.html \
 		browserElement_GetScreenshot.js \
 		test_browserElement_inproc_GetScreenshot.html \
 		browserElement_BadScreenshot.js \
 		test_browserElement_inproc_BadScreenshot.html \
 		browserElement_SetVisible.js \
 		test_browserElement_inproc_SetVisible.html \
 		browserElement_SetVisibleFrames.js \
 		test_browserElement_inproc_SetVisibleFrames.html \
@@ -191,16 +193,17 @@ MOCHITEST_FILES += \
 		test_browserElement_oop_LoadEvents.html \
 		test_browserElement_oop_DataURI.html \
 		test_browserElement_oop_ErrorSecurity.html \
 		test_browserElement_oop_Titlechange.html \
 		test_browserElement_oop_AppWindowNamespace.html \
 		test_browserElement_oop_BrowserWindowNamespace.html \
 		test_browserElement_oop_TopBarrier.html \
 		test_browserElement_oop_Iconchange.html \
+		test_browserElement_oop_Opensearch.html \
 		test_browserElement_oop_GetScreenshot.html \
 		test_browserElement_oop_BadScreenshot.html \
 		test_browserElement_oop_XFrameOptions.html \
 		test_browserElement_oop_XFrameOptionsDeny.html \
 		test_browserElement_oop_XFrameOptionsSameOrigin.html \
 		test_browserElement_oop_XFrameOptionsAllowFrom.html \
 		test_browserElement_oop_SendEvent.html \
 		test_browserElement_oop_SetVisible.html \
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/browserElement_Opensearch.js
@@ -0,0 +1,109 @@
+/* Any copyright is dedicated to the public domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that the onmozbrowseropensearch event works.
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+browserElementTestHelpers.setEnabledPref(true);
+browserElementTestHelpers.addPermission();
+
+function createHtml(link) {
+  return 'data:text/html,<html><head>' + link + '<body></body></html>';
+}
+
+function createLink(name) {
+  return '<link rel="search" title="Test OpenSearch" type="application/opensearchdescription+xml" href="http://example.com/' + name + '.xml">';
+}
+
+function runTest() {
+  var iframe1 = document.createElement('iframe');
+  SpecialPowers.wrap(iframe1).mozbrowser = true;
+  document.body.appendChild(iframe1);
+
+  // iframe2 is a red herring; we modify its link but don't listen for
+  // opensearch; we want to make sure that its opensearch events aren't
+  // picked up by the listener on iframe1.
+  var iframe2 = document.createElement('iframe');
+  SpecialPowers.wrap(iframe2).mozbrowser = true;
+  document.body.appendChild(iframe2);
+
+  // iframe3 is another red herring.  It's not a mozbrowser, so we shouldn't
+  // get any opensearch events on it.
+  var iframe3 = document.createElement('iframe');
+  document.body.appendChild(iframe3);
+
+  var numLinkChanges = 0;
+
+  iframe1.addEventListener('mozbrowseropensearch', function(e) {
+
+    numLinkChanges++;
+
+    if (numLinkChanges == 1) {
+      is(e.detail.title, 'Test OpenSearch');
+      is(e.detail.href, 'http://example.com/mysearch.xml');
+
+      // We should recieve opensearch events when the user creates new links
+      // to a search engine, but only when we listen for them
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.title='New title';",
+                                    /* allowDelayedLoad = */ false);
+
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+                                    /* allowDelayedLoad = */ false);
+
+      SpecialPowers.getBrowserFrameMessageManager(iframe2)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+                                    /* allowDelayedLoad = */ false);
+    }
+    else if (numLinkChanges == 2) {
+      is(e.detail.href, 'http://example.com/newsearch.xml');
+
+      // Full new pages should trigger opensearch events
+      iframe1.src = createHtml(createLink('3rdsearch'));
+    }
+    else if (numLinkChanges == 3) {
+      is(e.detail.href, 'http://example.com/3rdsearch.xml');
+
+      // the rel attribute can have various space seperated values, make
+      // sure we only pick up correct values for 'opensearch'
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=someopensearch type=application/opensearchdescription+xml href=http://example.com/newsearch.xml>')",
+                                    /* allowDelayedLoad = */ false);
+      // Test setting a page with multiple links elements
+      iframe1.src = createHtml(createLink('another') + createLink('search'));
+    }
+    else if (numLinkChanges == 4) {
+      is(e.detail.href, 'http://example.com/another.xml');
+      // 2 events will be triggered by previous test, wait for next
+    }
+    else if (numLinkChanges == 5) {
+      is(e.detail.href, 'http://example.com/search.xml');
+
+      // Make sure opensearch check is case insensitive
+      SpecialPowers.getBrowserFrameMessageManager(iframe1)
+                   .loadFrameScript("data:,content.document.head.insertAdjacentHTML('beforeend', '<link rel=SEARCH type=application/opensearchdescription+xml href=http://example.com/ucasesearch.xml>')",
+                                    /* allowDelayedLoad = */ false);
+    }
+    else if (numLinkChanges == 6) {
+      is(e.detail.href, 'http://example.com/ucasesearch.xml');
+      SimpleTest.finish();
+    } else {
+      ok(false, 'Too many opensearch events.');
+    }
+  });
+
+  iframe3.addEventListener('mozbrowseropensearch', function(e) {
+    ok(false, 'Should not get a opensearch event for iframe3.');
+  });
+
+
+  iframe1.src = createHtml(createLink('mysearch'));
+  // We should not recieve opensearch change events for either of the below iframes
+  iframe2.src = createHtml(createLink('mysearch'));
+  iframe3.src = createHtml(createLink('mysearch'));
+
+}
+
+addEventListener('testready', runTest);
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_inproc_Opensearch.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=883002
+-->
+<head>
+  <title>Test for Bug 883002</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.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=883002">Mozilla Bug 883002</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Opensearch.js">
+</script>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/browser-element/mochitest/test_browserElement_oop_Opensearch.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=883002
+-->
+<head>
+  <title>Test for Bug 883002</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="browserElementTestHelpers.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=883002">Mozilla Bug 883002</a>
+
+<script type="application/javascript;version=1.7" src="browserElement_Opensearch.js">
+</script>
+
+</body>
+</html>