Implementing Silverlight in 21 Days

by Miguel de Icaza

The past 21 days have been some of the most intense hacking days that I have ever had and the same goes for my team that worked 12 to 16 hours per day every single day --including weekends-- to implement Silverlight for Linux in record time. We call this effort Moonlight.

Needless to say, we believe that Silverlight is a fantastic development platform, and its .NET-based version is incredibly interesting and as Linux/Unix users we wanted to both get access to content produced with it and to use Linux as our developer platform for Silverlight-powered web sites.

Am now on a flight to Paris to show the results of 20 days of intense work that the team has implemented. It is hard to contribute to the effort sitting on a plane when the tree is changing every 10-20 minutes.

There is technically still some time left to improve what we can show.

You can see our screenshot-log to see our progress or the Moonlight Project Planning Page.

Testing Silverlight on Linux

At this point we do not have a packaged release of Silverlight for Linux and we still have to sort out a few things that would have to be done in order to ship a ready-to-use plugin.

But if you are curious or want to contribute to the effort check our page for information on downloading, compiling and getting started with the project.

Demo of Silverlight Airlines Demo

Progress on the Silverlight Airlines, June 20th.

How the Hackathon got Started

At the Mix conference this year, after the open source panel, I had a chance to meet with Marc Jalabert from Microsoft France who invited me to participate in a re-play of the Mix event in Vegas, this time in Paris.

Although Marc had sent me an email on May 9th, I did not notice his email until he pinged me back again on the 28th of May and got his confirmation on the 31st to participate at Mix in Paris. On the 31st he suggested:

We suggest you speak during the conference keynote and show a preview of moonlight if you already have something to show.

But on the 31st, other than having learned about Silverlight, explored how to decode video, experiment a little with video and started planning for an implementation we had nothing to show. Nothing am telling you. Also, May was a busy month for me HR-wise as we were hiring new developers to join the Mono team.

By 1pm on Thursday the 31st, I posted this to our internal Novell Mono mailing list (edited to remove all the embarrassing parts) calling for a hack-a-thon:

  Hello folks,
  
      The organizers of ReMix 07 in Paris (ReMix is the repeat of the
  Microsoft Mix conference) have offered us a 10 minute slot to talk
  about Mono and demo whatever it is that we have done with Mono's
  Silverlight.
  
      There are two problems: other than a video (rendered in blue,
  instead of natural colors) and a rectangle that moves, we do not have
  much.
  
      The second problem is that this event is in June 21st so that leaves
  very little time to get things in shape.
  
      Now, it might very well be the case that we should not show anything
  and we should not rush things out, but it is also a major opportunity,
  and I think it would be foolish not to take advantage of this.
  
      I do not think we need to demo things embedded in the browser, but
  it would be useful to demo something loaded from a XAML file (video,
  rectangles, bezier paths, and some limited maybe C# controlled
  animation, to avoid doing the full animation framework).   
  
      Issues:
  
          * We have a XAML parser written in C# but I have not checked on
            its state nor checked whether it can do more than just the
            basics (like doing data type conversion).
  
          * Microsoft suggested (and made a good point for it) that the 
            XAML parser be implemented in native code (as 99% of the 
            objects created by XAML are never manipulated by managed
            code).
  
            So we will end up with a C-based XAML parser, whether it is 
            a good idea to do this now, and not reuse the managed one
            is open to discussion.
  
          * Other than the rectangle (that is currently not even
            rendering) and the video (without audio) I got nothing.
  
          * We would need to bind the C implementation to C#, and I think
            that we can use the same model that Mike used for Gtk#.
  
            Not gapi, but the overall model where we mirror the class
            hierarchy in C# that exists in C++ (in this case, the class
            is determined by C#, not by C++, but you get the idea).
  
          * I have decided to use Cairo for now (David convinced me on 
            the grounds of hardware acceleration).
  
      We would need a dedicated hack team to drop whatever it is that they
  are doing for this noble cause.    The question is: who wants to
  participate in an intense two-week hackathon to make it happen?
  
      Obviously, not everyone can work on this at the same time, and
  having too many people would make things difficult to coordinate.   But
  who is interested?
  
  Miguel.
  	

We modified the Silverlight Surface demo to show a live clock and the Mono Logo.

The Team

The team was assembled quickly in response to the email, a limited group from the Mono team to avoid having too many coordination conflicts.

Sebastien, our resident security expert and also maintainer of our GDI+ implementation was the first to reply an hour after my posting. Sebastien would in the next few days be in charge of implementing most of the rendering primitives:

  Me. I haven't looked SL much outside the new security model (and I have
  the feeling this isn't what you have in mind for the demonstration ;-)
  but I have heard about that Cairo-thing.

