Home  >  

Flash Text Engine

Author photo
AddThis Social Bookmark Button

Note that every image with a blue border in this article launches a swf example. Read its caption to understand how it works.

One of the most interesting sessions at MAX 2008 was Creating a Next-Generation Desktop News Reader by Jeremy Clark, Daniel Wabyick and Justin Van Slembrouck. It demonstrated a sophisticated and dynamic AIR news reader application using the International Herald Tribune's feeds and gave a taste of what to expect in the news delivery of the future. It also showcased the greatly improved text management of the latest Flash player 10.

In addition, Adobe Labs released in December 2008 the Text Layout Framework (previously known as Vellum then Text Component ActionScript Library) built on top of the FTE. With it you can use or extend text components built on top of the text engine for both Flex and Flash. The Text Layout Framework deserves an article of its own as it will be used by most developers but the intent of this article is to give an understanding of how the engine itself works.

The new text engine flash.text.engine was built from the ground-up. It co-exists with the current TextField object but works differently: it is a low-level access, highly flexible text layout engine. Device fonts can now be manipulated as if they were embedded. In fact, a lot of the same effects can be applied to device and embedded fonts. The text is print-quality typography for the web.

The engine supports many languages and alphabeths including the ones using right-to-left layout (Arabic and Hebrew) or vertical layout (Chinese, Japanese and Korean) but also complex ones (Tate-chu-yoko) which have horizontal blocks in vertical text. Additionally a combination of scripts, such as Japanese or Arabic, is possible.

The following classes are used to create, format and control your text (in addition, many other classes manage under the hood core text information such as Font or TextRenderer).

  • the TextBlock - the factory for building a paragraph of text
  • the textLine - a line of text for the textBlock and a new displayObject
  • the contentElement - holds the content (text or graphic) of the textBlock
  • the ElementFormat - defines the format of the contentElement
  • the fontDescription - defines properties of the font applied to the elementFormat

This is some simple code using these classes to display text with all default settings:

import flash.text.engine.*;

var fd:FontDescription = new FontDescription();
var ef:ElementFormat = new ElementFormat(fd);
var te:TextElement = new TextElement("Hello world", ef);
var tb:TextBlock = new TextBlock();
tb.content = te;

var tl:TextLine = tb.createTextLine(null, 200);
addChild(tl);

FontDescription
This is where you define the font family fontName you want to use. For device font, you can select font styling such as italize fontPosture and bold fontWeight. For embedded font, you can take advantage of the enhanced screen rendering especially for small sizes renderingMode.CFF and strong horizontal stems to snap to a sub pixel grid especially important on LCD displays cffHinting. In RenderingMode.CFF mode, instead of the standard Flash renderer, "anti-alias for animation", used for vector art, Adobe's special glyph rendering technology is applied.

embedded.png

Define the fontLookup propriety to tell the player where to look for the font. If the value is DEVICE, it uses the standard operating system API to locate the font based on the font name and style specified in the swf. If the value is EMBEDDED_CFF, it looks at font outlines embedded in the swf. Such font becomes represented as a subclass of the flash.text.Font class (abstract base class) and holds font information such as fontName, fontStyle, fontType and hasGlyphs().

Note that fonts of type EMBEDDED can only be used by the TextField object (still maintained in the future but non longer improved). Only fonts of type EMBEDDED_CFF (Compact Font Format) can take advantage of the FTE features. In addtion to font outlines and information for Unicode mapping, they include a subset of OpenType tables needed to do things such as ligature substitutions, contextual writing systems like Arabic or Hebrew and GPOS/GSUB (Glyph Positioning table and Glyph Substitution table).

To see which fonts are available on your machine and in the swf, use the enumerateFonts method of the Font class. The method isFontCompatible(fontName, fontWeight, fontPosture) returns the availability of an embedded font in any style. Note that, for device font, the player has no interface to determine if the font provided by the OS has bold or italic face.

emulatefonts.png

This displays the embedded fonts in the swf as well as the device fonts installed on your computer.

import flash.text.Font;
import flash.text.engine.FontDescription;

// all fonts
var myFonts:Array = Font.enumerateFonts(true);
for (var i:int = 0; i < myFonts.length; i++) {
 if (myFonts[i].fontType == "device") {
  trace("I am a device font and my name is", myFonts[i].fontName);
 }
}

// embedded fonts only
var myEmbeddedFonts:Array = Font.enumerateFonts(false);
var f:Font = myEmbeddedFonts[0];
trace(FontDescription.isFontCompatible(f.fontName, "normal", "normal"));
trace(FontDescription.isFontCompatible(f.fontName, "bold", "normal"));
trace(FontDescription.isFontCompatible(f.fontName, "normal", "italic"));

Embedding fonts can be tricky. In Flex, embed the font and store it using DefineFont4 and font subsetting currently only supported by Gumbo. A future version of Flash will support it but in the meantime, a Gumbo SWC with the embedded font must be created then adding to your Flash CS4 project.

[Embed(source="assets/GaramondPremrPro.otf",
                            fontFamily="GaramondPremiere",
                            mimeType="application/x-font",
                            cff="true")]
private const GaramondPremiere:Class;

var fd = new FontDescription();
fd.fontLookup = FontLookup.EMBEDDED_CFF;
fd.fontName = "GaramondPremiere";

To display non-Roman text, Unicode character codes are converted to Strings. Unicode is a standard to represent text in most systems providing character information in an abstract way rather than graphically by assigning a unique number for every character in a language. The Flash player uses the font information to determine how to map the number to a glyph.

var text:String = "abc" +
String.fromCharCode(0x05D0, 0x05D1, 0x05D2, 0x5185, 0x95A3, 0x5E9C);

unicode.jpg

The font description is initially applied to an elementFormat (covered next) and locked. To make changes, a clone must be created:

import flash.text.engine.*;
import flash.text.Font;

var fd = new FontDescription("PALATINO", FontWeight.BOLD);
fd.fontLookup =  FontLookup.DEVICE;
var ef = new ElementFormat(fd);

var te = new TextElement("Hello world", ef);
var tb = new TextBlock();
tb.content = te;

var firstLine = tb.createTextLine(null, 300);
firstLine.y = 50;
addChild(firstLine);

// fd.fontWeight = FontWeight.NORMAL; // will throw an error
// Error 2185: FontDescription object is locked and cannot be modified	

// clone the font description
var fdCloned = (fd.locked) ? fd.clone() : fd; 
fdCloned. fontWeight = FontWeight.NORMAL;
var ef2 = new ElementFormat(fdCloned);

tb.content.elementFormat = ef2;

var secondLine = tb. createTextLine (null, 300);
addChild(secondLine);
secondLine.y = 100;

ElementFormat
This is where you define text styling and some of the layout of your content (ContentElement discussed next). They applied to both device and embedded fonts.

Some styling properties are self-explanatory such as alpha, color, fontSize and typographicCase. Others, maybe less familiar, take their root in typography digitCase, digitWidth, ligatureLevel. The layout properties affects horizontal spacing between atoms kerning, trackingRight, trackingLeft, vertical positioning baselineShift, alignmentBaseline, dominantBaseline, and textRotation. breakOpportunity determines which characters to break when wrapping text over several lines.

The image below shows several elementFormats with different settings. Note that the intent of some of the ElementFormat properties is to accommodate for vertical or right-to-left scripts rather than design.

formats.png

TextRotation on a elementFormat is only applied at a 90 degree angle so for a more detailed rotation such as moving text on a path, use the TextLine rotation. For alpha and textRotation, the final effect is the multiplication of several objects' property value.

alpha.png

This shows alpha multiplication with alpha set on both the ElementFormat and the textLine.

Like the fontDescription, once a ElementFormat is assigned, it is locked. It can however be cloned.

import flash.text.engine.*;
import flash.text.Font;

