monday, 18 february 2008

posted at 11:03

A couple of hours work on yesterday's effort, and we see this:

Had I known just how close I was, I probably wouldn't have even bothered posting yesterday.

The wonky text was because a stupid assumption I made in cairo's font code, which I've now fixed. The text still looks crap, mostly because of issues with the renderer, but I've been pointed at TTEngine this morning which looks much more like what I want and would let me remove some of the hacks I've had to do in cairo. I'll be looking at this further this week.

There's still a hell of a lot to do, so don't get too excited. At least now I have a way to see whether or not my changes are actually doing something or not.

I'll be posting many more screenshots as work progresses, but I won't be blogging them all. Things are moving just too fast for that. If you want to follow the screenshots, watch my screenshots set on Flickr or just subscribe to its feed.

sunday, 17 february 2008

posted at 09:46
Current progress:

This is WebKit on AROS rendering a trivial page containing a H1, a H2, a DIV with CSS styles set to force to 100x100 with a green background, and a IMG of a pirate, though thats not working yet.

The text alignment appears to be screwy because my code in cairo is not correctly calculating the baseline on tall glyphs. It works as expected from my cairo tests though, so I'll need to dig a lot deeper to figure this out. Likely I just missed some mundane detail; font metrics are actually quite difficult and I'm not help by the fact that the bullet interface doesn't provide away to get the metrics for the font as a whole, meaning I have to generate them in a rather horrible way.

There's also an issue where if a line of text is wrapped (eg if I resize that window to be really narrow), only the last line is rendered. I still haven't looked into that yet. Oh and of course there's a bunch of internal stuff that really isn't correct but won't noticeably affect the outcome just yet.

All in all, not bad progress so far. Its only going to get more difficult as I really get into the details, I think. Not to mention the many many shortcomings in services provided by AROS, which are going to need to be addressed if this thing is to look nice and not be insanely slow. I'll write more about that lot later.

monday, 11 february 2008

posted at 09:07

AROS work has slowed down over the last week. There's been a lot of email to reply to (I won't mention the topic :P), and I've doing some web work on the side, but I've still had a little time to work on cairo, which I'm now calling finished, at least for the moment.

The big thing I was trying to get going was the shared library stuff; ie having a shared cairo.library. I got this working, but programs are crashing because cairo has globals, a fact that I'd overlooked. It only has a couple, but they're rather important. Once again, I'm not willing to make the large changes required to remove the globals because I want to keep the changes to upstream to an absolute minimum. Once AROS has proper support for global data, then this code can be resurrected.

So cairo works, but is noticably slow. That mostly comes from it doing all its rendering in software and then blitting the results into the AROS graphics subsystem. Working slowly is good enough for me at this stage.

Fonts work, with the following issues:

  • Non-scale transformations (rotate, shear, etc) don't work as the necessary API is not exposed via bullet. Scaling work, buts only vertically - again, missing API. Basically the only cairo API that is of any use for glyph transformation is cairo_set_font_size().
  • The font tests don't pass. The first reason for this is that font sizing on AROS is not the same as on other systems. As far as I can tell the bullet interface to FreeType is recalculating the metrics to better match the traditional Amiga way of talking about metrics, with the downside that it makes the glyphs smaller than they should be. Additionally, there's no way to get the display device DPI under AROS, making it quite impossible to have FreeType adjust the scale appropriately.
  • The other reason the tests don't pass is that spacing between glyphs is wrong. A typical line of test rendered on Linux will have pretty much even spacing between each glyph. The same text rendered on AROS has uneven widths. I haven't been able to determine the cause of this yet.

The font problems shouldn't be an issue for WebKit as it does its own font work, though it will still hit the underlying font system so its likely the same issues will appear in other contexts. Again, I'll just do the best I can.

So this afternoon its back to WebKit! There's been many many changes there in the last month, so the first step will be to just get my stuff building again.

tuesday, 29 january 2008

posted at 10:12

I'm at this week and because I'm so well practiced at listening to people talk while doing something unrelated on the laptop (thanks dayjob), I've got a hell of a lot of code done, making up for the nothing I did over the weekend.

Yesterday I finally got text rendering happening via cairo:

There's not really a lot to say about it. The hardest part has been converting the glyph metrics that come back from the bullet glyph engine into cairo's glyph metrics, as they haven't a slightly different view of the world.

The code is still rather messy and incomplete. I still have to handle the font matrix which will allow arbitrary scalings, rotations, etc. Smarter font selection is needed as well as using the algorithmic emboldening/shearing stuff to provide fonts that don't exist. At least its all downhill from here.

tuesday, 22 january 2008

posted at 13:29

Things got a little slow in the last week. I spent last week tweaking bits of graphics.library and graphics.hidd to force the alpha channel to be set when calling ReadPixelArray() on a surface that has no alpha (so it can be fed directly to a cairo surface with alpha). Each attempt worked, but also introduced subtle incompatibilities into the Cybergraphics API. I still think its important to have (along with software alpha compositing, which is an entirely seperate issue), but it can't be done comfortably via the current API, so for now I just post-process the returned pixel data and force the alpha channel on before handing it to cairo. I don't like it, but it will do, and it makes it possible to use any system bitmap as a source. So now you can use cairo to take a snapshot of the entire screen with this simple code:

    struct Screen *screen = LockPubScreen(NULL);
    cairo_surface_t *surface = cairo_aros_surface_create(&screen->RastPort, 0, 0, screen->Width, screen->Height);
    cairo_surface_write_to_png(surface, "snapshot.png");

