target; // Ignore sub-frames (bugs 305472, 479408). if (link.ownerGlobal != this.contentWindow) { return; } let rel = link.rel && link.rel.toLowerCase(); // We also check .getAttribute, since an empty href attribute will give us // a link.href that is the same as the document. if (!rel || !link.href || !link.getAttribute("href")) { return; } // Note: following booleans only work for the current link, not for the // whole content let iconAdded = false; let searchAdded = false; let rels = {}; for (let relString of rel.split(/\s+/)) { rels[relString] = true; } for (let relVal in rels) { let isRichIcon = false; switch (relVal) { case "apple-touch-icon": case "apple-touch-icon-precomposed": case "fluid-icon": isRichIcon = true; // fall through case "icon": if (iconAdded || link.hasAttribute("color") || rel.includes("mask")) { // TODO (Bug 1337397): Add support for mask-icon favicons. break; } if (!Services.prefs.getBoolPref("browser.chrome.site_icons", true)) { return; } if (this.iconLoader.addIconFromLink(link, isRichIcon)) { iconAdded = true; if (!isRichIcon) { this.seenTabIcon = true; } } break; case "search": if ( Services.policies && !Services.policies.isAllowed("installSearchEngine") ) { break; } if (!searchAdded && event.type == "DOMLinkAdded") { let type = link.type && link.type.toLowerCase(); type = type.replace(/^\s+|\s*(?:;.*)?$/g, ""); // Note: This protocol list should be kept in sync with // the one in OpenSearchEngine's install function. let re = /^https?:/i; if ( type == "application/opensearchdescription+xml" && link.title && re.test(link.href) ) { let engine = { title: link.title, href: link.href }; this.sendAsyncMessage("Link:AddSearch", { engine, }); searchAdded = true; } } break; } } } handleEvent(event) { switch (event.type) { case "pageshow": return this.onPageShow(event); case "pagehide": return this.onPageHide(event); case "DOMHeadElementParsed": return this.onHeadParsed(event); default: return this.onLinkEvent(event); } } } PK