1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 ChromeUtils.defineESModuleGetters(lazy, {
8 FaviconLoader: "resource:///modules/FaviconLoader.sys.mjs",
11 export class LinkHandlerChild extends JSWindowActorChild {
15 this.seenTabIcon = false;
16 this._iconLoader = null;
20 if (!this._iconLoader) {
21 this._iconLoader = new lazy.FaviconLoader(this);
23 return this._iconLoader;
29 Services.prefs.getBoolPref("browser.chrome.guess_favicon", true) &&
30 Services.prefs.getBoolPref("browser.chrome.site_icons", true)
32 // Inject the default icon. Use documentURIObject so that we do the right
33 // thing with about:-style error pages. See bug 453442
34 let pageURI = this.document.documentURIObject;
35 if (["http", "https"].includes(pageURI.scheme)) {
36 this.seenTabIcon = true;
37 this.iconLoader.addDefaultIcon(pageURI);
43 if (event.target.ownerDocument != this.document) {
47 // Per spec icons are meant to be in the <head> tag so we should have seen
48 // all the icons now so add the root icon if no other tab icons have been
52 // We're likely done with icon parsing so load the pending icons now.
53 if (this._iconLoader) {
54 this._iconLoader.onPageShow();
59 if (event.target != this.document) {
65 if (this._iconLoader) {
66 this._iconLoader.onPageShow();
71 if (event.target != this.document) {
75 if (this._iconLoader) {
76 this._iconLoader.onPageHide();
79 this.seenTabIcon = false;
83 let link = event.target;
84 // Ignore sub-frames (bugs 305472, 479408).
85 if (link.ownerGlobal != this.contentWindow) {
89 let rel = link.rel && link.rel.toLowerCase();
90 // We also check .getAttribute, since an empty href attribute will give us
91 // a link.href that is the same as the document.
92 if (!rel || !link.href || !link.getAttribute("href")) {
96 // Note: following booleans only work for the current link, not for the
98 let iconAdded = false;
99 let searchAdded = false;
101 for (let relString of rel.split(/\s+/)) {
102 rels[relString] = true;
105 for (let relVal in rels) {
106 let isRichIcon = false;
109 case "apple-touch-icon":
110 case "apple-touch-icon-precomposed":
115 if (iconAdded || link.hasAttribute("mask")) {
116 // Masked icons are not supported yet.
120 if (!Services.prefs.getBoolPref("browser.chrome.site_icons", true)) {
124 if (this.iconLoader.addIconFromLink(link, isRichIcon)) {
127 this.seenTabIcon = true;
134 !Services.policies.isAllowed("installSearchEngine")
139 if (!searchAdded && event.type == "DOMLinkAdded") {
140 let type = link.type && link.type.toLowerCase();
141 type = type.replace(/^\s+|\s*(?:;.*)?$/g, "");
143 // Note: This protocol list should be kept in sync with
144 // the one in OpenSearchEngine's install function.
145 let re = /^https?:/i;
147 type == "application/opensearchdescription+xml" &&
151 let engine = { title: link.title, href: link.href };
152 this.sendAsyncMessage("Link:AddSearch", {
164 switch (event.type) {
166 return this.onPageShow(event);
168 return this.onPageHide(event);
169 case "DOMHeadElementParsed":
170 return this.onHeadParsed(event);
172 return this.onLinkEvent(event);