fontready event and pdf.js experiment
This is another blog post that I intend to write along side writing code, as opposed to doing it afterwards. This is my second time doing this, and I feel it has more of a narrative or story, than pure information. You get to read thoughts as they unfold, and something before I know what to do with them. I don’t feel this is better or worse than other blog posts, just different and I enjoy it from time to time.
The task at hand is to modify pdf.js to use my fontready patch. I am excited to see if I can decrease load time, but we’ll see. Another goal would be to reduce pdf.js’ code base. Also, this might be a good way for people to learn how to jump into a new project.
First thing: get their source. Easy enough. I went to their github pages page and found a simple git clone command, which I ran.
I explored their pdf.jd directory, and found it is quite similar to our own popcorn-maker directory. I opened a started reading README.md, which basically told me put it on a webserver and run make to compile all the source into one pdf.js file. So, I moved it to my webserver directory, and opened the src directory.
For testing my changes, I am going to go here: http://localhost/pdf.js/web/viewer.html
It was at this point I decided to start this blog. So I next did a bit of time traveling.
I am going to be looking for anything to do with fonts. The fact that all the parts of the source are split might be helpful, if there is something clearly marked font.js.
Instead of finding a font.js, I found a fonts.js 😛 Perfect.
Now I think, it is probably best to do this in a branch.
>git branch fontready master
>git checkout fontready
Good to go.
Now to explore fonts.js. very first line of code is “var kMaxWaitForFontFace = 1000;” which looks extremely interesting to me. But, after searching for all instances of “kMaxWaitForFontFace” I was surprised to see it was not in this file. Odd. I scrolled down some more, and once I got past all the declarations, I came to a FontLoader object, that has an attribute called listeningForFontLoad initially set to false, and two functions, bind(fonts, callback) and prepareFontLoadEvent(rules, names, fonts). First thing I see in prepareFontLoadEvent is /** Hack begin */ and another comment explaining the nature of the hack, how no fontready event exists, and how “This code will be obsoleted by Mozilla bug 471915“. Happens to be why I am here. Safe to say I am in the right spot. This code is reading quite well.
prepareFontLoadEvent is primarily doing two things. It is creating an invisible div to use the new @font-face, this will trigger the download of the @font-face. The second piece is an iframe with all the css @font-faces attached to it, with an onload event, that uses post message to inform the parent the font is ready. Interesting, I was not aware onload waited until a statically defined @font-face is loaded. This is both good and bad. It can solve the need to wait for @font-face, but i can see it holding back a lot of other good stuff in the event that doesn’t need to be held back. It does not allow for dynamically inserted @font-face’s, and still requires the font to be used before the @font-face triggers loading. This may potentially stall a onload forever, if the page is only using the font inside canvas, and the developer is not aware of this quirk. It is quite valuable for me to know how others load this, I am very happy about this find. Anyway, the path of least resistance here is to slap in my fontready listener and just make that work. Go from there.
I first tried to simply replace the onload event in the iframe to my fontready, and refreshed http://localhost/pdf.js/web/viewer.html. As expected, nothing happened. I am not in my fontready build.
Turns out I had to re build, from clean, so it took a bit. Anyway, it ended up working, sort of. I also removed all the iframe stuff, and just rewired the post message listener to be a fontready instead, and removed some code. I have a patch for anyone that is curious. Remember, this is just an experimental demo, not something that can become real.
I most definitely removed code. Hard to say if it is faster, as I did my testing in a debug build.
I had to leave in the invisible div to initiate the loading of the @font-face. I think this is the next thing I am going to try my hand at removing. That, or pass in useful information through the fontready event, but not sure what that should look like yet.