I've now turned my attention to the font backend. Its taken me a while to even begin to understand it, because I know basically nothing about font rendering, but I think I'm at least starting to see what's going on. I began an implementation based on the graphics.library functions for font rendering, but it really felt wrong as the interface really doesn't seem to support much - very few facilities for controlling rendering options, limitation to ASCII, etc. It seemed that there must be something more powerful available, as its clear from just loading up AROS that we support TrueType fonts and non-ASCII characters.

After a lot of digging, I found out about the existence of the bullet.library interface for outline fonts, and our implementation of it in freetype2.library. From there, to Google, where I discovered that there's next to no documentation out there for it. I did find reference to a document in the AmigaOS 3.1 development kit, and a quick ask-around in #aros gained me a copy of BulletLibrary, which I offer here for reference.

The interface is complicated, but appears to have most of the features I need to map to cairo font functions. I have no idea how it will go, and I imagine our implementation is deficient, but I will write some tests this afternoon and see what I can do with it, then start hooking it up to cairo.

friday, 18 january 2008

posted at 20:06

As far as cairo is concerned, its backend buffer get/set methods are only required to store and retrieve pixel data in the format requested by the cairo core. It does not have to do fancy conversions. It does not have to do alpha stuff. Presumably you'd want it be convertible to the host graphics system, but cairo itself doesn't care about that.

wednesday, 16 january 2008

posted at 12:21

Cairo is working! So far I have RGB and ARGB surfaces working, and so still have alpha-only surfaces and fonts to do, but that is enough to make the majority of the test suite work. I actually had the basics working on Thursday, but the colours were all messed up, and it took five days to track down all the issues and fix them. I won't go into the process, because its peppered with dead ends and misunderstandings, but here's what I've learnt:

  • CyberGraphics is a big-endian interface. That is to say, when you request ARGB, you will always get the same byte ordering on little and big-endian machines. This is different to cairo, where specifying ARGB will get you the ordering of the local machine. What this means is that on little-endian machines when converting from AROS bitmaps to cairo surfaces, I have to request BGRA format from ReadPixelArray() but then tell cairo its ARGB, and vice-versa.
  • When AROS converts from a bitmap with no alpha channel (eg RGB) to one with alpha (eg ARGB24), it will set the alpha in the target bitmap to 0 (fully-transparent). When feeding the target into cairo, which knows about alpha, it basically does nothing as it sees that all the pixels are fully transparent. I've already done a rather naive fix in AROS for one case, but there's still a case where the graphics library, realising that a conversion from a non-alpha format to a 32-bit with-alpha format is requested, rewrites the target format to be 32-bit no-alpha (eg 0RGB), thus leaving the alpha set to 0 again. I'm working on a more generic fix.
  • WritePixelArray() has no support for software alpha compositing. That is, when using it to blit a 32-bit with-alpha bitmap to another bitmap without alpha, the alpha component is ignored rather than computed in software. Ironically, alpha compositing code exists for WritePixelArrayAlpha(), so I'll also be looking at factoring this code out into a generic function and having both calls use it.

Once I get this sorted, I have a very cute piece of eyecandy in the works to demonstrate to you all just how powerful cairo is, and just how easy it is to use. Hopefully I'll have something to show in a few days, then I'll get back onto the font support.

wednesday, 9 january 2008

posted at 09:17

With the help of WebKit developers I finally sorted out the crasher that plagued me over Christmas, and now I see WebKit making network requests, receiving data and calling into the graphics code to get it on screen. The next step is to begin implementing this graphics code.

As far as I can tell I need support for both blitting objects (like images) to the screen, but also need drawing primitives, both simple stuff like lines, circles and rectangles as well as complicated things like Bézier curves and arbitrary paths. It needs to be able to apply a transformation matrix to both paths and images. It needs compositing support. It also needs to be able to operate on screens of arbitrary size and depth.

AROS (and the standard Amiga API) can't support this. Some of it exists, just not enough. graphics.library has basic drawing primitives but not advanced stuff like splines and such. Its primitives don't operate reliably on TrueColor screens, which is what pretty much everything is these days. CyberGraphics provides access to higher-depth modes, but only really for blitting. And we have no support for affine transforms, compositing, or other advanced features.

To Commodore's credit, its pretty clear that they were moving in this direction. They had these concepts on the market in a time where they were barely even considered elsewhere. I'm quite sure that were they still around today we'd have these features available. Sadly, we don't, so we must find another way.

I've studied the problem in some depth, and I've decided to port the cairo graphics library to AROS. Their description sums it up well enough:

The cairo API provides operations similar to the drawing operators of PostScript and PDF. Operations in cairo including stroking and filling cubic Bézier splines, transforming and compositing translucent images, and antialiased text rendering. All drawing operations can be transformed by any affine transformation (scale, rotation, shear, etc.)

A port will be a good thing for everyone. WebKit already has a cairo graphics target, so I'd get my rendering for free. The library is extremely portable, with a great target abstraction. Indeed, I already have the thing compiling and the AROS backend stubbed.

More controversially, I think cairo could actually become the core 2D graphics system for AROS. graphics.library could be trivially implemented on top of it for compatibility, so there's nothing to worry about there. We'd implement a cairo backend that talks to a stripped-down version of our graphics HIDD layer (as much of their functionality would no longer be necessary). Once it place it would give easy support for eyecandy like real transparent windows or something like Exposé. Combine that with the plan to get 3D via Gallium, and AROS could become the shiniest thing out there.

My port will be a proper AROS-style shared library, cairo.library. Cairo's code is clean enough that I think I can do this without requiring the API to change and while still making it possible to contribute all the changes upstream without adversely affecting them.

Port repositories: cairo and pixman. These will be combined in the final library.