var fd = new FontDescription("PALATINO");
fd.fontLookup = FontLookup.DEVICE;
var ef = new ElementFormat(fd);
ef.fontSize = 30;

var te = new TextElement("Hello world", ef);
var tb = new TextBlock();
tb.content = te;

var firstLine = tb.createTextLine(null, 300);
firstLine.y = 50;
addChild(firstLine);

// ef.fontSize = 50; // will throw an error
// Error 2184: The ElementFormat object is locked and cannot be modified

// clone the element format
var efClone = (ef.locked) ? ef.clone() : ef;
efClone.fontSize = 50;

// applies the new format to the existing content
tb.content.elementFormat = efClone;

var secondLine = tb. createTextLine (null, 300);
addChild(secondLine);
secondLine.y = 100;

ContentElement
is the content (text and graphic) stored in a block of text and is independent of how it is distributed over lines. The contentElement is an abstract base class and cannot be instantianted. Use one of its subclasses instead: TextElement, GraphicElement or GroupElement.

Text Element
import flash.text.engine.*;

var fd:FontDescription = new FontDescription();
var ef:ElementFormat = new ElementFormat(fd);
var te:TextElement = new TextElement("This is the content to display", ef);
var tb:TextBlock = new TextBlock();
tb.content = te;

var tl:TextLine = tb.createTextLine(null, 200);
addChild(tl);
GraphicElement
import flash.text.engine.*;

private var loader:Loader;

private function loadImage():void {
 loader = new Loader();
 loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done);
 var url:String = "http://www.google.com/images/nav_logo.png";
 var urlReq:URLRequest = new URLRequest(url);
 loader.load(urlReq);
}
		    
private function done(e:Event):void {
 var graphicElement:GraphicElement = new GraphicElement(loader, loader.width, loader.height);
 addChild(loader);
 textBlock.content = graphicElement;
}
GroupElement
import flash.text.engine.*;

// create a ContentElement vector to store multiple textElements
var content:Vector.<ContentElement> = new Vector.<ContentElement>();

var fd:FontDescription = new FontDescription();

var el1:ElementFormat = new ElementFormat(fd, 10);
content.push(new TextElement("I a the first piece of content. ", el1));

var el2:ElementFormat = new ElementFormat(fd, 15);
content.push(new TextElement("I am the second ", el2));

var el3:ElementFormat = new ElementFormat(fd, 20);
content.push(new TextElement("And I am the third one.", el3));

var tb:TextBlock = new TextBlock(new GroupElement(content));

var tbc = textBlock.content;
trace(tbc); // [object GroupElement]
trace(tbc.elementCount); // 3
trace(tbc.getElementAt(0)); // [object TextElement]

createTextLines(tb); // create lines using the text line content

Each element type has its specific mechanism. TextElement can replace its text. GraphicElement can modify the height and width allocated to the graphic on the line elementHeight and elementWidth. GroupElement manages its various elements in different ways such as replace, merge and split.

group.png

This takes advantage of the Flickr API to search pictures and of the text engine to easily layout text and graphic elements together. Search one of the word displayed in the text and see how the string is replaced by the matching Flickr image. The GroupElement is re-organized to display the GraphicElement where the word was and the TextElements surrounding it.

If the content is changed after it was initially created, the elementFormat doesn't need to be defined again or cloned but the lines containing the content need to be broken and recreated (discussed under TextBlock).

The contentElement read-only information is its text, its elementFormat, its groupElement if it is part of a group as well as its textBlock and its textBlockBeginIndex (index for this particular contentElement in the textBlock). The userData provides a way to associate data with the element. The eventMirror object mirrors the events dispatched to the textLine and can be used to add logic and interactivity to your text (example under TextLine).

TextLine
is a new DisplayObject used to render one line of content according to a variable width. A textLine can only be created via the textBlock function createTextLine().

The TextLine is made of "atoms”: characters, groups of characters, graphic elements and indivisible elements. Methods to retrieve atoms information are available but it is important to flushAtomData() afterwards to avoid memory overhead.

atoms.png

