Dynamic Personas - How They Work

The recently released update to the Personas extension includes support for dynamic personas, which are personas that change over time.  Here's a technical overview of the history and present condition of the feature (for a non-technical overview, see the labs blog).

Take One

Original discussions for making personas more dynamic started with the idea of building an API for them to specify a series of background images and when to switch between them.  But the more ideas we had about what personas might want to do, the more complicated this API became.

I wanted something both simpler to scale to more complex functionality and more powerful right off the bat, so I suggested we simply stick iframes behind the browser chrome at the top and bottom of the browser window, let personas load any web content (HTML, SVG, etc.) into them, and let them update themselves as needed ajaxically.

That seemed promising, so I prototyped it by XBL binding the top and bottom chrome into XUL stacks, making their backgrounds transparent, and sticking iframes underneath them.

That worked great until I locked down the iframes with type="content" for security, at which point they were hoisted to the tops of the stacks and covered up the browser chrome.

I asked about this on IRC, and roc pointed me to bug 130078, which won't be fixed in Gecko 1.9.  So I had to find a different solution.

Take Two

The one I hit upon, which is in the latest release, preserves as much of the web content magic of the original solution while still working (safely).  And it still enables personas to change over time, albeit not as rapidly.

The extension creates two iframes in the hidden window, loads the persona content into them (which can still be any web content), takes a snapshot of them using the canvas 2D context's drawWindow method, converts the snapshots to data: URL-encapsulated PNG images using canvas's toDataURL method, and then makes those images the background images for the top and bottom chrome.

Rinse and Repeat

The extension then leaves the persona loaded in the iframes and periodically (once per minute by default) updates the browser chrome with new snapshots.  And occasionally (once per hour by default) it reloads the persona from scratch, although personas are of course free to update themselves more frequently.

Once per minute is obviously not fast enough for animation (like an aquarium with fish swimming around in your toolbar), but it's fast enough for gradual changes, like a panoramic landscape that darkens as the sun sets or a pictorial depiction of the weather report.  And there are plenty of interesting personas for which this update frequency is fast enough.

(Incidentally, one can jack up the frequency with a hidden preference, but doing so is not recommended, since it could impact performance).

Bits and Pieces

When dynamic personas change the background, the optimal foreground color might change too, so the extension sets the foreground (text) color to the one specified on the root element of an HTML dynamic persona.

For example, Heldenhaft's Paderborn, Germany panorama persona is dark at night and light in the daytime, so I adapted some code from an NOAA Sunrise/Sunset Calculator to enable it to determine the status of the sun at its location and set its foreground color appropriately.

And if you want to test out this "any web content" claim, just select Preferences... from the personas menu, press the Custom Persona Editor... button to open the custom persona editor, and enter any URL (f.e. http://www.mozilla.com/) into the Header or Footer fields.  It might not be pretty, but it'll show you a chunk of the page behind the chrome.

Locking it Down

The code is a actually bit more complicated than described above, because the hidden window is an HTML document on Windows and Linux, and HTML iframes can't be locked down with type="content".

So instead of creating those iframes in the hidden window, it creates another iframe in the hidden window that loads a XUL document that contains the two iframes that load the persona content.

Tests like this one (and a version that tests the personas code directly) demonstrate that the content iframes are indeed locked down, so while personas can do anything web content can do in a browser tab, they can't break out of the content jail and access chrome UI or capabilities.

The only thing injected into chrome is static PNG snapshots of web content.

Of course, if you can think of a way around that or another security issue, I and other Personas hackers would be very interested in your thoughts.  To confirm your suspicions, install and test the extension or peruse the code online.


Tomer said...

RTL locales don't get it correctly since its browser UI is mirrored. Can you add a function that will mirror the skin just before the DrawWindow function? ‎This will make the extension usable to any Arabic/Hebrew user and it looks not to complicated to implement.

You can detect the UI direction using (chromedir=='rtl').

Myk said...

tomer: good point. I have filed this as bug 18895.

Jesse Ruderman said...

Do you prevent the hidden frame from popping up dialogs with alert(), bogus protocols in iframe srcs, etc?

Myk said...

jesse: no, but we do have the ability and reserve the right to disable personas that misbehave.