tinytlf Explorer App
by Paul Taylor, Oct. 21, 2011, under [ actionscript, community ]

I’ve written a little feature explorer app to showcase some of tinytlf’s latest features. You can play around with it below, or you can launch the demo app into a new window.

You can manipulate the renderer by editing CSS or switching which HTML document is rendered. I threw in a circular paragraph renderer just for fun. I also included a time indicator to show how long Flash takes to parse each HTML source. Even though Flash takes forever to serialize Strings to XML, this shows that tinytlf renders it almost instantaneously every time. I’ll talk about this more in my next post.

This is now the official tinytlf demo, so I’ll be updating it as I add features in the future. To demonstrate tinytlf’s capabilities beyond sanitized HTML input, I’ve included examples from Idle Words and the HTML version of Christian Cantrell’s eBook, Farmer One.

Watch or fork the project on Github.

Tags: ,

Design-by-Contract in RobotLegs 1.4
by Paul Taylor, Jul. 5, 2011, under [ actionscript, bitching, community ]

If you talked to me at a conference sometime in the last nine months, chances are I ranted loudly about type-variant auto-mediation. At the time, I meant an implementation I wrote in PureMVC because I assumed robotlegs already supported covariant auto-mediation. It doesn’t. Explanation to follow.

Flash and the City

Before I begin, this was the topic of my Flash and the City talk this year. You can find the slides here if you want.

Auto Mediation

Robotlegs has an interface called IMediatorMap, which maps UIComponent types to Mediator types. Robotlegs watches the display list, and when instances of any mapped components are added to (or removed from) the stage, it will create (or destroy) an instance of the mapped Mediator for it.

mediatorMap.mapView(MyViewType, MyViewMediator);

Each time you create and add a new instance of MyViewType to the stage, a corresponding MyViewMediator instance will be created.

Problems

The problem with MediatorMap is two-fold:

  1. It enforces an arbitrary restriction that each View instance can only have one Mediator instance. This is dangerous, because it blurs the line between view logic and business logic. Does this functionality belong in the UIComponent or the Mediator? Developers end up writing Views and Mediators with poor separation of concerns, and inevitably overflow View logic into their Mediators. Mediators aren’t seen as reusable bits of business logic, they’re seen as an extension to the UI component.
  2. MediatorMap is a type invariant mapping. The map creates a Mediator only if the view component is an exact instance of a mapped type.

    For example, if you register the MyViewComponentMediator type for MyViewComponent, subclasses of MyViewComponent (say, MyViewComponentSubclass) don’t get an instance of MyViewComponentMediator automatically created for them.

    If MyViewComponent encapsulates enough useful functionality to supplement it with its own Mediator, doesn’t MyViewComponentSubclass still implement (through inheritance) and require the same functionality from the MediatorMap? Sure, the subclass may override certain functions, but that’s just polymorphism at work.

Covariant Auto Mediation

The idea behind covariant mediation is that a Mediator is created if a component extends or implements a mapped view component type.

Here’s the practical difference between an invariant check and a covariant check:

//Invariant check:
if(myViewComponent.constructor == MyViewComponent){
    //Do something
}
 
//Covariant check:
if(myViewComponent is MyViewComponent){
    //Do something else
}

If the instance of myViewComponent is actually a subclass of the MyViewComponent type, the first check will fail, but the second check will pass.

Extends or Implements

Extending classes for functionality is all well and good, but it’s not as flexible or as clean as implementing an interface. For starters, AS3 allows you only one parent class, so you can’t compose much functionality through inheritance before running into the diamond problem.

Before I go any further, yes, this means you can map a Mediator for all instances or subclasses of Sprite or UIComponent.

// An instance of SpriteMediator will be created each time an instance
// or subclass of Sprite is added to the display list. Crazy, huh?
map.mapMediator(Sprite, SpriteMediator);

Naturally this introduces performance problems, so everything from the “flash.*” and “mx.*” packages are filtered out by default.

map.registerPackageFilter('flash.*');
map.registerPackageFilter('mx.*');

And you can add your own package filter definitions (like if you’ve got a particle emitter and want to skip inspection of each particle):

map.registerPackageFilter('com.myApp.particles.*');

Anyway, covariantly auto-mediating base classes is alright I guess, but who wants to maintain a complex inheritance tree? Not me. The real sexy magic happens when you start mapping Interfaces for auto-mediation.

Interfaces are covariantly checked:

trace(myComponent.constructor == IMyInterface); //will always be false
trace(myComponent is IMyInterface); //can evaluate to true

Demo Time

This post has been highly theoretical so far, and if you let me continue extolling the virtues of designing interfaces to apply behaviors to components via covariant mediation it will only devolve into something more abstract and academic.

So instead, I’ll show off some code to do it for me. Here’s the demo app I created for my FATC talk.

This demo has three progressively more impressive examples of common problems solved in very few LOC using covariant mediation:

  1. An example of handling system-wide error events.
  2. An example of managing selected screen state.
  3. An example DataGrid where each cell is representative of a unique and open streaming channel from the server.

Rundown

I’ll run through just the meaty parts of this demo. The source for the whole thing is here.

App.mxml and IoC Mappings

Here’s the important part of the Application MXML file:

override protected function createChildren():void
{
	// Normally these IoC mappings are done inside the Context.
	// Do them here because we have access to our children.
	var context:FATC_Context = new FATC_Context(systemManager as DisplayObjectContainer);
 
	var map:IVariantMediatorMap = context.variantMap;
 
	// Map implementations of ISystemErrorUI to have
	// SystemErrorUIMediators registered for them automatically
	map.mapMediator(ISystemErrorUI, SystemErrorUIMediator);
	// Map implementations of IScreen to have ScreenMediators
	// registered for them automatically
	map.mapMediator(IScreen, ScreenMediator);
	// Map implementations of IStreamingServiceUI to have
	// StreamingServiceUIMediator registered for them automatically
	map.mapMediator(IStreamingServiceUI, StreamingServiceUIMediator);
 
	var injector:IInjector = context.theInjector;
	// Tell the injector to create and inject a new instance of
	// StreamingService each time it sees a dependency on IStreamingService
	injector.mapClass(IStreamingService, StreamingService);
 
	super.createChildren();
 
	// Register the mediators for the Screens class immediately.
	// (normally the registration is deferred to the next frame).
	map.registerMediators(screens);
}

ISystemErrorUI and the SystemErrorUIMediator

public interface ISystemErrorUI
{
	function handleError(error:SystemErrorEvent):void;
 
	function get errorAcknowledged():ISignal;
}

Components that are interested in being notified when errors occur can implement the ISystemErrorUI interface. Whenever an error happens in the Application, it’s the responsibility of the errored operation to dispatch a SystemErrorEvent, either bubbling on the display list, or on robotlegs’ shared eventBus. Each instance of SystemErrorUIMediator will notify its ISystemErrorUI instance.

IScreen and the ScreenMediator

public interface IScreen
{
	function set selectedScreen(screen:IScreen):void;
 
	function get screenChangedSignal():ScreenChangedSignal;
}

Implementations of IScreen will be notified when the selectedScreen changes. Implementations of IScreen can cause the screen to change by dispatching their screenChangedSignal member.

Whether the implementor of IScreen truly wishes to change the selectedScreen, or whether it’s simply interested when the selectedScreen is changed, the ScreenMediator doesn’t care. In the demo, three of the four implementations of IScreen respond uniquely when their selectedScreen setter is called:

  1. The Screens class is a ViewStack. When its selectedScreen setter is called, it checks first whether the IScreen instance is a child of itself. If not, Screens adds it as a child. Screens ultimately changes its selectedChild property to the new IScreen.
  2. The ErrorNotificationView class is the bar at the top that drops down when an error occurs. If the bar is showing and the selectedScreen setter is called, the bar hides itself.
  3. The StreamingServiceItemRenderer class is the item renderer for the DataGrid. When the selectedScreen changes to and from the GridScreen instance, StreamingServiceItemRenderer starts or stops the incoming data stream. In this way, we can shut down any data sources for screens that aren’t currently visible.

IStreamingServiceUI and the StreamingServiceUIMediator

public interface IStreamingServiceUI
{
	function setStreamData(value:StreamData):void;
 
	function get updateStreamInfo():ChangeStreamInfoSignal;
}

There’s only one implementation of IStreamingServiceUI: StreamingServiceItemRenderer. StreamingServiceItemRenderer is the item renderer for each cell in the DataGrid.

StreamingServiceItemRenderer takes advantage of the fact that the DataGrid reuses its itemRenderers. When the user scrolls, the DataGrid sets in a new value for data. When that happens, the itemRenderer dispatches its updateStreamInfo member Signal.

When the UI dispatches its updateStreamInfo Signal, StreamingServiceUIMediator tells the service instance the new channel name. Then, the service closes its current channel, and opens a stream with the new channel name.

Because the DataGrid reuses its itemRenderers, and the itemRenderers dispatch changes in its data values to its Mediator, the Mediator can reuse its service instance, which manages opening and closing streams.

This means we only keep open connections for visible cells.

Pretty cool, huh?

Tags: , , ,

A Better Describe Type Cache
by Paul Taylor, Feb. 9, 2011, under [ actionscript, community ]

I don’t always work with the Flex Framework, so over and over I’ve written the following:

package my.project.package.utils
{
    public class Type
    {
        private static const cache:Dictionary = new Dictionary(false);
        public static function describe(value:Object):XML{};
    }
}

The describe function caches the results of a call to describeType() based on the type of Class passed in as the Value. But it’s super ugly! All over the place I’ve had to reference a static class: “Type.describe(myObject);” lame.

Why can’t the results of describeType() just be cached in the player? Maybe it is now and I just don’t know it? If so, please tell me!

So here’s the solution if you’d rather have a global function than a static method call:

package org.tinytlf.utils
{
	import flash.utils.*;
 
	public function reflect(type:Object, refreshCache:Boolean = false):XML
	{
		const typeCache:Dictionary = ReflectionCache.cache;
 
		if(!(type is Class))
		{
			if(type is Proxy)
				type = getDefinitionByName(getQualifiedClassName(type)) as Class;
			else if(type is Number)
				type = Number;
			else
				type = type.constructor as Class;
		}
 
		if(refreshCache || typeCache[type] == null)
			typeCache[type] = flash.utils.describeType(type);
 
		return typeCache[type];
	}
}
 
import flash.utils.Dictionary;
 
internal class ReflectionCache
{
	public static const cache:Dictionary = new Dictionary(false);
}

An internal class! Yipee! Static, but internalized. Until now I didn’t think you could store a static stateful reference for global functions to use.

Now you can go around all over the place calling “reflect(myObject);”, enjoying the convenience of describeType() and the benefits of using a static method.

Tags: ,

From Flash to Objective-C Part 1: Syntax
by Paul Taylor, Feb. 8, 2011, under [ community ]

Face it: Apple’s done a great job with the iOS UI. Consider this an axiom for the rest of the post. I’m not going to try and convince you if you disagree, and I’m not going to rehash what boils down to a religious debate. Their HIG is clutch.

But programming for it is crazy! Have you seen this language? What is this shit?
Are the designers of Objective-C insane??

Relax

This post is Objective-C syntax for the average Flash developer. It isn’t that scary. The colors are just different than you’re used to. And you’ll have to know or learn C, but don’t worry if you’re unfamiliar, I have faith you’ll pick it up quick enough. Because you’re creative and curious and you like learning new things dammit.

Syntax

So why haven’t you jumped into iOS? For me, it was the syntax. So now I’m going to compare the syntax of the languages from an AS3 dev’s point of view. In the end, I hope you won’t feel as intimidated as I did by this weirdly beautiful language.