This shows all the textLine information available. Click on an atom to display it. A yellow selection area is drawn using the atom bounds. A red line indicates the baseLine, a pink line the descent and a grey line the ascent.

The textLine can determine on mouseDown the atom selected by calling getAtomIndexAtPoint(e.stageX, e.stageY) but it has no knowledge of the content (text or/and graphic) corresponding to the atom. This information can be retrieved via the textblock.content.text and passing it the index position of the atom within the textBlock getAtomTextBlockBeginIndex().

private function createLine(tb:TextBlock, x:int, y:int, w:int, cont):void {
 
 // create the textLine and a mouseEvent listener
 var tl:TextLine = tb.createTextLine (null, w);
 tl.x = x;
 tl.y = y;
 cont.addChild(tl);
 tl.addEventListener(MouseEvent.CLICK, showMe);
}

// get the atom clicked by point position
private function showMe(e:MouseEvent):void {
 var tl:TextLine = e.target as TextLine;
 var atom:int = e.target.getAtomIndexAtPoint(e.stageX, e.stageY);
 
 // draw a yellow box above the atom
 var bounds:Rectangle = tl.getAtomBounds(atom);
 box.graphics.beginFill(0xFFFF00, 0.4);
 box.graphics.drawRect(bounds.left, bounds.top, bounds.width, bounds.height);  
 box.graphics.endFill();           	
 addChild(box);
 
 // get the atom content via the textBlock.content.text
 var index:int = textLine.getAtomTextBlockBeginIndex(i);
 trace( textLine.textBlock.content.text.charAt(index) );
}

The contentElement, covered earlier, can defines an event dispatcher as a mirrorRegion to the TextLine so that it receives events received by the TextLine. This option is helpful to add interactivity (click, mouseOver and mouseOut only). The code below uses this mechanism to make some text linkable.

var dispatcher:EventDispatcher = new EventDispatcher();
dispatcher.addEventListener("click", clickHandler);

var te1:TextElement = new TextElement("Here are more of", someFormat);
var te2:TextElement = new TextElement("Einstein's quotes", someFormat);
te2.eventMirror = dispatcher;
te2.userData = "http://rescomp.stanford.edu/~cheshire/EinsteinQuotes.html";

// code here to make the TextElements as content of the TextBlock
// and create TextLines

private function clickHandler(event:MouseEvent):void {
 var line:TextLine = event.target as TextLine;       
 var region:TextLineMirrorRegion = line.getMirrorRegion(dispatcher);
 selected = region.element as TextElement;
 navigateToURL(selected.userdata);
}

The text engine doesn't provide an interface to select text as with a traditional selectable text field. The (partial) code and swf below show how to add the cut, copy and paste functionality to the TextLine using the standard key commands. If you are developing for an AIR application, storing the text cut, copied or pasted is much simpler because you can take advantage of the Clipboard.setData() and Clipboard.getData() methods.

cutpaste.png

Use the standard key commands to cut, copy and paste text within and between textLines.

// Vector to store textBlock index position of selected text
private var selected:Vector.<int> = new Vector.<int>();

// Vector to store cut or copied text
private var stored:Vector.<String> = new Vector.<String>();

// displayObject used to draw red marker and blue selection
private var box:Sprite = new Sprite();

// store cursor position to paste text on keyCommand
private var lastAtom:int = -1;

textLine.addEventListener(MouseEvent.MOUSE_DOWN, trackSelection);
textLine.addEventListener(MouseEvent.MOUSE_UP, stopTracking);
textLine.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);

private function trackSelection(e:MouseEvent):void {
 e.target.removeEventListener(MouseEvent.MOUSE_DOWN, trackSelection);
 
 // clear previous selection
 selected.splice(0, selected.length);
 box.graphics.clear();
 
 var tl:TextLine = e.target as TextLine;
 var atom:int = tl.getAtomIndexAtPoint(e.stageX, e.stageY);
 var bounds:Rectangle = tl.getAtomBounds(atom);
 originX = bounds.x + tl.x;
 originY = bounds.y + tl.y;
 originW = 1;
 originH = tl.height;
 
 // draw a red selection marker
 box.graphics.lineStyle(1, 0xFF0000, 1);
 box.graphics.moveTo(originX, originY);
 box.graphics.lineTo(originX, originY+originH);
 
 // nows listen to the mouseMove
 e.target.addEventListener(MouseEvent.MOUSE_MOVE, drawSelection);
}

private function drawSelection(e:MouseEvent):void {
 var tl:TextLine = e.target as TextLine;
 
 // get atom index in the line
 var atom:int = tl.getAtomIndexAtPoint(e.stageX, e.stageY);
 
 // get atom index in the TextBlock to copy text between all lines
 var atomT:int = tl.getAtomTextBlockBeginIndex(atom);
 
 // only store the atom once
 if (atomT == oldAtom) {
  	 return;
 }
 oldAtom = atomT;
 
 // draw the blue selection based on the atom bounds and previous selection
 var bounds:Rectangle = tl.getAtomBounds(atom);
 box.graphics.clear();
 box.graphics.beginFill(0x7FBBF3, 0.4);
 box.graphics.drawRect(originX, originY, originW+bounds.width, originH);
 originW = originW+bounds.width;
 box.graphics.endFill();
 
 selected.push(atomT);
}

private function stopTracking(e:MouseEvent):void {
 e.target.removeEventListener(MouseEvent.MOUSE_MOVE, drawSelection);
 e.target.addEventListener(MouseEvent.MOUSE_DOWN, trackSelection);
 
 var tl:TextLine = e.target as TextLine;
 var atom:int = tl.getAtomIndexAtPoint(e.stageX, e.stageY);
 lastAtom = tl.getAtomTextBlockBeginIndex(atom);
}

// cut, copy or paste text
private function keyDownListener(e:KeyboardEvent):void {
 if (e.ctrlKey == true) {
  switch(e.keyCode) {
   case 88:
   if (selected.length > 0) {
    stored.splice(0, stored.length);
    var cutString:String = "";
    for (var i:int = 0; i < selected.length; i++) {
     // store text cut for future use
     stored[i] = textBlock.content.text.charAt(selected[i]);
     cutString += textBlock.content.text.charAt(selected[i]);
    }
    var c:TextElement = textBlock.content as TextElement;
    // remove text from textBlock.content
    c.replaceText(selected[0], cutString.length + selected[0], null);
    createLines();
   }
   break;
   case 67 :
   if (selected.length > 0) {
    stored.splice(0, stored.length);
    for (var i:int = 0; i < selected.length; i++) {
     // store text for future use
     stored[i] = textBlock.content.text.charAt(selected[i]);
    }
   }
   break;
   case 86:			
   if (lastAtom != -1) {
    var pasteString:String = "";
    for (var i:int = 0; i < stored.length; i++) {
     pasteString += stored[i];
    }
    var c:TextElement = textBlock.content as TextElement;
    // add text to textBlock.content
    c.replaceText(lastAtom, lastAtom, pasteString);
    createLines();
   }
   break;
   default:
  }
 }
}

Note that the dump() method which prints the textLine underlining information as an XML String can be handy during development (only available in debug mode).

TextBlock
is the factory to create one single paragraph (the algorithms for formats such as directional and line-break only work on one paragraph).

This is where the direction (or directions if mixed) of the text is set up bidiLevel, the tab offset tabStops, the text justified including for Asian scripts textJustifier and EastAsianJustifier. The baseline property baselineZero can be the Roman baseline, its ascent or descent and for scripts such as Chinese, ideographic top, center or bottom. The lineRotation can be modified by a 90 degree increment lineRotation and a special screen appearance turned on applyNonLinearFontScaling. The userData property is a handy way to associate some customized data to the textBlock like the text creation date or the name of the author.

With all these settings, the textBlock uses its content to create text, one textLine at a time at a given width. For each line created, a textLineCreationResult of type Success, Complete or Insufficient_Width is fired. The textLines must be added to the display list independently.

