Last week I formally introduced tinytlf to the world, just in time for FITC. I was blown away at its reception, the outpouring of feedback and support was amazing, way more than I thought there would be. Thanks a ton if you were a part of that!
Part of that feedback was a request for more information. What makes tinytlf different? What are the features/goals of the project? And (truly) my favorite inquiries, “does tinytlf have feature X?” So I thought I’d write a followup, explaining a bit about my motivations for writing it, my goals for the framework, and a high level overview of some of its key processes.
Note: When I say TextField, I’m talking about Flash’s legacy TextField, flash.text.TextField.
Goals
Tinytlf has ambitious goals. With tinytlf, I want to create a small, extensible library for developers to write advanced text controls. I want to give developers full control over every facet of the TextField; nothing is sacred, and every piece replaceable with a more suitable implementation. I want a TextField that finally parses real HTML, and applies real CSS stylesheets. I want a TextField that, while still visually consistent, finally provides interactive capabilities on par with the OS native text controls.
Native
Flash’s TextField has never been as good as the native OS offering. Like it or not, text is a place where [the dreaded] HTML5 has a clear advantage over Flash. I’d be willing to go as far as to say that it’s one of the main reasons many web developers, “technologists” (yes I’ve seen that job description), and web-savvy users hate on Flash content. They expect their text to be selectable across TextField instances. They expect the mouse and keyboard interactions to be the same as their OS of choice. They expect the text decorations to be just as eye-popping as the rest of Flash’s visuals. And it’s sad to say they aren’t.
HTML and CSS
It’s never been very easy for Flash developers either. The most common representation of rich text on the web is HTML. The TextField does support a subset of HTML tags; 11 of them to be exact. But you are stuck with those 11, and you have virtually no control over the styling or rendering of the content. Want stars for list items instead of bullets? Too bad. Don’t want your links underlined? Tough luck.
The CSS support is pitiful too. You can import CSS into a StyleSheet object, then apply the StyleSheet to the TextField, but it too only supports a subset of styles. On top of that, the TextField is no longer editable. So bon voyage to a Rich Text Editor that respects CSS! For that, you have to use the alternate and incompatible TextFormat class, but that requires management by developers and doesn’t offer any more styling options than StyleSheet!
Modularity
These days, modularity is a buzz word thrown around for good measure. Writing modular systems is the goal of every developer and framework, but it’s a promise that is seldom kept. Tinytlf ensures modularity by keeping strict separation of concern and delegating the bulk of the functionality to small, externally defined controller classes. Tinytlf has four actor maps, which allows for controllers to be defined or replaced from the outside.
For example, every text decoration in tinytlf is written externally and mapped into the framework at startup. There’s nothing inherently special about the word “underline”, or the class that draws underline decorations. It’s only what was defined and mapped in at runtime. So if you want to write your own class that draws underlines, you can, and externally map it in and replace tinytlf’s default implementation.
This same pattern is used over and over throughout the system, and gives you a new level of control over the TextField like you’ve never had before. If you want to support a new HTML tag, you can write a controller which parses that HTML tag. If you want a new decoration, write the implementation and map it in! If you need to fix a bug in one of tinytlf’s controllers, write the fix and replace the default controller. (Then contribute it back!)
A Text Layout Framework
Allow me to define the general problems a TLF has to solve:
- Model definition and resolution/parsing
- Text decorations (underline, strikethrough, etc).
- Text interaction (both generic and context-sensitive)
- Styles/formatting (notably inline and cascading styles)
- Rendering algorithms for the font glyphs that respects styles and formatting
- Layout algorithms that respect the model, decorations, and styles of the text
Luckily, tinytlf doesn’t have to solve all these problems alone. Tinytlf gets a tremendous amount of help from the Flash Player, through the Flash Text Engine API.
| Flash Text Engine’s responsibilities | Tinytlf’s responsibilities |
|
|
Architecture Overview
Tinytlf’s architecture allows all these pieces to come together, ensuring tinytlf is more than the sum of its parts.
Tinytlf is broken into five separate projects: utils, core, gestures, extensions, and components, respectively. Each project builds on the features of the previous project. You “pay as you go,” deciding for yourself what features you need and at what cost. For ease of use, you can use the components library, which is the default TextField, and depends on every project.
If you want, you can start over from core. Tinytlf is 100% interfaces, so, much like robotlegs, the default classes are just the reference implementation.
A Text Engine
The core of tinytlf is the TextEngine actor, responsible for invalidation, selection, and tracking the TextBlocks in the TextField. TextEngine is also a facade pattern, which unifies tinytlf’s four unique subsystems: TextLayout, TextDecor, TextStyler, and TextInteractor.
Every tinytlf actor or controller class receives a reference to the central TextEngine actor. Because TextEngine is a facade, any subsystem can call into any other subsystem. For example, the interaction controllers can add or remove text decorations by accessing the TextDecor actor from the TextEngine (e.g. when you mouse over, the controller can add an underline, then when you mouse out, remove it).
Engine Configuration
In tinytlf, every actor and controller class is externally defined. So tinytlf’s TextEngine accepts an ITextEngineConfiguration implementation to set up the default actors and mappings. For example, see the tinytlf TextField’s TextFieldEngineConfiguration.
Model Agnosticism
Tinytlf is model agnostic. It doesn’t care what format your data originally comes in, only if you can convert it into a tree of FTE ContentElements. The FTE already defined the model, it’s tinytlf’s job to resolve the differences between your model and FTE’s.
The default tinytlf TextField parses XHTML. There’s nothing inherently special about XHTML; XHTML is ubiquitous and easily converted into a tree of ContentElements. But if your model is not XHTML, you can write an implementation of ILayoutFactoryMap, then replace ITextLayout's textBlockFactory instance with your own.
Maps Maps Maps
Tinytlf exposes four maps, which allows for controllers to be externally defined. Tinytlf’s actors rely on definitions in their maps, then delegate functionality to the controllers. For example, tinytlf’s TextDecor exposes a map to define the classes which draw different text decorations. Then, when TextDecor receives instructions to decorate, it checks its map for the decoration definitions:
decor.mapDecoration("bgColor", BackgroundColorDecoration); decor.mapDecoration("strike", StrikeThroughDecoration); decor.decorate(someObj, {bgColor: 0xFF0000, bgAlpha: 0.7, strike:true});
In this example, TextDecor will instantiate two decorations, one for “bgColor” and one for “strike.” There’s nothing inherently special about those two strings, only that they exist in the map. Because of this, the TextDecor uses the mapped classes.
This is the pattern in three other areas as well: ILayoutFactoryMap, ITextInteractor, and ITextStyler.
Gestures
For context-insensitive text interaction, tinytlf includes a gestures library. A gesture is similar in spirit to iPhone and Android gestures; a sequence of events that occur in a certain order, so that when the last event occurs, the gesture is “unlocked,” and activates its behaviors. Behaviors are tiny command classes that are meant to control one facet of interaction. A great example is the IBeamBehavior, which controls whether the cursor is an IBeam or an arrow. Gestures can have multiple behaviors, and the same behavior can be mapped to multiple gestures.
The potential here is for interactivity on par with native text controls, but also allows for flexibility between platforms, like different gestures whether the user is on a PC or Mac. Moving from desktop to mobile? Just swap out mouse-based gestures for touch-based gestures, keeping all the same behaviors, allowing you to keep a consistent experience between devices.
Layout
Layout is a complicated problem, but tinytlf manages to cope. Tinytlf has a central ITextLayout actor for the ITextEngine, which renders lines from multiple TextBlocks between multiple DisplayObjectContainers (DOC). Each DOC gets its own layout controller, called an ITextContainer. I have previously blogged about various techniques for text layout, which are part of tinytlf’s default layout controllers. I’m still working on features for tinytlf v.1.0, but the current algorithm is pretty good.
During layout and re-render, tinytlf will only render the invalid TextLines from each TextBlock. This is one of many optimizations provided by the FTE of which tinytlf takes advantage.
Still rough around the edges…
Tinytlf isn’t finished. I’m working furiously to have 1.0 for my 360|Flex session. It needs more gestures and behaviors. I’m working on the layout algorithm to get text flow around images. Of course, editability is a huge feature everybody requests. I have a general idea of where the bottle necks in the framework are, but I haven’t done much formal testing. And of course I’m committed to releasing it with full test coverage.
If you would like to help, you can email me and/or jump in any time. The simplest thing you can do is request features. I’ve built this for myself, so I’m curious about other people’s requirements. I’ve already received some awesome feature requests that have kept my brain churning. At the very least I can keep them in the back of my mind, and try to keep from short-circuiting the framework, making those features impossible.
What are you waiting for? Fork it on github!
Tags: Flash Text Engine, tinytlf

Yes, every one of them. The Flash Player is capable of downloading just the data for the first frame and streaming the rest of the movie. Therefore a trend started in the earlier days of Flash-only developing; you typically put a very small loader object on your first frame that displays the loading progress of the rest of the SWF to the user. That way the user has a visual indication that something is happening, and the movie gets preloaded to a point where the user won’t experience any playback hiccups.

