Archive for March, 2012

OSD 0.8

Posted in open source on March 25, 2012 by scottdowne

The bulk of this release is my preliminary work on font a fontready event.

I initially wanted to have a test going for my my Firefox ticket (677122) but it turned out to be more of a learning curve than I expected, and not a test suite like the ones I was familiar with. I will have to push it to 0.9.

I did manage to accomplish all I set out to do in the short time I did it regarding fontready. It ended up being much much easier than 677122, but that might be due to the experience from 677122.

There is a Firefox ticket for fontready, but I really don’t think there is much more to say about it. Font ready is obviously a feature that is in demand, and I have no doubts it will eventually be in the browser, the question is a matter of how it will look. What I was attempting to solve is more to get my ideas out there, generate whatever interest I can, and help the people currently trying to get this attention. I feel demos and patches do that goal more justice than talking. This is only a start.

My first blog post on this was me figuring out when and how @font-face was loaded. I wrote this blog along side my exploring the code, so it is kinda like a narrative, which is fun. I ended up nailing down exactly the location in the code I needed. Went much more smooth than 677122 that’s for sure.

Second blog post was figuring out how to actually trigger the event “fontready”. This was also much easier than expected. I am going to have to go back to this, though, to get the event data in the callback to be something a little more meaningful, but this will require knowledge in what is meaningful to someone using this.

Third blog post was a demonstration of how it can be used to solf a real problem in using fonts in canvas.

There is interest on the chrome side of things, but not enough. There is also interest in making fonts load synchronously. While this solves the problem, and is better than nothing. What happens if a large font is needed? The developer needs more control over this. Fontready is still a much better solution, imo. I myself need to kick it into another level. This can be proven by googling fontready, and finding I am the one that comes up at the time of writing this.

My next release will be a pdf.js patch to use my fontready patch, fontready event data, and a test for 677122.

Follow through on my fontready patch

Posted in open source on March 14, 2012 by scottdowne

I recently created a patch for Firefox that allows one to listen to the ready state of fonts loaded via @font-face.

I have some examples on it.

First to get a more visual example, I will show images as to why this is useful and needed badly inside the browser.
This is an image of a div using some custom font, and a canvas drawing some text using the same font. As you can see above, the fonts are different. What is actually happening is there is a moment where the div is also incorrectly drawn, then when the font is loaded, it gets updated. This has been coined as
FOUT. The canvas never gets the update, or the FOUT, because it never knows to clear the canvas and redraw the text. One way around this is to constantly clear the canvas and redraw, and once the font it loaded, it will update, and bring along the FOUT with it. Also, you could setup an offscreen div, and measure text on it until it is not the same size as the default font, meaning your new font is most likely ready to go. Both solutions are hacks and suboptimal.

In my last post, I talk about my attempt to listen for font ready states. Given the same example above, this is now what I get on the first load:

As you can see, both fonts are the same. This is because I setup a listener for “fontready” and draw my canvas in there. This also gets rid of the FOUT. The event looks like this:

      var setupCanvas = function( e ) {
      
        var canvas = document.getElementById( "canvas" );
        var ctx = canvas.getContext( "2d" );

        ctx.font = "20pt dekar";
        ctx.strokeText("Hello World!", 50, 50);  
      };
    
      document.addEventListener( "fontready", setupCanvas, false );

One annoyance I noticed with this is fontready and DOMContentLoaded may become a race condition if not carefully implemented, because the dom must be loaded before the canvas can be drawn to. Example of this is if the font is ready before the document, and thus the canvas is not ready, and the font loading is lost. There are ways around this, though, and is not a huge deal, just something that must be accounted for, and is quite common in web development. I solved this by creating the font inside my DOMContentLoaded event. Looked like this:

      document.addEventListener( "DOMContentLoaded", function( e ) {
      
        var fileref=document.createElement("style");
        fileref.setAttribute("rel", "stylesheet");
        fileref.setAttribute("type", "text/css");
        fileref.innerHTML = "@font-face { font-family: dekar; src: url('Dekar.otf'); } div { font-family: dekar; }";

        document.getElementsByTagName("head")[0].appendChild(fileref);

        setupCanvas();
      }, false );

This is just one way to ensure things happen in the desired order. I just create a style element and insert it after the dom is ready, and my fontready event has been created.

There is a Firefox ticket for this very feature, along with a beginning of a proposed spec for a font API. I have been looking these over, and will have an opinion compiled shortly.

Getting started with contributing to Processing.js or Popcorn.js

Posted in open source, video, webmademovies on March 14, 2012 by scottdowne

So, the first two open source projects I was involved in have a fairly similar work flow, and I decided to write down the steps to get started in these projects.

Both Processing and Popcorn have fairly good intro sites, and I would start there. Popcorn also have secondary site that is useful. Also might want to check out the original Processing. Those sites provide a general introduction on the projects, and not something I will be covering here.

Both projects have four primary things, an issue tracker, a source repository, revision control, and a developer community.

An issue tracker is where bugs and new features get tracked, assigned, and reviewed. Both projects use something called lighthouse as their issue tracker. These can be found here for popcorn and here for processing. Issues can be anything from whitespace fixes, to documentation changes to complete rewrites. The pages I liked are the recent activity pages. You may want to look under milestones to get a list of potential tickets.

A source repository is a place where the code is stored and updated. Both projects use github as their source repository. These can be found here for popcorn and here for processing. Those are our release repos, in that they only get updated once for each release. If you want the unreleased code, you have to get that from a separate repo. These can be found here for popcorn and here for processing. We call these development branches.

Both projects use git for revision control. It goes hand in hand with github, but I do feel like it is a different thing. Source repository is where the code is kept, and revision control are the tools that interact with it. This is how I like to think of it, as it helps me understand it the way I need to work with it. I might not be technically correct with the definitions, though. Kinda like how the alphabet is not actually a song, but a song helps to understand it.

Both projects use irc for their developer community. This is the place you can go to get real time help from the people that have the answers. Popcorn uses the channel #popcorn and processing #processing.js. These can be found on the server irc.mozilla.org. More information about connecting to irc can be found here or here.

Now that that is out of the way, you will want to create a github account if you don’t already have one, then fork one of the projects from their github page. You will probably want to fork one of the development repos.

From there, you will need to get that github repo onto your local machine. I used this post when I started this, and I recommend it to others.

Next step is to find a bug on one of the lighthouse pages. Maybe comment in the bug that you are interested in working on it, so others know not to work on it as well.

You will want to create a branch on your local git repo named after your bug number. So, if my bug is popcorn bug #927 I will want to create a branch called t927. We add the t because code commits can be shorthanded to numbers, and there may be collisions in branch names and commits. Always good practice to but a letter in it. You can do this by running this command:

git branch t927 develop
git checkout t927

What this does is created a branch named t927 that is based off the branch develop. Then, moves you over to that branch.

Next you can go about changing the code in your local git repo. Once done, you will want to run some git commands.

1. git status: this shows the files that have changed, that you may need to commit.

2. git add: this adds those files. If you notice running git status after a git add, things will of changed.

3. git commit: this commits those added files. Again, running git status after this, you should see even more changes. I like to run this command like this:

git commit -m “[#927] usefull message about what I did”

This will add a message to the commit, so future developers can see why certain lines were changed, and even track it back to the original lighthouse ticket.

4. git push: this pushes the changes into your forked github repo. An example of this command for when I do it is:

git push git@github.com:ScottDowne/popcorn-js.git t927

This command takes the ssh url of my repo, and a name to name for the branch. After doing this, I could find my branch here: https://github.com/ScottDowne/popcorn-js/tree/t927 and my changes here: https://github.com/ScottDowne/popcorn-js/commits/t927

From here you will want to take one of those two urls and drop it back intp the lighthouse ticket, as a comment, and change the status to peer-review-requested. Both projects have a two step review process. Peer-review and super-review. Once both reviews passed, the repo manager will pull your changes into develop, and then on release day, everything including your changes will be pulled into master.

I’ve got a working @font-face ready event in Firefox

Posted in open source on March 13, 2012 by scottdowne

So to continue on from my last post, I was able to get a loaded or ready event for @font-face.

I mentioned in my last post I found a good place to create an event, just did not know how to create an event. I looked around mxr, starting with domcontentloaded, trying to find something similar. It was actually much easier than I thought to setup a custom event inside the c++. All you need to do is call nsContentUtils::DispatchTrustedEvent, and pass in a object that you want the event on, the second parameter is similar to the first, but it needs to be casted (have not quite figured this one out yet), third is a NS_LITERAL_STRING(“nameofevent”), and the last two are two trues (also don’t know what yet). I needed to get access to the document as well, but that was easy too. Final diff looks like this:

diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -247,16 +247,21 @@ nsFontFaceLoader::OnStreamComplete(nsISt
   // when new font loaded, need to reflow
   if (fontUpdate) {
     // Update layout for the presence of the new font.  Since this is
     // asynchronous, reflows will coalesce.
     ctx->UserFontSetUpdated();
     LOG(("fontdownloader (%p) reflow\n", this));
   }
 
+  nsIDocument* aDocument = ctx->Document();
+     nsContentUtils::DispatchTrustedEvent(aDocument, static_cast<nsIDocument*>(aDocument),
+                                        NS_LITERAL_STRING("fontready"),
+                                        true, true);
+
   return NS_SUCCESS_ADOPTED_DATA;
 }
 
 void
 nsFontFaceLoader::Cancel()
 {
   mFontEntry->mLoadingState = gfxProxyFontEntry::NOT_LOADING;
   mFontSet = nsnull;

And using it on a page like this, you receive the console.log.

<html>
  <head>
    <style>
      @font-face {
        font-family: dekar;
        src: url('Dekar.otf');
      }
      div {
        font-family: dekar;
      }
    </style>
    <script>
      document.addEventListener( "fontready", function( e ) {
        console.log( "We be ready, captain!" );
      }, false );
    </script>
  </head>
  <body>
    <div>
      Hello world!
    </div>
  </body>
</html>

I was pleasantly surprised the event was so easy to create.

This is just some preliminary work, really. This week I hope to get some eyes on it.

Starting to create a @font-face loaded event in Firefox

Posted in open source on March 11, 2012 by scottdowne

I am about to sit down and work on the beginning on what may become a JavaScript font API.

I am going to try something new with this blog post, and write it along side whatever it is I am working on, instead of afterwards. In hopes things will be more fresh in my mind, and to document my thoughts and process as I do things.

With regards to the font API, I am going to start hacking on it, dive right in, and learn something from it. My initial goal will be to somehow create a loaded((meta)data) event for fonts. For now, I am more concerned in making this work, than making it right. Making it right can come later.

First thing I did was head over to mxr and search for “fontface”. I bounced around a bit on there until I found the file nsFontFaceLoader.cpp.

Next I needed to setup some breakpoints, and in order to do this I had to have a webpage that would initiat the code path I am looking for. I started by downloading a font that I could initiat with @font-face, then setup a little html page that looked like this:

<html>
<head>
<style>
@font-face {
	font-family: dekar;
	src: url('Dekar.otf');
}
div {
  font-family: dekar;
}
</style>
</head>
<body>
<div>
Hello world!
</div>
</body>
</html>

I put a break point on the line nsUserFontSet::StartLoad(gfxProxyFontEntry *aProxy, const gfxFontFaceSrc *aFontFaceSrc), and ran the page. My theory was confirmed and my breakpoint was fired right away. All this tells me is I am close to the code I care about. I have found the code that loads the font, but what I really care about is the code right after the font is done loading.

So, this Start Load function is on the nsUserFontSet, and inside it sets up a nsFontFaceLoader object. This object might be what I care about, the thing that is loading. So next thing I am going to do is check what options this object has. I found a few functions like cancel, that I am not really interested in, but I did find a OnStreamComplete, which looks pretty interesting.

So now I am going to add another breakpoint, and leave my old one. Make sure both fire, with the newsest one firing last. That is exactly what it did. Now, this does not mean it is what I want yet, but probably pretty close. I noticed that at this point, if I view the webpage, the font-face has still not displayed, while I sit on my breakpoint. This is a good sign that what I have, is what I need. So next I am going to put breakpoints all over this block, and find the exact moment where the font on the page updates. So, bad news, I went all the way through this function, and the font did not update. Maybe I have the wrong spot after all. It might be some caching nonsense going on, though.

I kept looking around this function, and found a call to UserFontSetUpdated that seems to be related to styling reloads, but, seems to be after the reload, so probably too late. If I look a bit north of that, I see a “userFontSet->OnLoadComplete”, so I will send this over to mxr and see what I find there. Found the file gfx/thebes/gfxUserFontSet.cpp, with the OnLoadComplete function. I am pretty sure this is what I will need.

Next, I need to figure out how the firefox event system works, and create a load event of sorts attached to something… and call the event inside the OnLoadComplete. Probably all for tonight.

Popcorn.js 1.2 new features

Posted in open source, video, webmademovies on March 10, 2012 by scottdowne

A lot of new features landed in this release.

In no particular order:

1. Players have a _teardown function a lot like a plugin. Example:

Popcorn.player( "youtube", {
  _setup: function( options ) {},
  _teardown: function( options ) {}
});

So _setup is called when a new youtube player is created by doing Popcorn.youtube( “id”, “url” ), now _teardown will be called when destroy is called on the created player by doing p.destroy(). All track events and event listeners are cleaned before the _teardown, the idea it to just reverse what you did in _setup.

2. Popcorn.smart is a new function that tries to find the appropriate player for you. Example:

Popcorn.smart( "id", "url" );

Pretty simple, but if id is a video element, and url a valid HTML5 media, a regular old HTML5 video will be setup with popcorn. If the id is a div element, and the url a youtube, it will instead setup a youtube player.

3. Popcorn _canPlayType is a new player feature that is used by Popcorn.smart.

When you create a player, you can define a canPlayType function. Example:

Popcorn.player( "youtube", {
  _setup: function( options ) {},
  _canPlayType: function( nodeName, url ) {}
})

The _canPlayType accepts a node name that the player should be playable on. This is usually a html element, and a url, which is the url to the media to be loaded into the node. This function then return true if it can play, false otherwise. If this function does not exist on a player, undefined is returned instead.

To call this function, you do this Popcorn.youtube.canPlayType( “div”, “youtubeurl” );

4. Track event toString functions. Now, once you have a reference to a track event, you can call toString on it. This will return a string of the default data on any track event, usually the start, end and target. You can also add a toString method to the plugin when the plugin is being written, to better handle what to do with non default data. Example:

  Popcorn.plugin( "something" , {
    _setup: function( options ) {
      options.toString = function(){
        return options.start + ", " + options.end + ": " + options.foo;
    },
    start: function( event, options ){
    },
    end: function( event, options ){
    },
    _teardown: function( options ) {
    }
  });

5. We have moved players parsers and locale out of the core, and into modules. You include them much like you include a plugin, and from there on in, everything else is the same. Example:

<script src="popcorn.js"></script>
<script src="popcorn.player.js"></script>
<script src="popcorn.youtube.js"></script>
<script src="popcorn.subtitle.js"></script>

<script>
Popcorn( function() {

  Popcorn.youtube( "id", "url" ).subtitle({
    start: 10,
    end: 20,
    text: "hello world"
  });
});
</script>

6. We now have a shim to support ie8. This is only supported for the youtube player. Some plugins do work, like subtitle and footnote, but that was just a coincidence, and not something we are testing for, yet. We will improve our support for this over time. To include the shim, you have to include it before you include popcorn, like so:

<script src="popcorn.ie8.js"></script>
<script src="popcorn.js"></script>
<script src="popcorn.player.js"></script>
<script src="popcorn.youtube.js"></script>

7. All our plugins have had their manifests updated to supply options flags. This is useful for programmatically reading plugins dynamically. If someone uploads a plugin, and a program reads it in, it may want to know this information regarding options and mandatory data. Popcorn-maker is going to be using this soon. The idea will be when you click a track event to edit it, these will be a collapsible container with all the optional options. This makes a new plugin far less overwhelming, and easier to get at the important data quickly.

8. You can now supply events into a custom players option object. This is useful for listening to things that can happen during the creation process of the player. Example:

Popcorn.youtube( "id", "url", {
  events: {
    "error": function( e ) {}
  }
})

The error function will be called if for whatever reason, the player did not setup properly. This is also useful for knowing if popcorn.smart failed. Example:

Popcorn.smart( "invalidid", "nonsenseurl", {
  events: {
    "error": function( e ) {}
  }
})

So, the above id and url do not match any players, and is not a valid HTML5 media, the error function will be called. You can also put any other event in here, like canplaythrough, loadeddata, play, etc.

OSD 0.7

Posted in open source on March 10, 2012 by scottdowne

This project release was a pretty small release.

I took a r- with some nits, and turned it into an r+.

I mentioned in my last release I tried to get the nits into the last release, but ended up running out of time due to a strange error.

The error ended up being pretty simple, just not something I knew to look for. The answer came to me chatting over lunch with David Humphrey. I was changing a function that was returning a nsresult to return void. I have done this many times, so I know I had to change it in three places. The cpp file, the dot h file, and the return statement itself inside the function. Still would not build, and the error message was not being very clear. I was looking at my code, and not seeing anything I thought was wrong, so I thought it was something wrong with the build process. This was obviously a time sink…

David said right away I am probably returning inside a macro. Ended up being NS_ENSURE_TRUE would return a nsresult. I switched it to a check and return of my own, fixed up the other nits, built it, made a patch, submitted it, and got an r+. This is just a one time cost, though. I will never have to hit this again, and will always know to check for macros when I get weird errors. Also, it is hard to find macros on mxr so now I know to use dxr for this. I have found the macro I was snagged on, on dxr. Can clearly see the return there. Again, this is one of those one time costs, and gotchya moment that will not happen again. Pretty good experience if you ask me.

Now I need tests and to figure out the next step of review. Until then, I am going to look into building a fonts API! Just starting on this, but will have more about what it is about for my next release.

Follow

Get every new post delivered to your Inbox.