//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// // //======================================================================================== package flashx.textLayout.factory { import flash.geom.Rectangle; import flash.text.engine.TextLine; import flashx.textLayout.compose.FlowComposerBase; import flashx.textLayout.container.ScrollPolicy; import flashx.textLayout.debug.assert; import flashx.textLayout.elements.Configuration; import flashx.textLayout.elements.IConfiguration; import flashx.textLayout.elements.ParagraphElement; import flashx.textLayout.elements.SpanElement; import flashx.textLayout.elements.TextFlow; import flashx.textLayout.formats.BlockProgression; import flashx.textLayout.formats.ITextLayoutFormat; import flashx.textLayout.formats.LineBreak; import flashx.textLayout.tlf_internal; use namespace tlf_internal; /** * The StringTextLineFactory class provides a simple way to create TextLines from a string. * *
The text lines are static and are created using a single format and a single paragraph. * The lines are created to fit in the specified bounding rectangle.
* *The StringTextLineFactory provides an efficient way to create TextLines, since it reuses single TextFlow, * ParagraphElement, SpanElement, and ContainerController objects across many repeated invocations. You can create a * single factory, and use it again and again. You can also reuse all the parts that are the same each time * you call it; for instance, you can reuse the various formats and the bounds.
* *Note: To create static lines that use multiple formats or paragraphs, or that include * inline graphics, use a TextFlowTextLineFactory and a TextFlow object.
* * @includeExample examples\StringTextLineFactory_example.as -noswf * * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 * * @see flashx.textLayout.factory.TextFlowTextLineFactory TextFlowTextLineFactory */ public final class StringTextLineFactory extends TextLineFactoryBase { private var _tf:TextFlow; private var _para:ParagraphElement; private var _span:SpanElement; private var _formatsChanged:Boolean; static private var _defaultConfiguration:Configuration = null; private var _configuration:IConfiguration; /** * The configuration used by the internal TextFlow object. * * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ public function get configuration():IConfiguration { return _configuration; } /** * The default configuration used by this factory if none is specified. * * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ static public function get defaultConfiguration():IConfiguration { if (!_defaultConfiguration) { _defaultConfiguration = TextFlow.defaultConfiguration.clone(); _defaultConfiguration.flowComposerClass = getDefaultFlowComposerClass(); _defaultConfiguration.textFlowInitialFormat = null; } return _defaultConfiguration; } /** * Creates a StringTextLineFactory object. * * @param configuration The configuration object used to set the properties of the * internal TextFlow object used to compose lines produced by this factory. * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ public function StringTextLineFactory(configuration:IConfiguration = null):void { super(); initialize(configuration); } private function initialize(config:IConfiguration):void { _configuration = Configuration(config ? config : defaultConfiguration).getImmutableClone(); _tf = new TextFlow(_configuration); _para = new ParagraphElement(); _span = new SpanElement(); _para.replaceChildren(0, 0, _span); _tf.replaceChildren(0, 0, _para); _tf.flowComposer.addController(containerController); _formatsChanged = true; } /** * The character format. * * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ public function get spanFormat():ITextLayoutFormat { return _span.format; } public function set spanFormat(format:ITextLayoutFormat):void { _span.format = format; _formatsChanged = true; } /** * The paragraph format. * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ public function get paragraphFormat():ITextLayoutFormat { return _para.format; } public function set paragraphFormat(format:ITextLayoutFormat):void { _para.format = format; _formatsChanged = true; } /** * The text flow format. * @playerversion Flash 10 * @playerversion AIR 1.5 * @langversion 3.0 */ public function get textFlowFormat():ITextLayoutFormat { return _tf.format; } public function set textFlowFormat(format:ITextLayoutFormat):void { _tf.format = format; _formatsChanged = true; } /** * The text to convert into TextLine objects. * *To produce TextLines, call createTextLines()
after setting this
* text
property and the desired formats.
The text lines are created using the currently assigned text and formats and
* are composed to fit the bounds assigned to the compositionBounds
property.
* As each line is created, the factory calls the function specified in the
* callback
parameter. This function is passed the TextLine object and
* is responsible for displaying the line.
To create a different set of lines, change any properties desired and call
* createTextLines()
again.
createTextLines
* If no truncation is performed, a string equal to text
is returned.
* If truncation is performed, but nothing fits, an empty string is returned.
* Otherwise, a substring of text
followed by the truncation indicator is returned.
*/
tlf_internal function get truncatedText():String
{ return _truncatedText; }
private var _truncatedText:String;
/**
* Measures the truncation indicator using the same bounds and formats, but without truncation options
* Resultant lines are added to _measurementLines
*/
private function measureTruncationIndicator (compositionBounds:Rectangle, truncationIndicator:String):void
{
var originalLines:Array = _factoryComposer.swapLines(measurementLines()); // ensure we don't overwrite original lines
var measureFactory:StringTextLineFactory = measurementFactory();
measureFactory.compositionBounds = compositionBounds;
measureFactory.text = truncationIndicator;
measureFactory.spanFormat = spanFormat;
measureFactory.paragraphFormat = paragraphFormat;
measureFactory.textFlowFormat = textFlowFormat;
measureFactory.truncationOptions = null;
measureFactory.createTextLinesInternal(noOpCallback);
_factoryComposer.swapLines(originalLines); // restore
}
/**
* Gets the truncation position on a line given the allowed width
* - Must be at an atom boundary
* - Must scan the line for atoms in logical order, not physical position order
* For example, given bi-di text ABאבCD
* atoms must be scanned in this order
* A, B, א
* ג, C, D
*/
private function getTruncationPosition (line:TextLine, allowedWidth:Number):uint
{
var consumedWidth:Number = 0;
var charPosition:int = line.userData; // start of line
while (charPosition < line.userData + line.rawTextLength) // end of line
{
var atomIndex:int = line.getAtomIndexAtCharIndex(charPosition);
var atomBounds:Rectangle = line.getAtomBounds(atomIndex);
consumedWidth += atomBounds.width;
if (consumedWidth > allowedWidth)
break;
charPosition = line.getAtomTextBlockEndIndex(atomIndex);
}
line.flushAtomData();
return charPosition;
}
private function noOpCallback(line:TextLine):void
{
}
}
}