Disclaimer

I’m still learning this stuff too. If I’m wrong on anything, please post it in the comments. I’m trying to disseminate useful information, things that took me a bit of studying to figure out, in the hopes that it won’t take you as long.

Primitives

There are a few keyword differences:

AS3		Objective-C
true		YES
false		NO
null		nil
this		self

Variables

Variable declaration and assignment:

// AS3
var myInteger:int = 1;
// Objective-C
int myInteger = 1;

You can see, this isn’t any different from C++, Java, C#, etc. The difference from AS3 is the lack of the required var or const keyword, and the type is specified before the variable.

Memory Allocation

Something we don’t typically think about in AS3: stack vs. heap allocation.

The Stack is a LIFO (last in, first out) pool of memory blocks that are allocated/deallocated very quickly. Each time you call a function, a block of memory is allocated for the function’s scope. When you return from the function, the block of memory is released back to the stack. This means stack-managed memory blocks are reused very frequently, therefore is mostly allocated from RAM or even the CPU’s cache, making it extremely fast.

The Heap is more complex, and allocates and deallocates memory based on usage patterns. I am not remotely familiar with how Objective-C allocates memory from The Heap, but in general, allocating/deallocating memory from the heap takes longer than from the stack.

Here’s a better explanation of the difference between the stack and the heap. This stuff is just generally good to know.

Values

Values are primitive types, allocated on the stack, and passed by value, or copied. That is, if you pass the variable as an argument to a function, the variable’s value is copied then passed in.

Structs

A struct (short for “structure”), is a type that stores multiple values. AS3 doesn’t have structs, but we typically mimic the behavior of structs with Value Objects (VOs). But when structs are passed, they are passed by value, not reference. When you pass a struct (such as CGRect in Objective-C), the struct is essentially copied and fed into the target method.

Pointers

Pointers are a special data type that points to a location in memory allocated from The Heap. When a variable is typed to a pointer, accessing that variable will redirect you to the value stored at the pointer’s memory address. Pointers typically point to object instances, partly because objects have state and it won’t do to pass objects by value.

More about pointers at Wikipedia here.

The Objective-C syntax to designate pointers is to add a star (*) between the type and the variable name:

UIButton *myButton = [[UIButton alloc] init];

This means var myButton is a pointer that points to a UIButton instance somewhere in memory.

Methods

Objective-C has no concept of access modifiers or namespaces. For the purpose of this writeup, I’ll only use public methods. For familiarity’s sake, I’m using the addChild method signature of the DisplayObjectContainer class in my examples. Also, this post isn’t meant to introduce any Objective-C paradigms, obviously Cocoa doesn’t do DisplayObjects and event listeners like Flash does.

Anatomy

In AS3, functions are declared in this pattern:

namespace function name(parameters):Type;
public function addChild(child:DisplayObject):DisplayObject;

In Objective-C, you have the exact same options, just moved around a bit:

-(Type)name: parameters;
-(DisplayObject *)addChild:(DisplayObject *)child;

So in comparison:

public function addChild(child:DisplayObject):DisplayObject;
-(DisplayObject *)addChild:(DisplayObject *)child;

Say you’re writing the addChild method signature of the DisplayObjectContainer class:

public function addChild(child:DisplayObject):DisplayObject;
-(DisplayObject *)add: (DisplayObject *)child

Multiple Parameters

In AS3, you want more parameters, you separate them by commas:

public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

In Objective-C, you name them:

-(void)addEventListener:(NSString *)type listener:(SEL)listener useCapture:(BOOL)useCapture priority:(int)priority useWeakReference:(BOOL)useWeakReference

This is just to show 1-1 parity with AS3. Because the order and name of the parameters is what makes up the method name, you could also write this method something like this:

-(void)addEvent:(NSString *)type withListener:(SEL)callback usingCapture:(BOOL)phase withPriority:(int)priority andWeakReference:(BOOL)weakReference

This way, the method reads almost like a sentence: “add event type String, with listener SEL, using capture phase BOOL, with priority int, and weak reference BOOL.”

Static Functions

In AS3, you declare a static function with the static keyword:

public function instanceFunction():void;
public static function staticFunction():void;

In Objective-C, you put a + in front of the method declaration:

-(void)instanceFunction;
+(void)staticFunction;

Calling Methods

In AS3, if you’re calling a method, it’s straightforward like this:

mySprite.addChild(myChild);

Here’s the same thing in Objective-C:

[mySprite addChild:myChild];

And the two lines side-by-side:

mySprite.addChild(myChild);
[mySprite addChild:myChild];

Here’s calling our pretend addEventListener function from before:

//Calling our fictitious addEventListener method:
[dispatcher addEvent:@"mouseDown" withListener:^{/* do something */} usingCapture:no withPriority:0 andWeakReference:no];

Classes

In Objective-C, each class is composed of two files. One is called the header file (suffix .h), the other is the implementation file (suffix .m). This is a C convention, since C doesn’t have proper classes.

Constructors

ActionScript has one constructor, it’s a function named after the Class it’s constructing. There are language reasons for this, primarily because deep down, AS3 isn’t that different from JavaScript, and each class is really just one big closure. But that’s a topic for another time.

Objective-C has what are called “designated initializers.” A designated initializer is pretty much the same idea as a constructor. A designated initializer is just a function that returns self, the Object’s reference to itself (AS3′s equivalent of this). Since designated initializers don’t have to be named after the class, there can be many, each taking different initialization values. This is essentially constructor overloading.

So where in AS3, you’d write:

public function MyClass(required:Boolean, optional1:int = 0, optional2:int = 3)

You could write the following in Objective-C:

-(id)init; //no required options, can leave this out if you wish
-(id)init:(BOOL)required;
-(id)init:(BOOL):required withOption:(int)option1;
-(id)init:(BOOL):required withOption:(int)option1 andAnother:(int)option2;
-(id)init:(BOOL):required orJust:(int)option2;

By convention, initializers start with some variation of the word “init.”

Headers

A header file is loosely analogous to an Interface in ActionScript 3. The header file declares all the publicly available functions and getters/setters available on the object. The header also declares what our Class inherits from, and the interfaces our Class implements. For this reason, what ActionScript actually calls an Interface, Objective-C calls a Protocol.

In short, all the API is declared in header files.

Implementation

The second part of a Class is the implementation. The implementation is the actual method and property implementation of the header file for the Class.

Examples

ExampleClass.as:

package com.ptaylor.blog {
    public class ExampleClass extends Object implements IMyInterface, IOtherInterface {
        //Constructor
        public function ExampleClass() {
            //do stuff
        }
    }
}

ExampleClass.h:

#import <UIKit/UIKit.h>
@interface ExampleClass : NSObject <IMyInterface, IOtherInterface>
{
}

The @interface declaration tells Objective-C that this is a header file, followed by the header’s name, ExampleClass. The following colon (:) declares what type this Class will extend from. Protocol (AS3 Interfaces) implementation declaration happens after the superclass declaration, inside the < > block.

ExampleClass.m:

#import "ExampleClass.h"
 
@implementation ExampleClass
 
//constructor
-(id)init{
    //do stuff
    return self;
}

The @implementation declaration tells Objective-C what header this file is implementing.

That’s it. That’s all I’ve got. I’ve skimmed over and given you the fifty-thousand foot overview of the Objective-C continent. As always, post some shit in the comments if I’m wrong or you liked this or whatever.

Tags: , ,

Fun With Comments
by Paul Taylor, Jan. 23, 2011, under [ actionscript, community ]

Found this comment from a commit in November 2010. Had to repost it here. In case anybody else does this too, know you’re not alone. At least the code this describes passes the unit tests.