private function displayLines(tb:TextBlock, sp:Sprite, width:int):void {
 
 var prevLine:TextLine;
 var tl:TextLine = tb.createTextLine(prevLine, width);
 
 while (tl != null) {
  	tl.y = prevLine ? prevLine.y+tl.height : tl.ascent;
  	sp.addChild(textLine);
  	prevLine = tl;	
  	tl = tb.createTextLine(prevLine, width);
 }
 
}

After the initial creation, if the container's width changes or if a fontDescription, a textFormat or an elementContent is modified, the lines must be "broken" again.

blocks.png

This example and the (partial) code below show three different text layouts based on the dimension of the window (resize to view changes). All the values are set dynamically using the image and the lines information. Note that the image (graphicElement) becomes the child of the text line so in this example, its position is accessible via _textBlock.firstLine.

// photoW and photoH are the dimensions of the image
private var offset:int = 13; // offset from top left corner

// small layout
var prevLine:TextLine;
var textLine:TextLine = _textBlock.createTextLine(null, photoW);

while (textLine) {
 textLine.x = prevLine ? textLine.ascent : offset;
 textLine.y = prevLine ? prevLine.y + textLine.height : offset;
 // add a gutter to the first line below the image
 if (textLine.previousLine == _textBlock.firstLine) {
  textLine.y = prevLine.y + textLine.height + photoH + margin;
 }
 
 prevLine = textLine;
 addChild(textLine);
 textLine = _textBlock.createTextLine(textLine, photoW);
}


// medium layout
var isSecond:Boolean = false;
var prevLine:TextLine;
var currentWidth:Number = photoW -margin*10;
var refLine:TextLine;

while (textLine) {
 // lines along the side of the image
 if (isSecond == false) {
  textLine.x = prevLine ? prevLine.x : 13;
  textLine.y = prevLine ? prevLine.y + textLine.height : 13;
  // first line after the image
  if (textLine.previousLine == _textBlock.firstLine) {
   textLine.x = prevLine.x + photoW + margin;
   textLine.y = prevLine.y + textLine.height;
  }
  // line reaching bottom of image
  if (textLine.y > _textBlock.firstLine.height && isSecond == false) {
   isSecond = true;
   currentWidth = photoW + photoW-(margin*10) + margin;
   refLine = textLine;
  }
  // lines below the image
 } else {
  textLine.x = _textBlock.firstLine.x;
  textLine.y = prevLine.y + textLine.height;
  // add a gutter to the first line below the image
  if (refLine == textLine.previousLine) {
   textLine.y = prevLine.y + textLine.height+margin/3;
  }
 }
 
 prevLine = textLine;
 addChild(textLine);
 textLine = _textBlock.createTextLine(textLine, currentWidth);
}


// large layout
var isThird:Boolean = false;
var prevLine:TextLine;
 
var textLine:TextLine = _textBlock.createTextLine (null, photoW);
while (textLine) {
 textLine.x = prevLine ? prevLine.x : offset;
 textLine.y = prevLine ? prevLine.y + textLine.height : offset;
 // first line after the image - create a second row
 if (textLine.previousLine == _textBlock.firstLine) {
  textLine.x = prevLine.x + photoW + margin;
 }
 
 // create a third row
 if (textLine.y > _textBlock.firstLine.height && isThird == false) {
  textLine.y = _textBlock.firstLine.nextLine.y;
  textLine.x = textLine.previousLine.x + textLine.previousLine.width + margin;
  isThird = true;
 }
 
 prevLine = textLine;
 addChild(textLine);
 textLine = _textBlock.createTextLine(textLine, photoW);
}      
}

Thank you to Nabeel Al-Shamma, Senior Director, Engineering at Adobe, for his information on fonts and to the late Albert Einstein and Ernst Haeckel for the memorable quotes and the beautiful jellyfish drawing.

Read more from Veronique Brossier. Veronique Brossier's Atom feed v3ronique on Twitter

  • comments: 27

