Bug 339725 - SVG <a> with xlink:href don't show HTML link features in context menu, r?jaws,longsonr draft
authorRobert Longson <longsonr>
Sun, 07 May 2017 01:09:00 +0100
changeset 579476 4f000c1b99089ca5e32157ba6dd7830287fbb220
parent 579463 6e3ca5b38f7173b214b10de49e58cb01890bf39d
child 629011 16604522e4e1264371abd2c15bf817c872e3f535
push id59258
push usergijskruitbosch@gmail.com
push dateWed, 17 May 2017 10:36:07 +0000
reviewersjaws, longsonr
bugs339725
milestone55.0a1
Bug 339725 - SVG <a> with xlink:href don't show HTML link features in context menu, r?jaws,longsonr MozReview-Commit-ID: Kg9dONwXCrB
browser/base/content/nsContextMenu.js
browser/base/content/test/general/browser_contextmenu.js
browser/base/content/test/general/subtst_contextmenu.html
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -876,24 +876,27 @@ nsContextMenu.prototype = {
    */
   _setTargetForNodesWithChildren(editFlags, rangeParent, rangeOffset) {
     // Second, bubble out, looking for items of interest that can have childen.
     // Always pick the innermost link, background image, etc.
     var elem = this.target;
     while (elem) {
       if (elem.nodeType == Node.ELEMENT_NODE) {
         // Link?
+        const XLINKNS = "http://www.w3.org/1999/xlink";
         if (!this.onLink &&
             // Be consistent with what hrefAndLinkNodeForClickEvent
             // does in browser.js
              (this._isXULTextLinkLabel(elem) ||
               (elem instanceof HTMLAnchorElement && elem.href) ||
+              (elem instanceof SVGAElement &&
+               (elem.href || elem.hasAttributeNS(XLINKNS, "href"))) ||
               (elem instanceof HTMLAreaElement && elem.href) ||
               elem instanceof HTMLLinkElement ||
-              elem.getAttributeNS("http://www.w3.org/1999/xlink", "type") == "simple")) {
+              elem.getAttributeNS(XLINKNS, "type") == "simple")) {
 
           // Target is a link or a descendant of a link.
           this.onLink = true;
 
           // Remember corresponding element.
           this.link = elem;
           this.linkURL = this.getLinkURL();
           this.linkURI = this.getLinkURI();
@@ -1670,18 +1673,23 @@ nsContextMenu.prototype = {
 
     // Voila!
     return node;
   },
 
   // Generate fully qualified URL for clicked-on link.
   getLinkURL() {
     var href = this.link.href;
-    if (href)
+    if (href) {
+      // Handle SVG links:
+      if (typeof href == "object" && href.animVal) {
+        return href.animVal;
+      }
       return href;
+    }
 
     href = this.link.getAttribute("href") ||
            this.link.getAttributeNS("http://www.w3.org/1999/xlink", "href");
 
     if (!href || !href.match(/\S/)) {
       // Without this we try to save as the current doc,
       // for example, HTML case also throws if empty
       throw "Empty href";
--- a/browser/base/content/test/general/browser_contextmenu.js
+++ b/browser/base/content/test/general/browser_contextmenu.js
@@ -973,16 +973,69 @@ add_task(async function test_link_sendli
       async onContextMenuShown() {
         await openMenuItemSubmenu("context-sendlinktodevice");
       }
     });
 
   restoreRemoteClients(oldGetter);
 });
 
+add_task(async function test_svg_link() {
+  await test_contextmenu("#svg-with-link > a",
+    ["context-openlinkintab", true,
+     ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+     // We need a blank entry here because the containers submenu is
+     // dynamically generated with no ids.
+     ...(hasContainers ? ["", null] : []),
+     "context-openlink",      true,
+     "context-openlinkprivate", true,
+     "---",                   null,
+     "context-bookmarklink",  true,
+     "context-savelink",      true,
+     ...(hasPocket ? ["context-savelinktopocket", true] : []),
+     "context-copylink",      true,
+     "context-searchselect",  true
+    ]
+  );
+
+  await test_contextmenu("#svg-with-link2 > a",
+    ["context-openlinkintab", true,
+     ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+     // We need a blank entry here because the containers submenu is
+     // dynamically generated with no ids.
+     ...(hasContainers ? ["", null] : []),
+     "context-openlink",      true,
+     "context-openlinkprivate", true,
+     "---",                   null,
+     "context-bookmarklink",  true,
+     "context-savelink",      true,
+     ...(hasPocket ? ["context-savelinktopocket", true] : []),
+     "context-copylink",      true,
+     "context-searchselect",  true
+    ]
+  );
+
+  await test_contextmenu("#svg-with-link3 > a",
+    ["context-openlinkintab", true,
+     ...(hasContainers ? ["context-openlinkinusercontext-menu", true] : []),
+     // We need a blank entry here because the containers submenu is
+     // dynamically generated with no ids.
+     ...(hasContainers ? ["", null] : []),
+     "context-openlink",      true,
+     "context-openlinkprivate", true,
+     "---",                   null,
+     "context-bookmarklink",  true,
+     "context-savelink",      true,
+     ...(hasPocket ? ["context-savelinktopocket", true] : []),
+     "context-copylink",      true,
+     "context-searchselect",  true
+    ]
+  );
+});
+
 add_task(async function test_cleanup_html() {
   gBrowser.removeCurrentTab();
 });
 
 /**
  * Selects the text of the element that matches the provided `selector`
  *
  * @param {String} selector
--- a/browser/base/content/test/general/subtst_contextmenu.html
+++ b/browser/base/content/test/general/subtst_contextmenu.html
@@ -64,10 +64,13 @@ Browser context menu subtest.
 <div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
 <div id="test-select-text-link">http://mozilla.com</div>
 <a id="test-image-link" href="#"><img src="ctxmenu-image.png"></a>
 <input id="test-select-input-text" type="text" value="input">
 <input id="test-select-input-text-type-password" type="password" value="password">
 <embed id="test-plugin" style="width: 200px; height: 200px;" type="application/x-test"></embed>
 <img id="test-longdesc" src="ctxmenu-image.png" longdesc="http://www.mozilla.org"></embed>
 <iframe id="test-srcdoc" width="98"  height="98" srcdoc="Hello World" style="border: 1px solid black"></iframe>
+<svg id="svg-with-link" width=10 height=10><a xlink:href="http://example.com/"><circle cx="50%" cy="50%" r="50%" fill="blue"/></a></svg>
+<svg id="svg-with-link2" width=10 height=10><a xlink:href="http://example.com/" xlink:type="simple"><circle cx="50%" cy="50%" r="50%" fill="green"/></a></svg>
+<svg id="svg-with-link3" width=10 height=10><a href="http://example.com/"><circle cx="50%" cy="50%" r="50%" fill="red"/></a></svg>
 </body>
 </html>