////
// Everything after this point is basically magic. It was written during
// one coffee fueled weekend, and to be honest, I don’t remember much of
// it. That night is just a blur in my memory. Modify at your own peril.
//
// Here be dragons.
// (I’ve always felt that any serious library needs this comment at
// least once).
////

Tinytlf Updates and new Experiments
by Paul Taylor, Nov. 15, 2010, under [ actionscript, community ]

Sorry for the dearth of tinytlf posts lately, I’ve been head-down coding tons of new stuff. If you don’t believe me, check out the git repository history.

I’m working on an official tinytlf demo explorer app, ala minimalcomps but it’s going to let you do lots of cool stuff. In the meantime, I’ll post a few choice demos to this post, kind of show off what I’ve been working on.

Mobile TextField

First up, huge updates to gestures, behaviors, and decorations. So much that I’ve been able to come up with this demo, primarily meant for Android devices, but still usable on the desktop. Highlight in this TextField:

Better HTML support

Here’s some awesome HTML demos that Tanya Gray has put together…

and… maybe Divs and Tables?

Advanced Constraint Layouts

Floats aren’t just for HTML. Floats take advantage of a more generalized layout algorithm, which flows text around constraints. Floats are just a simple (Rectangle) constraint. You can implement the ITextConstraint interface with your own constraint implementation.

Here’s a few demos that show off the layout algorithm. Special thanks to Jim Armstrong (the Algorithmist) for the spline math.

Experimental, Just for Fun

A gmail-style link editing behavior!

So you can see I haven’t been idle! It’s just a lot of work. All the code for these demos is here. Fork the framework at github!

Tags:

Tinytlf at 360|Flex DC and 360|MAX
by Paul Taylor, Sep. 12, 2010, under [ community ]

360|Flex Speaker

I haven’t been blogging as often these last two weeks because I’m spending a lot of time preparing for my 360|Flex and 360|MAX presentations. I’ve been developing some kickass features and demos that I have yet to discuss publicly, so if you’re in the mood to be wowed, show up to my presentations.

360|Flex DC

My presentation is the first morning, right after the keynote address (go ahead, ask me if I’m nervous about following Doug McCune?). The title is “Advanced Text Rendering with the Flash Text Engine and tinytlf.” I’ll present a general overview of the Flash Text Engine and introduce tinytlf. I’ll try and cover the low level FTE APIs as best I can in the time, but I need to move quickly into tinytlf. I only have about 70 minutes, and I hope to leave 5-10 minutes at the end for questions. I’ll be announcing tinytlf 1.0, as well as demoing some yet-to-be-announced features. It’ll be killer, I promise!

360|MAX

The title for my 360|MAX presentation is “Tinytlf and Multi-Everything.” This presentation will begin with an overview of tinytlf, but will primarily focus on the features that enable and promote multi-screen, multi-platform, and multi-touch development. Topics covered will be the performance, interactivity, and configurability for different platforms. If you’re interested in a multi-platform text controls, this will be presentation to see.

These two conferences are the places to be for developers or companies who have invested in the Flash Platform. You’ve done your due diligence by choosing Flash, now keep up with the platform ’cause the times, they are a-changin’. Register for 360|Flex here, and for Adobe MAX here.

I’m very excited to present tinytlf to the world. If you see me at either event, hit me up! I’m more than happy to answer questions, etc. See you there!

Dual Image Flow Example
by Paul Taylor, Aug. 30, 2010, under [ actionscript, community ]

Expounding on last week’s image flow algorithm, I present to you a generalized algorithm for text flow around inline graphics. You can see it here: ImageFlowContainer, and fork the repo here: tinytlf.

This algorithm only works for left-aligned paragraphs, if you try it with any other alignment I can’t guarantee it’ll look good. These images don’t respect float, they’re just placed at fortuitous positions in the content. They respect box-model padding properties (padding-left, etc.). Also, I changed the default selection colors to be as close to Aqua Blue as possible.

Here’s the original Wikipedia article for comparison. As always, here’s the source for this demo. Just XHTML and CSS.