Jackson who in the past worked on our IL assembler and has been working for a few years on our managed Windows.Forms implementation and been maintaining the Tree and Text controls in Windows forms followed up with:

  I'm in.  Not exactly sure which area would be best for me to get started
  on, so if anyone has suggestions...otherwise I'll just pick something
  without the words text or tree in it.
        

Jeff Stedfast, who had been working on MonoDevelop for the last couple of months and works with me in the Cambridge office followed up:

  I am down with the dope!

  count me in.
	

Jeff's first task would be to fix audio in the media player. He would eventually rewrite the video playback engine so we could provide Video brushes in all of its glory and implement the audio support.

Some other people signed up on IRC, so I do not have their early sign up messages. By Sunday things started to get in shape team-wise. Some folks had started work already and became the de-facto maintainers of those pieces of code:

  • Jackson started work on the Expat-based XAML parser (we wanted to use a small XML parser so we can eventually make this a small download as well).
  • Everaldo started work on the browser plugin.

At this point I got the feeling that "DependencyObject" and "DependencyProperty" might be playing a role more important than I had originally thought of. My initial reaction to DependencyObject was a mix between "ugh" and "its kind of clever". At the time it seemed important, but did not quite grasp its importance, I asked Rolf (of Visual Basic compiler in Visual Basic) fame to take over that.

Eventually we would end up with a complete type system and I would describe if it wasn't for the fact that it is still changing and being refactored. Our "Value::Kind" enumeration just vanished and became part of our "Type" class in a valiant effort by Rolf to clean up the code base.

Chris Toshok started work on timelines, which as a dependency required him to start work on transformations as well. He would later take over the entire animation, clock, and frame rendering infrastructure pieces.

The rest of the Mono team was charged with keeping an eye on the rest of the project, continue to fix bugs and provide us with cover for our fresh project. They also would help when we ran into problems (like helping out with performance on Monday the 18th when we were things were not looking great for the Surface demo).

In addition other Novell employees (Atsushi Enomoto, JB Evain, Marek Safar and Mark Probst) are indirectly working on Moonlight. JB by improving Cecil and his Linker (originally funded by the Google Summer of Code, thanks Google!) that would allow us to shrink our existing assemblies into assemblies that would be identical to the Silverlight ones.

Atsushi has done most of our WCF platform, JSon serialization, Marek by implementing LINQ for our C# 3 compiler and its underlying infrastructure and Mark will be working on the JIT support for the new Silverlight security system and of course everyone else in the Mono team that continues to improve our runtime.

Various members from the Mono community have also contributed to Moonlight directly or indirectly through their contributions to the Olive sub-project: Stephen, Joel, Olivier, Antonello, Marek and many more am missing.

The Development: Early Choices

My original plan was to write the low-level rendering engine in C and expose some sort of "scene" API that the managed world would control. With only a few primitives and a handful of operations on those primitives this idea sounded passable. The first code checked into the tree was written in C with the usual Gtk+-like programming pattern and a glib-like object system.

The early tests of Silverlight content rendering side-by-side with SVG content.

There were a few factors that altered the design: the advice from Scott Guthrie and Jason Zander during my trip to the Compiler Lab; David Reveman's [1] (the wizard behind Glitz, Xgl and Compiz) suggestion for moving the engine into the compositing manager and early changes to the class hierarchy that moved me away from C.

I discussed with Scott Guthrie and Jason Zander that I wanted to do as much as possible in managed code, but they made an interesting observation. XAML content might have a few thousand objects defined here and there, but most applications would only care about a couple of high-level objects: a handful of buttons, handles, animations, and so forth but it was not worth having all of those objects in managed memory and for a graphics intensive system we wanted to minimize the number of managed to unmanaged transitions.

The above being said, in 20 days we really had no time to implement two versions and compare whether these assumptions were correct or not.

The other consideration to move away from C# to C at the time had to do with the early conversations with David Reveman who wanted to hardware accelerate this. The idea was to turn the Silverlight high-level operations into a scene description that we could transfer from the client applications directly onto the compositing manager (On modern X installations this is what actually puts the bits on the screen and what has enabled all those spicy effects like the rotating cube).

The idea here is that the Silverlight client could detect if it was running under a compositing manager that offered rendering on the server and it would off-load all the rendering to the layer that can talk directly to the OpenGL hardware.

As the hack-a-thon got started and I started introducing a C-virtual function here and a C-virtual function there, the second time I had to change the hierarchy I got annoyed, bit the bullet and moved the code to C++.

We kept our use of C++ features to a bare minimum, it helped us in quite some cases and in some other cases we hated it. A proper rant about C++ will have to wait for another day.

At least we stayed within the confines of the "C" family of languages.

[1] David Reveman is one of the main wizards behind the graphics revolution going on in Linux: Glitz, Xgl and Compiz. He also happens to be based in the Cambridge office and host an international crowd at his fabulous apartment for drinks.

