Thursday, April 2, 2009

Flash bugs: dynamic TextField and letterSpacing issue

I'm creating TextField instances in ActionScript, modeled after one TextField instance in the Flash UI designer.

There are two stupid problems.

Problem 1:

The first is that Flash is very forgetful.

Suppose I go :

tb.text = 'Some new text';

Just like that, key TextField settings are lost! Idiotic. Things like letterSpacing get reset to zero.

The solution (noted by others) is to :

var tf:flash.text.TextFormat = tb.getTextFormat();
tb.text = 'Some new text';
tb.setTextFormat(tf);

If that makes sense to anyone, I suppose there probably are airborne sows.

But it kinda does the trick. Kinda.

Enter: problem the second

If I'm doing all this with an embedded font, the aforesaid hack DOES NOT WORK.

At least, not without a bit more effort.

I had the original textbox, built in to the Flash stage. Let's call it tbOriginal.

Then I have my dynamic textboxes, modelled off the original.

tbCreatedAtRuntime.text = 'Some text here';
tbCreatedAtRuntime.setTextFormat(tbOriginal.getTextFormat());

Nice - does the trick, except that the letterSpacing is shot.

So I play with the letter spacing. I try all sorts of values.

tbCreatedAtRuntime.text = 'Some text here';
var tf:flash.text.TextFormat = tbOriginal.getTextFormat();
tf.letterSpacing = 0.55; /* I tried lots of different values here. */
tbCreatedAtRuntime.setTextFormat(tf);

The problem was that, regardless of what letterSpacing value I set, it would often make no difference whatsoever to the overall length of the string.

But it was weirder than that. Once I got down to about 0.54, the string length jumped down very significantly. It was like the letterSpacing had a very course rounding applied, such that there was only one "real" letterSpacing option per 0.5 increment of the letterSpacing value.

But I knew this couldn't be the total story, because the tbOriginal was using a letterSpacing of 0.75, and on screen it was longer than tbCreatedAtRuntime with letterSpacing around 0.5, and shorter than tbCreatedAtRuntime with letterSpacing around 1, and as stated earlier, tbCreatedAtRuntime would treat letterSpacing of 0.75 the same as letterSpacing of 1.0.

What gives?

Fortunately, whilst not intuitive (after all, this is Flash isn't it?), the documentation did this time give me the clue I needed.

It turns out that Flash only supports integer values(1) for letterSpacing for "device fonts". My brain whirred away for a microsecond and I realised what the problem was.

I was using a special font, but I hadn't explicitly told my dynamically-created TextField to use font embedding. I just presumed that, since it got its TextFormat from tbOriginal, it would get the same font embedding as tbOriginal. Not so.

So now I explicitly tell tbCreatedAtRuntime to use the same font embedding as tbOriginal :

tbCreatedAtRuntime.embedFonts = tbOriginal.embedFonts;

... and now at last, letterSpacing works as expected. Whew!




But can you permit me to lament once more just how STUPID this design (or lack of design) is?

Adobe might be good at graphics, but they are very bad at development tools and APIs.

What SHOULD happen is that if ANY text field ANYWHERE in the Flash file has embedded a font, and ANY other text field anywhere else in the same movie (or even created dynamically) attempts to use the same font, the embedded font should be automatically applied to that other text field.

Now, failing that, at the very least, copying the TextFormat from one text field to another should ensure that if the first had an embedded font, the second uses the same embedded font.

Adobe, lift your game! Microsoft's APIs make yours look pathetic. You can do better than this!

(1) The integer-letter-spacing-for-device-fonts limitation is mentioned in the Flash 8 documentation. I'm using Flash 10, and I am surmising that Flash 10 supports 0.5 increments, in contrast to the Flash 8 doco which claims only 1.0 increments are supported in Flash 8.

No comments: