Sunday, February 01, 2009

Planning Inkface v0.2

With v0.1.X of Inkface libraries feasibility of SVG based GUI framework is proven. With different experiments, the following structure seems to be evolving.

The inkface library provides canvas objects to draw on. These canvas objects can be implemented using different backends. Currently only X is used as backend. Clutter seems possible, it will be there in v0.2.X. Inkface library loads the SVG elements with the help of altsvg library. altsvg library is responsible for parsing the SVG document and rendering its component elements.

I spent past few weeks investigating the SVG rendering solutions that are out there. There are two major efforts in open source to the best of my knowledge: librsvg (Gnome library, which is the base of current libaltsvg) and Qt's couple of libraries (QtSVG and other being a KHTML component).

They are good libraries with their own advantages and pitfalls. But they are made with a simple purpose in mind - Parse the SVG document and render it as an image. They do not handle the individual elements of the SVG DOM tree in a dynamic way. This is the reason, none of them fully supports animation extension of SVG specs.

In the inkface framework, following two things are expected from the altsvg library:
1. Separate rendering of different elements of an SVG document.
2. Programmatic access to the SVG attributes of these individual elements.


I have spent very long time trying to understand librsvg. It was very painful to get it working the way it works right now. I am not satisfied with the patches I applied on top of librsvg to accomplish the 1st requirement above. (2nd requirement is not available in v0.1.X). I have faced great difficulty to understand the highly recursive logic of librsvg. It will take much larger effort to tweak it elegantly so that both the above requirements are fulfilled.

I also looked into Qt SVG libraries. Qt's code is elegant and easy to understand. But I am afraid, it is tightly embedded inside Qt framework (at least it will take long to tear it and take away what's needed, not sure if that's worth it).

After exploring above two options, I have also considered implementing altsvg from scratch. And that sounds like a better option after all. I have started experimenting with that option. Here are some details.

As the altsvg block shows, there are two distinct components in these libraries:
a) SVG parsing - nothing but a standard XML parsing
b) SVG rendering - librsvg uses cairo and QtSVG uses their PaintEngine for this logic.


I plan to reimplement the SVG parsing part. The rendering will be done by cairo or Qt's PaintEngine. Cairo and Qt's rendering library are mature libraries and their role is orthogonal to the above two requirements of the inkface framework.

Furthermore I figure that the SVG parsing part is not as performance critical as rendering part. But it will have to go through lot of iterations of design and implementation. So I will be implementing it in python. Python's excellent support for XML parsing will speed up the prototyping.

So far I see following advantages of implementing altsvg from scratch and that too in python:

1. It will save energy and time in trying to understand existing librsvg/QtSVG libraries and try to redesign them for the purpose that they might not have been designed for in the first place.
2. Some initial work on this front has proved that, I can totally eliminate the need for a designer to change in XML nodes in Inkscape. They will also not need to explicitly mention the order as an attribute of the element. The order in which the elements are shown in the Inkscape will be recognized by the inkface framework. Also the name of the element can be defined using Inkscape's "Object Properties" option in the context menu.
3. Most of the developers who have inquired about this project, have asked about the portability. The choice of python will help address that issue.
4. It certainly would be a daunting task to aim for a full SVG compliance with my own implementation. But in retrospect, I think that's not the goal. It's not necessary initially to implement all of SVG spec. Some basic features like paths (lines, bezier curves, rectangles, ellipses) and gradients should be available soon enough. They are the most widely used elements. Further features like filters can be implemented incrementally. I suspect, that will be a translation of librsvg's cairo calls to PyCairo calls.
5. I am not sure how can I do this, but a progressive rendering of SVG elements seems possible. It will need more interaction between inkface and altsvg. It will improve load time of the GUI.

There are other two topics as well. But I may address them in some later post. Implementation of inkface (its role in the big picture, the clutter backend) and benefits of using OpenGL for rasterization (Qt has a proven advantage over cairo in this regard. I know glitz can solve this problem for cairo, but I didn't find any numbers to support that)

8 comments:

Anonymous said...

very nice to see some evolution with your project!

i'm also interested on a "replacement" (or enhancement) for rsvg, that can do more than just render whole file or id. but theres one fundamental thing that i haven't yet figured out:

<circle ... transform="translate(x,y) rotate(r)...">

circle = element
transform = attribute
translate = ?
x,y = ?
rotate = ?
r = ?

how do we parse those "?" (transform-list) ones with like lxml/etree?

my little knowledge says that the "translate(x,y) rotate(r)..." is just a value (string) for etree, and we have to write our own parser (and naming?) for that ?

ps. i noticed that inkscape doesn't use a list in transform attribute, instead it uses matrix if your element has more than one transformation... and apropos svg transform matrix, for math noobs like me, this seems usefull: http://www.datenverdrahten.de/svglbc/?code=matrix_reverse

Jayesh said...

Thanks oskude!

You are right about how to deal with the "translate(x,y) rotate(r)" strings.

We are supposed to parse them. SVG spec designers could have made the translate or rotate (or matrix, scale, skew*) as children nodes of transform. But they might have their own reasons for not doing so. The way I would go about doing it is, parsing it myself. My first choice would be to use regex.

Yes, the matrices are complicated. But they are powerful if gotten right, because they can represent all the other special cases - translation, scaling, skew, etc. They are more suitable for machine representation than human readability.

Anonymous said...

and my first choice would be sscanf.
(as it's like the "opposite" of print, easy to use, read and remember)

oh, wait: http://docs.python.org/library/re.html#simulating-scanf ...*sigh*

Anonymous said...

excelent work! i've spent a few time with your code... just an idea, what about an "onclick" event? it will be fantastic to made some traditional guis!

good luck!

Jayesh said...

> just an idea, what about an "onclick" event?

that's fair. So far my target was n810 handheld GUIs, which don't have mice. But as we start using this for other platforms, we will have to implement onClick. I will get it in v0.2

Jayesh said...

Just FYI, this checkin implements the "translate" transform discussed above.

Anonymous said...

This looks like a quite promising project. I'm currently looking into toolkits for the N810 (coincidence? ;)) as the plain GTK+ and Qt dont really satisfy me when it comes to thieir pything bindings and the possibilities to modify the look'n'feel of the GUI elements. I'll probably give Inkface (I like the name, too!) a shot :)

So, keep up the good work!

Jayesh said...

Thanks Yves. I have just posted inkface v.0.2.3.

I have tested it on Diablo SDK. It also has basic Clutter support now.

Check the changelog on mailing list:
http://groups.google.com/group/inkface/browse_thread/thread/a87c068fc7087787