On the joys of grotty code #
Today, for the n-th time (for n > 10) I received a bug report about Iconographer sometimes clipping the right-side third of the 48 x 48 (huge) icon member 1-bit mask. In a fit of constructive procrastination, I decided to look into it. What followed was several hours of delving into code that I had started writing more than 5 years ago. The problem seemed to reduce to something like this: when using CopyBits
in srcCopy
into a 1-bit 48 x 48 GWorld
with the destination rectangle encompassing all of it, the right-side 16 pixels (of the full height of the image) would get set to white, regardless of what the source was. Changing the mode to srcXor
, shifting the destination rectangle or changing the with of the image all made the problem go away.
Obviously I wouldn't have shipped something like this, so the problem must have materialized in the meantime. Sure enough, this wasn't reproducible on a machine that was still running 10.2. I figured that QuickDraw, especially when operating on 1-bit GWorld
s must not be very high up in Apple's list of priorities, and so this was something that had gotten past their regression tests. The workaround seemed to be to use srcXor
mode, and first clearing the destination area (i.e. setting it to white). This had the same effect as a normal srcCopy
CopyBits
with only a slight performance/complexity hit. It worked as expected, and I figured I could leave it that and begin preparing for a 2.5.1 release in a few days.
However, I wanted to make sure that this was really the case, and perhaps even report the bug to Apple. I made a simple test case app, and discovered that the problem wasn't exhibited there. After much digging around, I traced it to the way I was creating my GWorld
s. Normally this is done with NewGWorld
, however at some point in the distant past I had my my own wrapper for it. The reason was the padding that QuickDraw adds to each row, presumably so that each one can be aligned to a 16-byte boundary in order to speed up memory accesses. However, icon data is stored unpadded in the 'icns'
resources and .icns
files, and the back and forth conversion seemed rather tedious to me. I therefore created a wrapper called NewGWorldUnpadded
that would allocate a GWorld
with a slightly smaller width, so that the final allocated size would correspond to the unpadded final desired width. I then had to fix back the GWorld, changing its bounding rect, clipping region, row bytes field, etc. so that it was consistent with my desired size. This required a lot of twiddling with the GWorld
and PixMap
data structures, something I feel isn't very encouraged today. I was in fact very proud of this back in the day, since not only did it make loading/saving easier, but it also cut down on memory use of saved drawing states. I should have realized this tradeoff perhaps wasn't worth it, since two days after releasing Iconographer 1.0 I had to do a 1.0.1 release, fixing a bug caused by this wrapper (since I was using it for selections, which weren't always a multiple of 16 in width, a case I hadn't accounted for).
The problem seemed to be with the manual changing of the rowBytes
field of the GWorld
's PixMap
. Part of this was because there is now a PixMapExtension
struct linked from the PixMap
's pmExt
field, and this struct has a longRowBytes
field that needs to be kept in sync (I believe that 10.2 was more lax about this, since the regular rowBytes
field is enough for smaller values). There are now functions such as QTSetPixMapHandleRowBytes
that would perhaps take care of this, but the solution is very simple. It is now 2004, not 1998, therefore wasting 3K of memory is not a big deal. I can scrap NewGWorldUnpadded
entirely, and just use regular GWorld
s, dealing with the padding as appropriate. This will hopefully fix not only this problem, but also others that I have seen (e.g. rotations sometimes causing crashes). The only downside is that there are 15 places where the wrapper is used, with presumably many more pieces of code that rely on GWorlds having no padding. It will probably take a while to fix.
4 Comments
When will the much talked about version 3.0 hit the shelves?
We would all love to see Iconographer move another step forward, especially after 3 years!
Kind regards,
Tom.
Post a Comment