Comments

27 Comments

fontmania said:

Seems like the new low-level API is quite complex to handle. In general, it's interesting to observe that on the one hand new tools, such as Adobe Thermo/Catalyst, are developed which are supposed to simplify things and on the other hand the engineers are opening up more and more low-level access to certain functionalities (think of the Sound API or the here mentioned Text Engine) to build more powerful applications on top of it. Some developers will probably start building libraries around the complex stuff to make things easier and quicker again. In the end, hopefully more advanced but easier to use applications are developed.
Anyway, for developers, it's quite hard to keep on being up-to-date with all these new APIs, where some of them could fill up a whole book. However, if developers are too limited in their possibilities they will start complaining and requesting new language features and APIs. No end...

Veronique Brossier said:

This article was meant to introduce the API for the ones interested in using it as is and to provide some background (text is complex for software development in general, not just for Adobe products).

I personally like the fact that the Adobe engineers give us access to low-level information. But I agree that is is important to also provide a framework to help make use of the API easier and accessible to all.

My next article will be about the Text Layout Framework which makes this API easier to use.

Likeyn said:

Second, thank you for all these informations. I wasn't able to find such a level of concrete details about FTE anywhere else.

Third, I am in a hurry to read your next article about the Text Layout Framework.

Fourth, I also like having access to low-level information.

And First, please pardon me about my English level, I'm French :)

Veronique Brossier said:

Hi Likeyn,
I am glad you find the article helpful.
I am working on the second one.

Je suis francaise aussi et ton anglais est parfait!

George said:

Can I test this with Flex Builder 3?

I installed nightly build Flex 4.0 SDK, and try to create an ActionScript project in FB, but it seems failed to load new flash.text.engine package. Is there anything I missed?

I tried Flash CS4 no problem for sure. But I want to write code with FB.

Thanks,
George

George said:

Ok, I know why, need to add player 10 playerglobal.swc manually.

Andrew said:

Excellent article. Explained everything well. Some great examples that we can adapt to our own work and get started with the new Classes. I like wrapping my own frameworks around the AS3 Classes to further automate things. anyway, great job.

Veronique Brossier said:

Thank you Andrew. Please post some links of your work using FTE.

Mikael Hultgren said:

Very nice article, what would have helped tho was having the option of downloading the source code and follow along in that since some of the source code published above seems incomplete. Also the swf http://www.insideria.com/elementGroup2.swf with the flick image integration shows only text and not an image.

Veronique Brossier said:

Mikael,
Please read the instructions carefully on the elementGroup2.swf example. You are supposed to enter one of the words of the sentence in the text field and wait until the flickr API comes back with a matching image. Then the image will display. Note that the API is somewhat slow.

Veronique Brossier said:

Mikael,

Please read the instructions carefully on the elementGroup2.swf example. You are supposed to enter one of the words of the sentence in the text field and wait until the flickr API comes back with a matching image. Then the image will display. Note that the API is somewhat slow.

Mikael Hultgren said:

Loading the elementGroup2.swf example shows no textfield to enter any text into, all it shows is the text that is preloaded. I did actually try the swf and read the instructions before posting.

Veronique Brossier said:

Thanks Mikael for the heads up. The issue seems to happen only when the movie example is loaded in a separate window or a new tab. It works properly if it is loaded in the same window.

Adrian Parr said:

Hi Veronique,

I am currently working on a project for the BBC where I am required to localise several existing instructional animations in to Arabic and Persian. I am using the Flash CS4 IDE and all the textfields that need translating are static ones.

Is it possible to display right-to-left text in static textfields in Flash CS4, or can it only be done using AS3 and the FTE classes?

Many thanks in advance,

Adrian

Rob McCardle said:

Thanks for the useful article. I've written a little round up called "Flash Player 10 AS3 Text Layout Engine Dynamic Selectable Embedded TTF’s" clearing a few things up and linked to you...

http://www.robmccardle.com/wp/?p=59

