6

I am using the Firefox Add-on SDK to create an extension and am performing a PageMod. This code is in main.js.

...
exports.main = function() {
  var pageMod = require("sdk/page-mod");

  pageMod.PageMod({
    include: "*",
    contentScriptWhen: 'end',
    contentStyleFile: [
      self.data.url("css/style.css"),
      self.data.url("css/font-awesome.css")
    ],
    contentScriptFile: [
      self.data.url("js/jquery.js"),
      self.data.url("js/spritzify.js")
    ],
    onAttach: function onAttach(worker) {
      worker.postMessage("Hello World");
    }
  });
};
...

my css/font-awesome.css gets loaded into the page although the font files do not.

@font-face {
  font-family: 'FontAwesome';
  src: url('fonts/fontawesome-webfont.eot?v=4.1.0');
  src: url('fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'), url('fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
  font-weight: normal;
  font-style: normal;
}

The fonts folder is in the data folder of my extension. Could someone please explain how I can load custom fonts into a webpage using PageMod!

nmaier
  • 32,336
  • 5
  • 63
  • 78
mildog8
  • 2,030
  • 2
  • 22
  • 36
  • Interestingly, there are already at least two duplicates of your question (https://stackoverflow.com/q/21172670/785541 and https://stackoverflow.com/q/19808064/785541), both without a proper answer. – Wladimir Palant Jun 23 '14 at 06:38

3 Answers3

17

If you look into the console messages, this is what you should see:

downloadable font: download not allowed (font-family: "FontAwesome" style:normal weight:normal stretch:normal src index:0): bad URI or cross-site access not allowed

Unfortunately for you, web fonts are subject to the same-origin policy which can only be relaxed via CORS. This means that there is no way to load the font file from an extension URL as there is no way to use CORS there.

This leaves you with two options:

  1. You host the font on a web server with proper CORS headers or use some existing font hosting.
  2. You encode the font as a data: URI. There is a number of data: URI generators available, e.g. this one.

IMHO the second solution is the preferable one as your extension won't be dependent on any web servers, especially not third-party web servers. Also, it won't introduce any delays caused by font downloading. I tried it and it worked fine:

@font-face {
  font-family: 'FontAwesome';
  src: url('data:application/octet-stream;base64,d09GRgAB...') format('woff');
  font-weight: normal;
  font-style: normal;
} 

Side-note: You don't need the full backwards compatibility dance in a Firefox extension, it's sufficient to have the font in the WOFF format.

Wladimir Palant
  • 56,865
  • 12
  • 98
  • 126
  • What about making it a `chrome` path and setting `contentaccessible=yes` in the `chrome.manifest`? – Noitidart Jun 23 '14 at 08:57
  • 1
    @Noitidart: I think `chrome` URLs have the same issue, at least according to some Google search results. Not that it is a practicable solution for an SDK extension. – Wladimir Palant Jun 23 '14 at 09:35
  • does not seem to be working `@font-face { font-family: 'FontAwesome'; src: url('data:application/octet-stream;base64,ARs...') format('embedded-opentype'); font-weight: normal; font-style: normal; }`. Am I doing anything wrong? – mildog8 Jun 23 '14 at 22:38
  • @AndrewM: Embedded OpenType format is a proprietary Internet Explorer feature. You should really be using the WOFF format. – Wladimir Palant Jun 24 '14 at 05:34
  • @WladimirPalant still does not seem to be working using WOFF format. – mildog8 Jun 24 '14 at 06:42
  • 1
    @AndrewM: See http://pastebin.com/P0ttkDmw - that's the complete CSS file I used for testing, it worked correctly for me. – Wladimir Palant Jun 24 '14 at 11:54
  • @WladimirPalant Thanks a lot. Working now! – mildog8 Jun 24 '14 at 20:34
  • I tried solution 1 and it still failed with `Content Security Policy: The page's settings blocked the loading of a resource at http://fonts.gstatic.com/s/opensans/v10/cJZKeOuBrn4kERxqtaUH3bO3LdcAZYWl9Si6vvxL-qU.woff`. Any thoughts? – willlma Apr 16 '15 at 00:35
  • @willlma: Content Security Policy settings are configurable in `manifest.json`, you have to allow that domain. – Wladimir Palant Apr 16 '15 at 08:10
  • Thanks for the response. It was only failing on `https` pages, so I changed the protocol to `https` and it is now working on all pages (I was hoping protocol agnostic `//fonts…` would do the trick, but not so). – willlma Apr 16 '15 at 18:51
  • @WladimirPalant what is the manifest.json file? I'm building a Firefox extension, having the same issue, but my code has a package.json (https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/package_json), not manifest.json. Any info is much appreciated. – Buu Feb 01 '16 at 04:00
  • I'm trying to load icon fonts on github.com from my Firefox add-on but GitHub's CSP includes “font-src assets-cdn.github.com” which makes it impossible to load font files via data URI (“content blocked”). F.Y.I. In Chrome, local files can be loaded directly but the data URI solution fails too. In Firefox I haven't found a solution to this yet. @WladimirPalant do you know any work around here? – Justineo Feb 03 '16 at 10:04
  • @Justineo: Using remotely downloaded fonts in an extension is a bad idea. You should download and add them to your extension, as `data:` URIs. – Wladimir Palant Feb 03 '16 at 10:22
  • @WladimirPalant I was actually serving fonts as data URI but it doesn't work because of GitHub's CSP (you probably missed that in my last comment). In Firefox I only got the error message "content blocked" and I figured it out after I tried in Chrome. I was addressing the difference that Chrome allow local Web fonts (provided by the extension, not remotely downloaded) but not data URI in content script, while under same CSP, Firefox forbids both. – Justineo Feb 05 '16 at 07:50
  • @Justineo: Got it, I thought that the fonts were hosted on GitHub, not that you are trying to use them there. Frankly, I have no idea whether it's possible to work around CSP here. – Wladimir Palant Feb 05 '16 at 13:08
  • @Justineo did you ever manage to get past github's csp? somehow? anyhow? Im facing this bug too :( – Irtza.QC Feb 22 '16 at 16:03
  • @Irtza.QC Nope. I was trying to load Octicon into GitHub in my browser extension because they switched to SVG icons some time ago. I finally ended up with switching to SVG icons as well. – Justineo Feb 23 '16 at 08:07
  • @Palant - I have a bootstrap.js addon with my page being an about page with flag `Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT`. I set a chrome path in my `chrome.manifest` and set it to `contentaccessible=true` - https://github.com/Noitidart/Topick/blob/master/chrome.manifest - however I still get the same "downloadable font: download no...." error for only fonts inside, even though i used the full `chrome://topick/content/...` path. Is there anyway to modify the CORS so this gets allowed. Paths to images work fine, its so weird. – Noitidart Aug 28 '16 at 11:28
  • 1
    @Noitidart: Frankly, I have no idea how this works with non-HTTP schemes. It's a CORS-enabled request and the only channel implementing CORS handling is the HTTP channel. It might be that a custom channel could be used as well but it looks like using it here requires understanding Gecko internals better than I do right now. – Wladimir Palant Aug 28 '16 at 18:24
  • Darn. Thanks though @WladimirPalant for spending the time to look into it! :) – Noitidart Aug 29 '16 at 06:29
0

I think you need to use absolute paths in those url fields. So figure out what seld.data.url('fonts') (by like console.log'ing it) (the path should be something like resource://weraweraer-at-jetpack/data/fonts) and then update your url's to use that path.

I'm pretty sure this should work because resource url's don't have security restrictions. See this page here: https://developer.mozilla.org/en-US/docs/Chrome_Registration#resource

It says:

Note: There are no security restrictions preventing web content from including content at resource: URIs, so take care what you make visible there.

Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 2
    "I'm pretty sure this should work because resource url's don't have security restrictions" - well, you are wrong :) – Wladimir Palant Jun 23 '14 at 06:39
  • @WladimirPalant You were right. I verified that this does not work. I tried setting them as a resource path in `chrome.manifest`. :( – Noitidart Aug 28 '16 at 11:29
0

The best answer I have found is here: https://stackoverflow.com/a/39971918/1635421

src: url('moz-extension://MSG@@extension_id_/css/fonts/webFonts/font-awesome/fontawesome-webfont.eot?v=4.5.0');

Which is analogous to this method for Chrome: src: url('chrome-extension://MSG@@extension_id_/fonts/...

jmarch
  • 101
  • 1
  • 4