Tuesday, 30 November 2010

Coding antipatterns: excessive nesting

With apologies to Dave Neary for stealing his excellent word, 'antipatterns', from his talk at MeeGo Conference.

This is an opinion piece. Feel free to skip it if you already know what you're doing when writing code.

We all have things we dislike in code, sometimes it's indentation, sometimes it's a bit less trivial. One of my current pet hatreds is excessive nesting.

For those of you that don't know what I mean, if you see something like this:
void foo(bool bar, bool lol, bool hax, bool meep)
{
    if (bar) {
        if (lol || hax) {
            if (meep) {
                // do something
            }
        }
    }
}

Then you're probably a victim of excessive nesting.

If you're writing code like this then all I can say is you're probably doing it wrong.

That above example might be written better like so:
void foo(bool bar, bool lol, bool hax, bool meep)
{
    if (!bar)
        return;

    if (!lol && !hax)
        return;

    if (!meep)
        return;

    // do something
}

Generally speaking, you want your code to be like a river: to flow from one point to another, and branch off gracefully, but still continue flowing nonetheless.

In more technical terms, this makes it a lot easier to take appropriate actions at any of those junctions (if, say someone wants logging added for all of those returns in future) and makes your code a lot easier to read.

Please stop and think about what you're doing, and refactor if necessary rather than blindly adding another conditional. It might be easier to add another level of nesting, but you'll suffer in the long term. Think about it.

As a general rule of thumb, I personally think if you have more than three levels of nesting, you might need to think whether you need a new method, or whether you need to rethink your code's flow.

Labels: , , , ,

Friday, 5 November 2010

Qt on Skia

The astute, regular readers I manage to have might have wondered why I have recently been playing with Skia, Google's 2D graphics rendering library, notably used in Chromium and Android. Well, now that my experiment is in a semi-usable state, I decided that it's probably about time I let the cat out of the bag and started talking about what I've been doing.

Over the past week, I've been diving into the Qt graphics stack a bit, for my own fun and amusement, to learn more about how it works and what makes it tick. This has been my first dive into graphics, so it's been a bit of a learning curve containing many gems like:
  • "transform? what's a transform"
  • "clipping? I know I need a haircut, but..."
  • "oh, you mean I actually have to store ARGB values for everything, and the order differs from toolkit to toolkit, and in some cases, from big/little endian?"
But I think I've made some progress in figuring things out slowly. And getting my project of choice, Qt rendering using Skia, to work, slowly but surely - a picture is worth a thousand words, so without further ado:
(Qt's demos/browser/, using Skia rendering)

Of course, it's still not done. There's a lot to implement (proper text rendering not using paths, clipping, supporting QBrush formats other than solid color fills...) and a lot of bugs to fix, as is visible in the screenshot above - and then the work starts in earnest to make this fast, but I'm happy with the progress so far over the past week.

As for my intentions? Well, I don't know. First, we'll have to see if I can get it finished, then, see how it performs vs Qt's own internal raster engine. If it's faster, then perhaps there's reasons to talk to the Qt graphics folks about whether it's worthwhile to include in Qt or not.

Even if this code doesn't make its way into Qt, I'm confident that there will be some valuable lessons and contributions from it. I do plan to write up another post on how to introduce a new graphics system into Qt, and I also have some notes to improve documentation for things like QPaintEngineEx.

If you're interested in tracking my progress, keep an eye on my skia-master branch on Gitorious. Note that if you want to try it yourself, for now you'll need the Qt branch of my Skia clone on github (note that this will only work on x86 with SSE2 support for now), because Skia's upstream SVN repository doesn't have an up to date/working buildsystem, and also contains a few problems that block compilation. I'm aware that this isn't really end-user-friendly, or a very sensible approach, but it will do for the short term. Just build it and copy libskia.a into /src/plugins/graphicssystems/skia/.

I'd like to thank a few people for their assistance:

  • Andreas Kling, for nudging me to indulge my insane self and actually try this
  • John Brooks, for giving me a crash course on how images are actually stored in memory
  • Samuel Rødal, for walking me through the internals of Qt's graphics guts
  • Zack Rusin, for his discussion/help with implementing complex non-joined sub-paths in QSkiaPaintEngine::fill()

I'll leave you with some screenshots showing the earlier work at getting things rendered, just for fun.




the first thing Qt on Skia drew, a test circle and a border. getting somewhere more useful, we rendered some blocks!




Qt on Skia manages to draw shapes in mostly the right place! Qt on Skia draws pixmaps for the first time

Labels: , , , , , , ,

Tuesday, 2 November 2010

Dear Google,

I've now wasted spent a highly enjoyable day trying to build Skia. Your provided, autotools build system is out of date and doesn't work (and let me assure you, dear third party reader, that this issue isn't the only one), which isn't really surprising since the last time you appear to have updated your build system was in March 2009, and there's a large part of your source that it doesn't cover (e.g. everything outside /src/core/). I don't really have the time (or know autotools), otherwise I'd try fix this.

So, I think to myself, Chromium uses Skia. Surely I can build Skia from a Chromium checkout. And you can!

But don't forget to wave a dead chicken, remember to *also* build and copy libskia_opts.a (not just libskia.a), and figure out how to remove parts of Chromium from also being used/linked in with the third party Skia source.

I'm up to that last part, in case you wondered.

Labels: , ,