So, this year’s GSoC 2013 has reached the hard deadlAnd tine at 19:00 UTC (21:00 CEST).
And, I’ve managed to fix some critical bugs in the Opal-based backend of GNUstep. Huzzah!
What we now have is doublebuffering support, image support, font support, blitting from a ‘gstate’ to a ‘gstate’ (actually between their backing surfaces while taking their respective transform matrices into account). We also have an an assortment of ‘DPS’ methods.
Everything is made possible thanks to great work of Opal’s authors, especially Eric Wasylishen who helped by fixing some outstanding bugs in Opal as well as with some text rendering code in the Opal backend. He was also of extreme assistance by keeping me great company over XMPP during late hours full of frustration 🙂
Thanks also go to everyone who ever worked or contributed on GNUstep — particularly on gnustep-gui. Especially Fred Kiefer, my last year’s mentor, whose advice always proves invaluable; perhaps initially cryptic, but always invaluable.
Thanks also go to David Chisnall, my this year’s GSOC mentor who kindly welcomed everyone to Cambridge on this year’s GNUstep meeting, and tolerated my rare status reports. 🙂
Aside from the various delays caused by job interviews, summer camps and sicknesses (as well as my overall suckiness 🙂 — the most confusing thing to me was the concept of ‘gstate’. As it turns out, GNUstep loves to keep a lot of graphics state in a class derived from GSGState
. It loves to be able to switch between gstates at will. It likes resetting matrix to the identity matrix whenever it wants. It likes setting custom matrices. It likes resetting the clipping path. In short — it loves to do many things that Core Graphics doesn’t want to let you do.
Which is why I got so confused when Fred Kiefer suggested that getting rid of GState may not be so easy. Core Graphics looked so logical to me and methods that gnustep-back implemented looked like they matched them so closely. Why are things in gnustep-back so complicated?
Turns out there is a good reason — switching and copying of gstates, which DPS permits and GNUstep uses in large amounts.
So in the end, I dumped the branch related to cutting out OpalGState
out of my backend. Classes in the gsc/
folder implement enough logic for it to be worth keeping them as base classes for context, gstate, etc. And Eric was kind enough to implement a way to get GState out of Opal so I can save it in OpalGState
class in the backend and apply to a context when appropriate. Whew.
Next thing that caused a lot of problems for me was doublebuffering support. First, I got stuck with incorrectly understanding the CGContextDrawImage()
API. I thought it specified the source and painted at 0,0; it turned out it specified destination. And the source was specified by creating a duplicate image. (Well, not a duplicate; same image is still used, just a different cropping argument is set.)
So I used that, and failed horribly. As much as I tried to get it to work (many hours wasted shuffling the code around) — nothing. Turns out Opal, unfortunately, did NOT make use of the cropping specifier in the ‘subimage’. When that was fixed, getting doublebuffering to work was trivial.
Images were fun. During initial sprint, I got them to work — only if they were 32bit RGBA images. And only after a lot of tries. And when context’s -isDrawingOnScreen
returns YES
, images break. Turns out they are drawn into an offscreen context, and then blitted onscreen using -compositeGState:...
.
As I didn’t figure out how exactly an offscreen context is created, right now -isDrawingOnScreen
returns NO. It’s a shameless lie, but until I get some time to debug what’s going wrong, it’ll stay this way. At least we get icons in System Preferences this way!
Final issue that I struggled for a week or two was -compositeGState:...
(and its buddy -drawGState:...
). Figuring out how it’s called and from where and why was messy, and the fact that it works at all by the deadline is a small miracle. How does one debug why an image is not being correctly painted into an offscreen context — for example, one for images? How does one figure out what offsets does -gui
imagine I’m applying? Did I forget to apply device offset or did I forget to update CTM? Should I flip the passed .y
coordinate? Is -compositeGState:...
incorrectly sourcing the image from NSImage
‘s backing OpalGState
, or is -DPSimage:...
incorrectly painting the image into that OpalGState
‘s backing surface’s backing CGContext
? Does the surface exist at all when -DPSimage...
is painting into it? Does the surface have the backing CGContext
set up? Did I correctly apply all properties to the -copyWithZone:
‘d OpalGState
? Maybe code is trying to call -drawGState:...
? And the most important question of them all: why the heck does it not draw?!
So right now we have a mostly functional -compositeGState:...
and committed. Why mostly? Well, some images don’t seem to be drawn. And as long as you scroll the NSScrollView
by grabbing the scrollbar, you’ll get a correctly scrolled scrollview. (You can also try clicking on the last visible item and pressing the down arrow: it’ll work.)
Then try clicking on an arrow button of the scrollbar. Heh — turns out -gui
is scrolling it in a different way. What way? I did not try figuring out yet (as I hit the deadline).
What else is verified to be missing or broken? The blinking cursor in textviews (e.g. in Ink and TextEdit). Round buttons. I have a tableview that I can’t doubleclick on without crashing the app. (Curiously, outlineview version of the same test app does not crash.) Sometimes, pen is not lifted in appropriate places — to see this, launch SystemPreferences and open the Themes panel. Popup buttons with selection that happen to have an ‘arrow’ on the right side — in SystemPreferences, open the Font panel and look on the left — will not be correctly painted when clicked on.
Aside from being generally unhappy with performance, I’m also especially unhappy with font performance; it does seem to be a sad result of doublebuffering (everything is an image, so X11 is unhappy with that).
I’m not looking forward to fixing what remains broken, but I’ll try. I’ll try. After all — we can’t have Core Animation integration without the Opal backend 🙂
All in all, this is certainly not ‘release’ quality — but it’s close to being actually usable. I’m somewhat pleased that the backend actually works, considering how many issues I had along the way, largest of which being myself and (again) not being fanatically devoted to GSOC, which is what Google intended the students to be 🙂