Demo & source there - hope this is useful to someone,

Cheers,

Rob

www.robmccardle.com

Veronique Brossier said:

Hi Adrian,
Sorry for the late response. Somehow I missed your post.

Yes you can display text right-to-left using the beta software available on the Adobe labs: http://labs.adobe.com/downloads/textlayout.html
Install both the Text Layout Framework and the Text Layout Component.

You may choose to develop in pure ActionScript by adding the FTL library to your Flash environment. To do so, select File > Publish Settings > Flash > Settings > LibraryPath, select the swc icon and navigate to the textLayout.swc in the libs directory of your downloaded files.

If you install the Text Layout Component mentioned earlier, you can use in two ways. You can create an instance of the Text Layout Component and extend its functionality by adding your own code or if you don't want to do any coding, place the TextLayout component from the components panel to the stage, single-click it then select the Text Layout panel from Window > Other Panels. Select "get from Stage" to bring the component data to the panel and layout it out visually and "send to Stage" to push it back.

Let me know if any of this is not clear. Keep in mind that this product is still in beta so some of it may changed.

lance said:

Hey,

any ideas how to do something like StyleSheet on the Label in flex?

textFlow.styleSheet = "path/to/stylesheet.css"

If not, can you do ...?

If not, how do you create text styles?

THANKS!

your post is helpful and informative

Ezinez said:

Wow very great scripts, lots of example, beautiful and easy to apply now.
Thank for share.
--------------
Ezinez

Neil said:

Hello,

Great article for low level knowledge, any news on your next article - Text Layout Framework

Thanks

Mike said:

Veronique -

Thank you! Thank You! Thank You! I've been looking all over the place for a comprehensive explanation of the new Text Engine. This helps a lot more than anything else I've read.

A1A said:

I like the way you coding, all are very bright and easy to apply.
Thank you.

barbara said:

Hy,
I'm having a stupid problem that i can't find a way to solve.
so the thing is:
I'm trying to do a dynamic text with a UIScrollBar.
a can do it perfectly good except that id love to be able to put text breaks (spaces between the lines), and if a just put in a normal break nothing works any more.
since it's a huge text it would be really boring to read...

but i just can't manage it!

please help me I'm getting frustrated at this!

thank in advanced!
Barbara
:)

basel said:

Can we render HTML using this text engine? how?

dbam said:

Veronique, thank You for this FULL_SCALE review on the new engine!

I'm puzzled about one thing though, and can't find appropriate reference on the topic, and i really HOPE You, or somebody reading this article can help.

You state in Your article:
" In RenderingMode.CFF mode, instead of the standard Flash renderer, "anti-alias for animation", used for vector art, Adobe's special glyph rendering technology is applied. "

Does this mean, that using the new flash.text.engine one can't set the anti-alias parameters, or change the type used?
How to deal with it in FTE / this special glyph rendering tech?

Adobe has some mystical hints "here 'n there" on their pages regarding anti-aliasing, but no real statements nor description ( as far i could see ).

Sorry to add "just another question" in the row...

Cheers,
dbam

Veronique said:

A (late) response to your questions.

No CSS support in FTE. Please look at the ongoing development of the Text Framework.

To add a break in text (not specific to FTE), use "\n" as part of your string or
if using html text.

About the RenderingMode.CFF, the FTE offers an alternate method to rendering type. It doesn't have to do with anti-alias per say, or only, but more about the placement of the text in the context of the display (screen). The ultimate goal is to make the text look as readable and attractive as possible. If you want to think of it in the simplest form, the challenge is how to make a letter (i.e. the curve on the letter e) round and smooth on a display which only offers square pixels.

"Anti-alias for animation" was the name used by Macromedia when they started offering alternative endering techniques.

Anonymous said:

I should qualify that previous comment.
There is much more to rendering that my grossly simplified example!

Leave a comment


Tag Cloud

Poll: Mobile Features

What feature do you use most on your mobile phone?

Vote | View Poll Results | Read Related Blog Entry

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.