Gumbo Text Primitives - Functional and Design Specification
Glossary
FTE - An acronym for Flash Text Engine, a set of new classes baked into Flash Player 10. They support low-level text functionality such as rendering individual lines of text. This involves mapping Unicode characters to font glyphs, laying out the glyphs using the Unicode bidirectional text algorithm, determining appropriate line breaks, and rendering the glyphs into pixels.
FTE is the foundation for all future text functionality in the Player. TextField will be maintained for backward compatibility, but it will no longer be enhanced, and bug fixes are unlikely.
The documentation for the FTE APIs can be found under the flash.text.engine.* package in the Gumbo ActionScript 3.0 Language and Components Reference. However, very few developers are likely to need to use FTE APIs.
TextLine - FTE's display primitive for text rendering. At the level of FTE, displaying text means using a TextBlock to create instances of TextLine – a new subclass of DisplayObject – for each line of text and putting them on the display list. TextLines support alpha and rotation, even with device fonts. When using embedded fonts, FTE requires that they be embedded in the SWF file with a new DefineFont4 tag rather than the old DefineFont3 tag.
TLF - An acronym for Text Layout Framework, a set of classes built on top of FTE. They provide high-level text functionality such as multiple lines and paragraphs; an XHTML-like text model and markup language; and scrolling, selection, and editing.
TLF was formerly known by the code name Vellum. (At one point it was also called TCAL, the Text Component ActionScript Library.). It is provided within the Gumbo SDK as the three SWCs textLayout_core.swc, textLayout_conversion.swc, and textLayout_edit.swc.
The documentation for the TLF APIs can be found under the flashx.textLayout.* package in the Gumbo ActionScript 3.0 Language and Components Reference. Developers are likely to use TLF mainly via its text model, when they write MXML tags like <p> and <span> or import markup with such tags. TLF's text model is a superset of FXG 1.0.
text object model - Unlike TextField, TLF uses an ActionScript object model to represent rich text. Concepts like paragraphs, spans, and hyperlinks are not represented as formats that affect the appearance of character runs in a single, central text string. Instead they are represented by runtime-accessible ActionScript objects, with their own properties, methods, and events (but not styles, at least not yet). For example, you can easily write code to change the color of the second paragraph object. The "plain text" that is displayed is actually distributed across the leaf nodes of the text object model.
text markup - Markup languages, such as that defined by the FXG 1.0 specification, are very useful with TLF but have secondary importance compared with the primacy of the text object model. Markup – either as MXML at compile time or as a String at runtime – can be used to create a text object model, but the model does not store the exact markup that was used to create it. To obtain it again, you "export" new markup from the model.
TextFlow - TLF's most important class. It is the root of a TLF text object model, which is a tree of FlowElements such as ParagraphElements (corresponding to <p> tags) and SpanElements (corresponding to <span> tags). TLF's job is to create, render, manipulate, and edit TextFlows.
FlowElement - The base class for all the nodes in a TextFlow. The tags and classes for the nodes inside a TextFlow tree are
| Tag |
Class |
| <div> |
flashx.textLayout.elements.DivElement |
| <p> |
flashx.textLayout.elements.ParagraphElement |
| <span> |
flashx.textLayout.elements.SpanElement |
| <a> |
flashx.textLayout.elements.LinkElement |
| <img> |
flashx.textLayout.elements.InlineGraphicElement |
| <br> |
flashx.textLayout.elements.BreakElement |
| <tab> |
flashx.textLayout.elements.TabElement |
| <tcy> |
flashx.textLayout.elements.TCYElement |
character formats - Text-formatting styles or properties which apply at the level of individual characters, such as fontSize.
paragraph formats - Text-formatting styles or properties which apply at the level of individual paragraphs, such as marginLeft.
container formats - Text-formatting styles or properties which apply at the level of the entire component, such as paddingTop.
anchor position - A character index specifying the end of the selection that stays fixed when you extend the selection with the arrow keys.
active position - A character index specifying the end of the selection that moves when you extend the selection with the arrow keys.
FlowOperation - An editing operation that can be performed on a TextFlow. FlowOperations are often created automatically by user activity such as entering text, backspacing, and cutting/pasting. Events let you intercept them to have control over editing operations.
Summary and Background
Gumbo will have three text primitives – TextBox, TextGraphic, and TextView – which offer new text functionality made possible by Flash Player 10 and AIR 1.5. They are implemented using a combination of FTE and TLF.
These primitives will typically be used in the skins of skinnable components, and having three of them allows a pay-as-you-go strategy: you use the lightest-weight one that meets your needs.
For example, the default skin of a Gumbo Button will a TextBox to render the label of the Button. If you have a Button that requires rich text, you can "upgrade" its skin to use a TextGraphic. The default skins of a Gumbo FxTextInput and FxTextArea will use a TextView to provide an area in which text can be edited (but not the border, background, or scrollbars).
The following table summarizes the features of the three text primitives. Note how TextGraphic has more functionality than TextBox, and TextView more than TextGraphic.
| Feature |
TextBox |
TextGraphic |
TextView |
| Extends |
GraphicElement |
GraphicElement |
UIComponent |
| Uses |
FTE |
TLF |
TLF |
| Advanced typography |
Y |
Y |
Y |
| Alpha* |
Y |
Y |
Y |
| Rotation* |
Y |
Y |
Y |
| Bi-directional text |
Y |
Y |
Y |
| Multiple lines |
Y |
Y |
Y |
| Default formatting via CSS styles |
Y** |
Y |
Y |
| Multiple formats |
N |
Y |
Y |
| Multiple paragraphs |
N |
Y |
Y |
| Text object model |
N |
Y |
Y |
| Markup language |
N |
Y |
Y |
| Inline graphics |
N |
Y |
Y |
| Hyperlinks |
N |
N |
Y |
| Scrolling |
N |
N |
Y |
| Selection |
N |
N |
Y |
| Editing |
N |
N |
Y |
| Linked containers |
N |
N |
N |
* even with device fonts!
** TextBox supports a "basic" subset of TLF formats, as explained in the styles section below.
Note that none of the text primitives are designed to support flowing text through linked containers. This functionality will be added in a post-Gumbo release.
Note also that TextBox and TextGraphic are GraphicElements. GraphicElement is a new core class in Gumbo which supports UIComponent-like layout and invalidation, but which is not itself a DisplayObject. Instead, multiple GraphicElements can sometimes share a single DisplayObject.
This specification also covers FxTextBase, the base class for skinnable components that include a TextView in their skin, such as Gumbo's new FxTextInput and FxTextArea components. It extends FxComponent, the base class for all Gumbo-skinnable components, which is described in the Gumbo Skinning spec.
This specification does not cover details of functionality which is implemented entirely within FTE and TLF. For example, it does not describe things like the linebreaking algorithm, whether a double-click selects whitespace after a word, what Shift-Right-Arrow does, etc., because these are not implemented in Gumbo code.
Usage Scenarios
These three primitives are the basis for all text display in Gumbo components, so usage scenarios include anything involving text. See the table above to determine which text primitive offers which capabilities.
Detailed Description
Default formatting via CSS styles
The three primitives will support specifying default text formatting via CSS styles. The complete set of styles will support all of TLF's formatting capabilities and is divided into the six include files listed below.
Each category of formatting styles – character, paragraph, and container – is divided into "basic" and "advanced" subsets. Because it relies only on FTE and not TLF, TextBox will support only the "basic" styles below, which are a subset of FXG 1.0. TextGraphic and TextView will support both "basic" and "advanced", which constitute a superset of FXG 1.0.
BasicCharacterFormatStyles.as
[Style(name="alignmentBaseline", type="String",
enumeration="roman,ascent,descent,ideographicTop,ideographicCenter,
ideographicBottom,useDominantBaseline", inherit="yes")]
[Style(name="baselineShift", type="Object", inherit="yes")]
[Style(name="cffHinting", type="String",
enumeration="none,horizontalStem", inherit="yes")]
[Style(name="color", type="uint", format="Color", inherit="yes")]
[Style(name="digitCase", type="String",
enumeration="default,lining,oldStyle", inherit="yes")]
[Style(name="digitWidth", type="String",
enumeration="default,proportional,tabular", inherit="yes")]
[Style(name="dominantBaseline", type="String",
enumeration="roman,ascent,descent,
ideographicTop,ideographicCenter,ideographicBottom", inherit="yes")]
[Style(name="fontFamily", type="String", inherit="yes")]
[Style(name="fontLookup", type="String",
enumeration="device,embeddedCFF", inherit="yes")]
[Style(name="fontSize", type="Number", format="Length", inherit="yes")]
[Style(name="fontStyle", type="String",
enumeration="normal,italic", inherit="yes")]
[Style(name="fontWeight", type="String",
enumeration="normal,bold", inherit="yes")]
[Style(name="kerning", type="String",
enumeration="on,off,auto", inherit="yes")]
[Style(name="ligatureLevel", type="String",
enumeration="none,minimum,common,uncommon,exotic", inherit="yes")]
[Style(name="lineHeight", type="Object", inherit="yes")]
[Style(name="locale", type="String", inherit="yes")]
[Style(name="renderingMode", type="String",
enumeration="normal,cff", inherit="yes")]
[Style(name="textAlpha", type="Number", inherit="yes")]
[Style(name="textRotation", type="String",
enumeration="rotate0,rotate90,rotate180,rotate270,auto", inherit="yes")]
[Style(name="trackingLeft", type="Object", inherit="yes")]
[Style(name="trackingRight", type="Object", inherit="yes")]
[Style(name="tracking", type="Object", inherit="yes")]
[Style(name="typographicCase", type="String",
enumeration="default,title,caps,smallCaps,
uppercase,lowercase,capsAndSmallCaps", inherit="yes")]
AdvancedCharacterFormatStyles.as
BasicParagraphFormatStyles.as
AdvancedParagraphFormatStyles.as
BasicContainerFormatStyles.as
AdvancedContainerFormatStyles.as
The names, allowed values, and meanings of these styles are the same as those in TLF's ICharacterFormat, IParagraphFormat, and IContainerFormat interfaces. (These are in the flashx.textLayout.formats pacakge.) For details, please see the documentation for these interfaces. Note that some styles are inheriting and others non-inheriting.
TLF's FlowElement tags such as <p> and <span>, which are supported in the content of a TextGraphic or TextView, currently support formatting only via properties, not CSS styles. The CSS styles determine the default formatting for text in a text primitive. Formatting properties on FlowElements are applied after the formatting styles on the component.
The default values for each style will be specified in the global selector:
Five of these default values – those for color, fontFamily, fontSize, kerning, and textAlign – have Halo-compatible defaults for now. They are likely to change in the future.
Text content
Components like TextGraphic and TextView which support TLF-formatted text expose a content property whose getter always returns a TextFlow which is owned by the component.
Although you can set this property to a TextFlow, it is typed as Object to allow you to set to more convenient things from which the component will automatically create a TextFlow:
If you set it to a String, the String will be assumed to be a markup string to be imported by TLF. Such a markup string can range from plain text such as "Hello, world!", through "partial markup" such as "This is <span fontStyle='italic'>very</span> exciting", to full markup enclosed with a <TextFlow> tag.
If you set it to XML, the XML should start with a <TextFlow> tag, and it will get converted to a String and parsed by the TLF importer.
If you set it to a TLF FlowElement, such as a ParagraphElement, this element will get wrapped into a TextFlow.
If you set it to an Array containing Strings and FlowElements, each String will get wrapped into a SpanElement, and then all the FlowElements will get wrapped into a TextFlow.
Regardless of what you set the content to, it will be transformed into a TextFlow by the component's commitProperties() method, so that if you get the content property later (after an updateComplete event) it will be a TextFlow.
There is of course an interaction between the text and content properties. If you set one and later (after an updateComplete event) get the other, they will be in sync.
TextGraphicElement
TextBox and TextGraphic will extend a new subclass of GraphicElement called TextGraphicElement which implements IStyleClient and supports a text property.
Being an IStyleClient means that TextGraphicElements have the same styling APIs as UIComponents, such as getStyle(), setStyle(), styleName, etc. This spec will not discuss them further because the IStyleclient interface is familiar from Flex 3. Note that other types of GraphicElements do not support CSS styles.
The text property can be used for setting and getting "plain text" without any markup. When set, this text will be rendered using the formats determined by the component's CSS styles.
TextGraphicElement is an abstract class in the sense that it does not actually declare any styles or render any text. You need to use one of its subclasses for useful functionality.
TextBox
TextBox is the most lightweight text primitive, because it offers the least functionality. It is a GraphicElement, not a UIComponent. Although currently it always has its own DisplayObject, eventually it will do so only when necessary. It is implemented using only the FTE classes in Flash Player 10 and therefore doesn't link in any classes from the TLF SWCs.
TextBox is basically Gumbo's replacement for <mx:Label>, with some differences: it can display multiple lines, but only in a single format; it can render bidi text; and it supports rotation and alpha even when you use device fonts. Note that it is completely non-interactive: it doesn't support hyperlinks, scrolling, selection, or editing.
TextBox does not support drawing a background or border; it only renders text. It supports only the basic formatting styles: BasicCharacterTextStyles.as, BasicParagraphTextStyles.as, and BasicContainerTextStyles.as.
TextBox uses FTE to create TextLines to statically display its text String in the format determined by the basic formatting styles. For performance, its TextLines do not contain information about individual glyphs; for more info, see flash.text.engine.TextLineValidity.STATIC.
The specified text is wrapped at the right edge of the component's bounds. If it extends below the bottom, it is clipped. The display cannot be scrolled. Truncation is not currently supported but is under consideration.
TextBox's measure() method is implemented to determine the "natural" size of the text. If the width isn't specified, then text will be broken only at explicit linebreaks such as <p> and <br/>.
The only APIs that TextBox adds to TextGraphicElement are the basic formatting styles.
TextGraphic
TextGraphic is the middle-weight text primitive. Like TextBox, it is a GraphicElement, not a UIComponent. Although currently it always has its own DisplayObject, eventually it will do so only when necessary. It is implemented using TLF's TextLineFactory functionality, so using it increases the size of a SWF.
TextGraphic is basically Gumbo's replacement for <mx:Text>: it can display richly-formatted text, with multiple character and paragraph formats. However, it is completely non-interactive: it doesn't support scrolling, selection, or editing.
TextGraphic does not support drawing a background or border; it only renders text and inline graphics. It supports all the text formatting styles.
TextGraphic adds a content property of type Object, as explained in the section above about content.
TextGraphic uses TLF's TextLineFactory to create TextLines to display its TextFlow. For performance, its TextLines do not contain information about individual glyphs; for more info, see flash.text.engine.TextLineValidity.STATIC.
The specified text is wrapped at the right edge of the component's bounds. If it extends below the bottom, it is clipped. The display cannot be scrolled. Truncation is not currently supported, but is under consideration.
TextGraphics's measure() method is implemented to determine the "natural" size of the text. If the width isn't specified, then text will be broken only at explicit linebreaks such as <p> and <br/>.
TextView
TextView is the most heavyweight of the three text primitives, because it offers the most functionality. Unlike TextBox and TextGraphic, it is a UIComponent rather than a GraphicElement, in order to be able to take focus. It is implemented by having TLF control TextLines within the TextView via a DisplayObjectContainerController. In addition to offering TextGraphic's rendering capabilities, it also supports hyperlinks, scrolling, selection, and editing.
TextView is basically a chromeless <mx:TextArea>: it renders a scrollable rectangle of selectable/editable text and inline graphics, but it doesn't support drawing a background, border, or scrollbars. You combine it with other components to do that. For example, new Gumbo components like FxTextInput and FxTextArea use a TextView in their skin to provide the scrollable area where the text is rendered and edited. TextView supports all the text formatting styles.
For setting the text to display, TextView supports both text and content properties. It also supports insertText() and appendText() methods. The content can be exported to XML using the export() method, which produces XML with a TextFlow root tag.
TextView's measure() method does not determine the measured size from the text to be displayed, because a TextView often starts out with no text. Instead it uses two properties called widthInChars and heightInLines to determine its measuredWidth and measuredHeight. These are similar to the cols and rows of an HTML <TEXTAREA>.
TextView supports autoscrolling while selecting or editing, and also supports user scrolling via the mouse wheel. Although it has no scrollbars, it supports programmatic scrolling via the horizontalScrollPosition and verticalScrollPosition properties. The scrolling range can be determined from the contentWidth and contentHeight properties. A selectionChange event is dispatched when the selection changes. Scrolling is currently pixel-based, but line-based scrolling is likely to be added.
The selectability of the content is determined by the selectable property. The selection range can be determined from the read-only selectionAnchorPosition and selectionActivePosition properties and can be set with the setSelection() method. The format of the selection can be determined with the getSelectionFormat() method and set wtih the setSelectionFormat() method.
The editability of the content is determined by the editable property. Each editing operation is preceded by a cancelable changing event and followed by a change event, which specify the FlowOperation that is occurring. (Note: Unlike a TextField's textInput event, the changing event lets you listen for deletions as well as insertions.)
The multiline property determines the behavior of the Enter key when the content is editable. If this property is true, the Enter key terminates the current paragraph. If this property is false, the Enter key does not affect the content and instead causes an enter event to be dispatched.
FxTextBase
FxTextBase is the base class for skinnable Gumbo components whose skin contains a TextView, such as FxTextInput and FxTextArea. It extends FxComponent, the base class for all Gumbo-skinnable components.
The TextView is available via the textView property. FxTextBase facades some of TextView's APIs for convenience. If you need other TextView functionality, access it through textView.
FxTextBase has a text property, but does not support a content property for rich text. (Nobody needs a single-line rich text editor, do they?) It supports the same text formatting styles as TextView, which provide all of TLF's formatting capabilities. (These are actually declared on FxComponent.) It exposes insertText() and appendText() methods.
For selection, it exposes selectionActivePosition and selectionAnchorPosition read-only properties and a setSelection() method.
FxTextInput redispatches its TextView's selectionChange, changing, and change events.
API Description
Class TextGraphicElement
Class TextBox
Class TextGraphic
Class TextView
Class FxTextBase
Class TextOperationEvent
B Features
None.
Examples and Usage
TextBox
If you simply specify the text, it will be formatted according the text formatting styles found by the usual getStyle() search algorithm. The TextBox will be just large enough to display the specified text.
Since text is the default property of a TextBox, you can also specify it like this:
Since TextBox supports CSS, you can use class selectors and instance styles:
If you specify an explicit width or a percentage width, the text will, by default, get wrapped to that width:
You can use newline characters to create explicit line breaks. In this case, the TextBox will be as wide as the longest line.
Of course, you can specify explicit linebreaks even when using implicit wrapping. If you use neither, all the text will appear in a single, wide line.
If you don't specify a height, the height is calculated to be big enough to display all the text. If you specify an explicit height or a percent height and the text doesn't fit, the glyphs are clipped to the bounds you specify.
TextGraphic
The examples above for TextBox are also valid for TextGraphic, although when you use TextGraphic the default property is content. However, you can go further and use rich text. The most explicit way to do this is to set the content to a TextFlow instance:
Since content is the default property of TextGraphic, you can omit it:
You can also get terser by setting the content to an Array of Strings and FlowElements, such as in this example:
The MXML compiler treats the character data "Hello, " as if it were wrapped in a <String> tag:
You can also set the content to a single FlowElement:
or to a single String:
TextView
The examples for TextBox and TextGraphic are also valid for TextView. But if you use TextView, the text will by default be scrollable, selectable, and editable.
Additional Implementation Details
None.
Prototype Work
None.
Compiler Work
The MXML compiler has already been modified to support "mixed content", and it is being modified to support enhanced font embedding using the new DefineFont4 SWF tag, as required for use with FTE.
Web Tier Compiler Impact
None.
Flex Feature Dependencies
The skins for the Gumbo components will make use of these text primitives.
TextGraphic and TextView depend on the TLF library.
Backwards Compatibility
Syntax changes
None.
Behavior
None.
Warnings/Deprecation
None.
Accessibility
This is nontrivial and under investigation. It should be possible to get a screen reader to read the entire text of these components using Flash Player 10.0. However, reading the selection will require a new API in Flash Player 10.X.
Performance
The goal is to match Halo components, which used TextField, in speed and memory. Achieving this will depend on further optimizations in FTE beyond those in Flash Player 10.
Globalization
The goal is to accept Unicode input in any language, but Flash Player 10.0 doesn't make this possible. (In particular, Arabic and Hebrew input are not possible on the Mac.) This should improve in Flash Player 10.X.
Localization
Compiler Features
None.
Framework Features
None. The Flex code for these components does not throw any RTEs. But TLF needs to be able to hook into Flex's ResourceManager to get localized RTE messages.
Issues and Recommendations
1. Player 10.X needs to reduce the memory footprint of FTE.
2. It would be natural for TLF FlowElements such as paragraphs and spans to support CSS, but TLF is not currently architected for this. There are ongoing discussions with the TLF team regarding this.
3. It would be natural for all FlowElements – not just LinkElements – to support mouse events, but TLF is not currently architected for this. There are ongoing discussions with the TLF team regarding this.
4. Player 10.X needs to support a new accessibility API for conveying the selection from TLF to the Player.
5. Player 10.X needs to support Unicode input with any input system on Windows and Macintosh.
6. We need to make sure that FTE and TLF can support cross-SWF font embedding without using Font.registerFont().
7. Player 10.X should either support countable mouse events (e.g., second mouseDown) or expose the system's doubleclick threshold.
8. Player 10.X should have an API for getting the system's text selection color.
9. The tabStops style is supposed to be a possibly-empty Array of TabStopFormat instances, but it isn't clear how to specify this in CSS syntax.
10. TextView needs to support line-by-line vertical scrolling, including for nonuniform lineheights.
Documentation
None.
QA
TBD
|
 |
Amazing!
and to think, there was a time when all was was hoping for from vm10 was that the <ul><li> html text rendering was fixed to help with text formatting.
I hardly know where to start. This is so much more than I could of hoped for.
Thank you!
(ps. thats twice now that the 'please type this word graphic thingy' has said fatter!, are you trying to tell me something?)