Platform/GFX/Moz2D
The Moz2D graphics API, part of the Azure project, is a cross-platform interface onto the various graphics backends that Gecko uses for rendering such as Direct2D (1.0 and 1.1), Skia, Quartz, and NV Path. Adding a new graphics platform to Gecko is accomplished by adding a backend to Moz2D (see #Implementing a new backend).
Some of the notable features of the API are:
- Mostly stateless—better suited to CSS rendering and eliminates overhead
- Floating-point—better suits platform APIs
- API methods line up with HTML canvas
Current status
The Gecko graphics API preceding Moz2D was Thebes which consists of a C++ wrapper around Cairo, some Gecko-specific utility code, and a text API that uses platform text handling. Currently both the Thebes API and Moz2D API are in use. A Thebes wrapper around Moz2D allows code that still uses the Thebes API to run on top of Moz2D. Over time this code will be migrated to using the Moz2D API directly (see Azure Conversion).
Once the Azure project is completed—that is, all the backends have been implemented and all the calling code converted to use the new Moz2D API—the old Thebes API will be removed.
Side note: For historical reasons, there are some classes with “Thebes” in the name which will be surviving this process as they're not actually part of the graphics API. They may get renamed eventually, to reduce the number of magical words you need to know about, but be warned that just because some code has “Thebes” in the name, it does not mean that the code is on its way out!
See also:
- Progress on Moz2D - July 2013 update
- Azure Conversion
Stateful vs stateless
Many of the performance gains anticipated from Moz2D come about due to its mostly-stateless API.
Stateful APIs
The Thebes API wrapped the Cairo graphics library which uses a stateful context model much like Postscript or Quartz 2D. To draw content, you make individual API calls to set up various bits of state in a context object, followed by another API call to actually perform drawing. For example, to stroke a shape with a dashed line, you would typically set the color, set the line width, set the dashing style, start a new path, emit path segments, and finally draw the stroke—all as separate API calls. In Cairo, even drawing an image requires the caller to set the source surface, emit a rectangle path, and fill—at least 6 API calls.
The overhead of setting up state can be justified when that state is re-used, but for CSS rendering this is typically not the case. Rather, for each item that is drawn fresh CSS values are fetched and re-set. Because the browser does not know what it is drawing, it is unable to group operations and re-use state effectively.
On the other hand, the HTML5 canvas element has a stateful API but because its state-tracking differs from that of Cairo drawing state must be tracked twice: once for canvas and once in Cairo.
A further complication specific to Cairo arises because internally Cairo uses a stateless surface API. On OS X, Cairo uses its Quartz backend for all drawing. However, when using Cairo, despite the fact that both Firefox and Safari ultimately use Quartz as their backend for drawing, Safari is faster than Firefox on some demos. We believe one reason this is the case is because Quartz is stateful. As a result, Cairo needs to convert from its stateful API to its internal, stateless surface API, then back to Quartz’s stateful API.
The Moz2D API, despite being mostly-stateless, was designed to map onto stateful APIs like Quartz in a more efficient manner.
Moz2D: Mostly-stateless
Almost all the operations on an Moz2D DrawTarget (see #Draw targets below) take relevant state as parameters and do actual drawing. The only state carried by a DrawTarget is the destination surface itself plus a current transform and a current clip stack. We let the transform and clip state remain in the DrawTarget because those are the only pieces of state not constantly reset by CSS rendering. Our CSS rendering needs to always render under some given transform and clip and we don't want all our rendering code to have to pass those around all the time. Because of this, the Moz2D API is called mostly-stateless.
Learning Moz2D: Introducing the API
Source surfaces
Draw targets
Developing Moz2D
Building Moz2D
Testing Moz2D: Player2D
Implementing a new backend
Further reading
The following resources describe the motivation for and goals of this API: