Flash MX 2004 now shipping! Buy it here...
(Your purchase will help support moock.org.) -->
August 12, 2008
workaround for 127px font size limit
In ActionScript, text fields formatted via TextFormat, CSS, or HTML have an undocumented maximum font size of 127px. The limitation is based on historical requirements placed on Flash Player by the operating system. The limit also applies to dynamic and input text created in the Flash authoring tool, but not to static text.
Fortunately, the 127 font-size limit can be overcome with an ugly little workaround: set the font size, then scale the text field using scaleX and scaleY. For example, the following code sets a text field's effective font size to 200 by first setting TextFormat.size to 100, then scaling by 2.
var format:TextFormat = new TextFormat();
format.size = 100;
var t:TextField = new TextField();
t.autoSize = TextFieldAutoSize.LEFT;
t.text = "Nice and big.";
t.setTextFormat(format);
t.scaleX = 2;
t.scaleY = 2;
addChild(t);
As of Flash Player 10, the 127px font size limit continues to apply to traditional text, but has been removed for text rendered via the new Flash Text Engine (FTE). The following code, courtesy of Flash Player engineer Jeff Mott, sets the font size of a TextElement to 300.
var ef:ElementFormat = new ElementFormat();
ef.fontSize = 300;
var te:TextElement = new TextElement ("Nice and big.", ef);
var tb:TextBlock = new TextBlock (te);
var tl:TextLine = tb.createTextLine();
tl.x = 20;
tl.y = 300;
addChild (tl);
The 127px limit will also be removed for Flash's new Text Layout Components when they are released.
August 01, 2008
ActionScript 3.0 String-concatenation error gotcha
Take a look at this code:
trace(1 + + 2); // Output: 3
It may seem strange to us, but ActionScript considers it legal. It assumes you mean:
trace(1 + (+2));
which produces the value 3.
Now take a look at this code:
// Oops! One too many + signs...
trace("Hello" +
+ " world");
Once again, ActionScript assumes you mean:
trace("Hello" +
(+ " world"));
which yields the following somewhat misleading error:
1067: Implicit coercion of a value of type String to an unrelated type Number.
The error occurs because ActionScript considers '(+ "world")' a datatype-conversion operation, not a String concatenation. The fix is simple: remove one + sign.
trace("Hello"
+ " world");
But why does ActionScript consider '(+ "world")' a datatype conversion? Francis Cheng explains here...
July 24, 2008
event-registration performance
In Flash Player 9, the time required to register a listener for a given event increases as the number of listeners already registered for that event increases. Here are the results of a simple event-registration test on a P4-2.6ghz machine running Windows XP:
- Registering 1000 listeners for an event took .06ms per registration (i.e., an average of .06ms to run addEventListener() once).
- Registering 20000 listeners for the same event took .47ms per registration.
The increased per-listener registration time results from Flash Player 9's implementation of a safeguard built into the event-registration system: when a listener asks to register for an event, ActionScript first checks whether that listener is already registered; if so, ActionScript rejects the registration request. Listeners are, thus, prevented from registering multiple times for the same event.
In Flash Player 9, the "already-registered" check uses a linear lookup, comparing the new listener to every existing listener before allowing the registration to proceed. If an event already has 20000 listeners, and a new listener asks to register, ActionScript must make 20000 comparisons before the registration can be allowed (hence the high ".47ms per-registration" cost in the test above).
Adobe has improved the situation in Flash Player 10 by using a hash-table lookup instead of a linear lookup when checking for the existence of listeners at registration time. Registering for an event with many existing registered listeners will, therefore, be much faster in Flash Player 10.
July 17, 2008
TextField.text Gotcha: \n becomes \r
Here's a little TextField quirk: when you assign the string "\n" (newline) to a TextField's text variable, ActionScript automatically converts it to a "\r" character. For example,
var t:TextField = new TextField()
t.text = "Hello\nworld";
trace(t.text.indexOf("\r")); // 5
trace(t.text.indexOf("\n")); // -1
So if you're hunting for a "\n" you've added to a text field, you'll need to search for "\r", not "\n". The docs for TextField's text variable actually point out that "\r" is used:
"Lines are separated by the carriage return character ('\r', ASCII 13)."
But the docs fail to mention that "\n" is converted to "\r".
July 16, 2008
The Charges Against ActionScript 3.0
More than a year has passed since Flash CS3 was released to widely positive reviews, but many Flash users are still frustrated by some of the workflow changes introduced by ActionScript 3.0. The truly problematic changes are relatively few, but together they have a deep effect on the typical Flash user's daily job. In the spirit of working toward solutions, and of giving a formal voice to the collective grumbling of everyday Flashers, I have published an article called The Charges Against ActionScript 3.0 on O'Reilly's InsideRIA.
The article discusses the following issues:
1. The removal of on()/onClipEvent() from Flash CS3 makes creating simple interactivity hard.
2. Getting rid of loaded .swf files is hard.
3. Casting DisplayObject.parent makes controlling parent movie clips hard.
4. The removal of getURL() makes linking hard.
5. The removal of loadMovie() makes loading .swf files and images hard.
6. ActionScript 3.0's additional errors make coding cumbersome.
7. Referring to library symbols dynamically is unintuitive.
8. Adding custom functionality to manually created text fields, to all movie clips, or to all buttons is cumbersome.
9. The removal of duplicateMovieClip() makes cloning a MovieClip instance (really) hard.
You can read the article in its entirety here.
July 15, 2008
Things You Must Do Before Unloading a SWF File
If you load a .swf file into Flash Player 9 with ActionScript 3.0 and subsequently wish to remove it from memory, you must first deactivate it, and then dereference it. If you dereference the .swf without deactivating it, it will continue to consume resources and in some cases might never become eligible for garbage collection.
Here is an unofficial list of tasks required to deactivate a .swf file:
- Tell any loaded .swf child assets to disable themselves.
- Stop any sounds from playing.
- Stop the main timeline, if it is currently playing.
- Stop any movie clips that are currently playing.
- Close any connected network objects, such as instances of Loader, URLLoader, Socket, XMLSocket, LocalConnection, NetConnections, and NetStream.
- Release all references to cameras and microphones.
- Unregister all event listeners in the .swf (particularly Event.ENTER_FRAME, and mouse and keyboard listeners)
- Stop any currently running intervals (via clearInterval()).
- Stop any Timer objects (via the Timer class’s instance method stop()).
Note that the preceding list is, by definition, insufficient because it is neither exhaustive nor officially maintained by Adobe. If you know of a task that needs adding to the preceding list, please sent it to me via email (username colin, domain moock.org).
As of Flash Player 10, the preceding tasks can be performed automatically by calling the Loader class's new method unloadAndStop().
For further discussion, see Charge #2 in my Inside RIA article, The Charges Against ActionScript 3.0 and Grant Skinner's article Additional Information on Loader.unloadAndStop().
July 02, 2008
convert xml tags to lowercase
Here's a handy little function for converting all tag names and attribute names in an XML object to lower case. Useful for doing case-insensitive matching on tag names and attribute names.
public function xmlTagsToLowerCase (xml:XML):XML {
// Convert the root tag to lowercase
xml.setName(xml.name().toString().toLowerCase());
for each (var attribute:XML in xml.@*) {
attribute.setName(attribute.name().toString().toLowerCase());
}
// Convert all descendant tags to lowercase
for each (var child:XML in xml..*) {
// If the node is an element...
if (child.nodeKind() == "element") {
// ...change its name to uppercase.
child.setName(child.name().toString().toLowerCase());
// If the node has any attributes, change their names to uppercase.
for each (attribute in child.@*) {
attribute.setName(attribute.name().toString().toLowerCase());
}
}
}
return xml;
}
// Usage:
var x:XML = xmlTagsToLowerCase(new XML ("<A C='D'><B>test</B></A>"));
trace(x); // Output: <a c="D"><b>test</b></a>