Communications

The project was originally organized over email but the day-to-day technical discussions moving into a private IRC channel.

We did use email as a way of communicating with some of the developers on other time zones to either pass the baton and as a poor man's bug-tracking system.

We did have a handful of one-to-one phone conversations when we started to merge things together: some components were independent of each other and due to the hacking intensity during this period.

The crowd in America would go to sleep and Atsushi (Japan) and Rolf (Spain) would take over development for the next eight hours until we were able to catch up again: Everaldo in Sao Paolo, Sebastien in Canada, Jeff, Alan in Boston and later Jackson, and myself on the East Coast (due to our sleeping hours) and Chris on the West Coast.

This is basically how we do things in the Mono team, except this time we were under tight pressure.

The Documentation

The .NET API to Silverlight shipped with very little in the form of documentation, but a lot of it could be inferred from the Silverlight 1.0 API and from the WPF API.

The Silverlight .NET API is a flatter API than WPF is, but in some cases (the work that Chris did on animations) we would internally on the C++ side implement some of the classes that are found on the bigger brother of Silverlight as support infrastructure for it.

The API reference that we used was what was available on the Visual Studio Object Browser (or Mono's equivalent command line tool: monop).

Second Week

Alan McGovern (of BitSharp fame) would be arriving to Boston a week after the hack-a-thon and we asked him to start work on a Silverlight-based designer and on bits of the C# API (exercising our C++ code).

At this point the class hierarchy was no longer the "early" check-in that was more focused on "scenes" but instead mirrored the C# API one-to-one. Also, the type system had been in place and we had to come up with a mechanism to provide the equivalent to object identity and boxing to communicate between C# and C++. Keeping the two sets of typecodes in sync had become a source of frustration which lead to Chris and Rolf to write some sanity checking scripts and auto-generate one from the other.

During this week the C# binding came to life. We had been doing all of our work in C++ and testing every new class by sticking the new object, brush, opacity setting, transformation, animation, storyboard and flag into a single demo. One ugly demo with CNN and the Colbert Report spinning on the background.

The object system was designed with reference counts in mind, similar to The GObject system and also has the notion of "sunk" references. By the end of the week we had not really paid much attention to proper object management and ownership and problems started to creep up when we had to properly shutdown (say, when loading a second XAML file in the same Surface that might have been animated).

Chris fixed the reference counting before the weekend and we closed the week. This is more or less what happened during the week, based on my partial log:

June 14th:

  • Text renders (Jeff).
  • Radial gradients (Sebastien).
  • Attached properties are now handled by Canvas on changed children.
  • Implemented the downloader (Toshok).
  • Managed downloader (Miguel).
  • Mouse enter/leave events (Miguel).
  • It is possible to load images from the net
  • everaldo gets plugin using <object> embedding instead of the hack we were using.

June 15th:

  • Inlines and Runs in text
  • Performance improvements
  • Mouse event routing to individual objects.
  • Loading of custom objects from XAML files using assemblies.
  • Everaldo gets plugin to change surfaces with javascript.
  • Sebastien starts work on porting the surface to Gtk# with Silverlight, just in case.

June 16th

  • Loading of xaml dependency files (Miguel, Jackson).
  • Toshok optimizes rendering using bounding boxes.
  • Jackson hooks this dependency loader.
  • Jeff refactors the video engine to make it reusable.
  • C# bindings.

June 17th

  • Jeff implement VideoBrush
  • Sebastien implements the various image properties, so that they render with the specified parameters.
  • Event system updated, Surface now gets events in the correct order.
  • Animation parser fixes, surface animations are now properly timed.
  • Everaldo added support for XAML content in HTML pages (referenced with '#' in a url).
  • Jackson got support for x:Class on XAML loading.

June 18th:

  • Rolf implemented support for nullable types in the Moon typesystem and bindings to map Nullable in the C# code to our C++ Nullables.
  • Jeff implemented support for having VideoBrushes share a MediaElement.
  • Jeff implements brushes for Runs.
  • Paolo helps with the profiling of Moonlight's Surface and helps us get interaction smoother.
  • Chris and Sebsatien worked on tuning the performance for rendering on the screen.
  • Chris improves animations and screen refreshes, and sets up xlib-based image surfaces.
  • Jackson completes Path Data parsing, the underlying infrastructure was done by Sebsatien enabling the remaining samples from Sam Ruby's sample site to render.
  • Jackson and Sebastien implement the various segments that are missing for the Path rendering
  • Jackson implemented XAML support for <Run/>

June 19th:

  • Javascript bridge to DependencyObjects works, the Javascript-controlled XAML Clock sample works now.
  • Collection iterators are implemented
  • Work on proper browser shutdown.
  • Many missing managed bindings are implemented by Rolf.

Some stats

In the last 20 days, the team:

  • Made 1,228 commits to the SVN repository (Everaldo was the lucky commiter for revision r80000 in our tree).
  • Wrote 24,373 lines of C++
  • Wrote 1,367 lines for the C# binding to Gtk# and the Mozilla C# host.
  • Wrote 13,207 lines of C# class libraries (not including the ongoing work on an open source Javascript compiler for the DLR from Olivier, nor including the fine work going on to implement LINQ, nor upgrade our C# compiler and runtime).

What Worked And Did Not Work

There are various factors that I think worked very well for the project:

  • The availability of Cairo.
  • Pango for doing text rendering.
  • The team background and familiarity with Mono, C#, C, C++, Gtk+, X11, Cairo and Pango.
  • Valgrind. Best C/C++ debugging tool in the world. When the bugs get nasty Valgrind was able to pinpoint the problems while we mixed Mozilla, Mono, Cairo and our runtime library.

Some of the things that we need to sort out and have been problematic:

  • Cairo performance, we probably need to learn how to better employ Cairo, but there are some bottlenecks in there that are quite bad.
  • Alternatively we can mix rendering with Cairo with rendering with Antigrain (shared RGB buffer) or we could explore replacing Cairo with Antigrain.
  • Cairo does not offer options to render the end cap and start cap differently.
  • Cairo needs to offer an "alpha" enabled version for sources, not only "_set_source_rgba", but allow the "a" to exist for patterns and sources.
  • Pango text rendering with Cairo, two problems:
    • Rotated text looks terrible and even miss-aligned. Antigrain has a "round-off" mode that makes these rendering glitches go away, it would require us to port pango-cairo to use Agg though. See what it looks like.
    • Ligatures do not seem to be implemented, this is a problem for rendering arabic strings as it renders each character in its standalone form instead of the linked way. Pango does this, but we could not figure out why it does not work with Cairo (see image showing Linux spelled in Arabic).

Future Directions

I did not think we would be able to get this far in 21 days, I was hoping at most to have a simple XAML file loading and some animations going but the team really achieved an incredible project . I think we are still quite impressed that it could be done.

But there is still much work left to do to before we can work flawlessly as a Silverlight plugin.

There are still some important chunks of work missing: from ensuring that everything we have implemented is complete to completing large chunks of work that are still missing.

One of the major areas that needs work is the C# to browser integration as well as improving the browser plugin which only recently started working. Some work has been done (all on our public SVN repository) but the pieces came in too late to be integrated.

We have a to-do list for some of the remaining tasks.

Future Directions: Gtk# Widget and the Gnome Desktop

Although Silverlight is intended to be used in a web browser we think it would be very useful to Linux desktop programmers to have Silverlight reusable as a widget.

We already have been talking to a few folks about how we can help them improve and spice up their desktop applications with Silverlight. Obvious choices are all the existing Gnome/Mono based applications, but ever since we got started on this, the idea of writing a "Media Center" sort of UI has been making the rounds.

I have for years talked about my desire of having a "Flash on a Widget" widget for Gtk+, an idea that was not very popular back in the days when Flash was considered only a technology to do animations.

We finally have such a widget and it can be scripted, hosted, embedded or extended from any ECMA CLI compliant language: all the traditional static languages for .NET as well as the new batch of dynamic languages that take advantage of the Dynamic Language Runtime (DLR).

Larry of F-Spot fame for example has already prototyped F-Spot integration with the Surface demo:

He also has this mode printing PDFs already.

Future Directions: Media Codecs

Currently we are using the fantastic ffmpeg video library but for the sake of distribution in some countries we might have to write a new video/audio backend.

Novell will be requiring copyright assignments or contributions to be made under the MIT X11 license to Moonlight to ensure that we can ship this plugin with proprietary drivers if necessary (and also to relicense Moonlight for embedded system users).

Future Directions: Silverlight Designer

We will be working on a simple designer for Silverlight written in Silverlight itself. We hope to achieve:

  • Allowing Linux users to develop rich user experiences in Linux without having to learn XAML by memory or requiring a Windows machine with Blend to design UIs.
  • To integrate this directly into our MonoDevelop IDE so people can create web sites using Silverlight (Michael Hutchinson of aspnet-edit, another Google SoC graduate will be joining us in September).
  • By developing Silverlight in Silverlight we will also allow the MacOS crowd that currently can consume Silverlight content but not produce it to participate in the production ecosystem.

Future Directions: Logo

We need a logo for the Moonlight project, so we can print T-Shirts.

Jackson suggested on irc for the Silverlight Airlines demo:

<jackson> also, we should totally add snakes, time permitting

Contributing

If you want to help on the effort, the best thing to do is to get the source code, instructions are here and post your questions or suggestions to the Mono Olive discussion group.

Posted on 21 Jun 2007