Selection

Tinytlf’s selection algorithms are character and line level algorithms, not block level algorithms like most web browsers. That means that even if you select an entire paragraph, tinytlf only knows you’re selecting from the paragraph begin index to the paragraph end index.

This leads to some interesting consequences, like an image on the first atomIndex in a line causing the entire line height to be as tall as him. You see some overlap, because tinytlf’s default selectionAlpha is 0.28.

In addition, all the decorations in tinytlf only draw underneath the TextLines. Therefore you don’t see selection over images, like you would in a web browser. Later I might allow the option for decorating on top of the Lines layer, but I’ve left it out for 1.0.

Tags: , ,

Advanced Text Layout in Tinytlf
by Paul Taylor, Aug. 24, 2010, under [ actionscript, community ]

Since last week, pretty much the most requested feature has been text flow around inline graphics. Yes, even more than editability. I’ve had cleaning up and adding advanced features to the TextLayout and TextContainer on the tinytlf 1.0 roadmap for a while, but last night I finally got to work on it. These classes are only preliminary, but I hope they demo just how powerful tinytlf’s layout architecture can be.

As always, the source is available here: source for these demos.

Text Layout

Ok, so say we have this wikipedia entry about the fascinating Atrophaneura hector (Crimson Rose) butterfly. It’s a nice article, and tinytlf formats it well (except for the TLMR bug):

Don’t encyclopedia entries come with an image?

Much better!

Put that image where you want it

Alright, now we’re rockin’

Ok, I know this is ugly, but I thought I’d show off a little bit. You aren’t constricted to docking on the left or the right, the new layout algorithm will wrap text around images no matter where they are in the markup.


Features

This shows off some features I’ve never talked about before. Of course there’s flow around the image, but that’s really just some fancy layout math, it’s not too complicated. I’m probably most proud of the fact that tinytlf intelligently renders only the invalid TextLines.

Invalidation

This is a Flash Text Engine feature, but it’s one that I love: when members of the FTE ContentElement model change (text, ElementFormat, etc.), the TextBlock will tag the TextLines which render the content “invalid.” The FTE can’t automatically update the TextLines; whomever renders the TextLines (tinytlf, in this case), is responsible for surgically removing and re-rendering the invalid lines.

It’s a delicate procedure, but tinytlf handles it like a champ. You see the result of this in the examples whenever you roll over an anchor tag and it changes fontPosture or color.

Layout

The second part of this is the little bit of fancy math I did to break and layout the lines in the proper order. If you want to see the algorithm, check out the newest ImageFlowContainer here.

It’s not too difficult. Basically, as I lay out the lines, I calculate the (x, y) position for the next TextLine. Because I can change the x and y independently of each other, I can break TextLines across the plane of the graphic.

Where can it go from here? My next feature will be to respect padding set on the <img/> tag. After that will be allowing a way for the <img/> to specify whether it renders inline, causes line/paragraph breaking, etc. There’s a lot that can be done.

Caveats

I haven’t tested this with more than one image. In theory it should work, but I’ve been awake for longer than 24 hours, so I can’t trust I’m actually thinking as clearly as I think I am o.O.

And yes, there’s a bug with the links. It’s especially prominent here, but basically when you move the mouse very quickly, the FTE TextLineMirrorRegions dispatch a “mouseOver” but never its corresponding “mouseOut.” If anybody on Adobe’s TLF or FTE team can shed some light on this situation, I’d be very grateful.

That’s it, happy coding. Fork it on github!

Tags: , ,

Tinytlf Overview
by Paul Taylor, Aug. 23, 2010, under [ actionscript, community ]

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
  • Model definition
  • Contextual text interactions
  • Inline styles
  • Glyph rendering algorithms
  • Model resolution and parsing
  • Generic text interactions
  • Cascading and inline style application
  • Layout algorithms, including text flow around images and flow between containers
  • Text decorations
  • The default definition of a TextField component

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: ,