blob: 03d0c7fc54784bc832fa220110e1186fdd89114f [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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 UnitTest.Tests
{
import UnitTest.ExtendedClasses.TestDescriptor;
import UnitTest.ExtendedClasses.TestSuiteExtended;
import UnitTest.ExtendedClasses.VellumTestCase;
import UnitTest.Fixtures.TestConfig;
import UnitTest.Validation.BoundsChecker;
import UnitTest.Validation.CompositionResults;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.engine.TextLine;
import flash.text.engine.TextLineValidity;
import flash.ui.KeyLocation;
import flashx.textLayout.*;
import flashx.textLayout.compose.IFlowComposer;
import flashx.textLayout.compose.StandardFlowComposer;
import flashx.textLayout.container.ContainerController;
import flashx.textLayout.container.ScrollPolicy;
import flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.debug.assert;
import flashx.textLayout.edit.SelectionFormat;
import flashx.textLayout.edit.SelectionState;
import flashx.textLayout.edit.TextScrap;
import flashx.textLayout.elements.*;
import flashx.textLayout.events.CompositionCompleteEvent;
import flashx.textLayout.factory.StringTextLineFactory;
import flashx.textLayout.factory.TruncationOptions;
import flashx.textLayout.formats.BlockProgression;
import flashx.textLayout.formats.ClearFloats;
import flashx.textLayout.formats.Direction;
import flashx.textLayout.formats.FormatValue;
import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.formats.LineBreak;
import flashx.textLayout.formats.TextAlign;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.formats.VerticalAlign;
import flashx.textLayout.utils.NavigationUtil;
use namespace tlf_internal;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.factory.StringTextLineFactory;
import flashx.textLayout.compose.TextFlowLine;
import flashx.textLayout.edit.IEditManager;
import flashx.textLayout.formats.Float;
import spark.primitives.Line;
import flash.events.MouseEvent;
import flash.events.IEventDispatcher;
import flash.display.Shape;
import flashx.textLayout.events.TextLayoutEvent;
import mx.core.Container;
import mx.core.UIComponent;
import mx.utils.LoaderUtil;
import flashx.textLayout.events.StatusChangeEvent;
import flashx.textLayout.factory.TextFlowTextLineFactory;
import mx.containers.Canvas;
public class FloatTest extends VellumTestCase
{
private var _textFlow:TextFlow;
private var _flowComposer:IFlowComposer;
private var _editManager:IEditManager;
private var _testXML:XML;
private var _currentContent:String; // content in TextFlow
private var _disableVerticalCheck:Boolean; // don't check floats vertical location; tests that force floats down should set this
private var _floatColor:int;
private var _disableBoundsCheck:Boolean = false;
private static var _englishContent:String = "There are many such lime-kilns in that tract of country, for the purpose of burning the white marble which composes a large part of the substance of the hills. Some of them, built years ago, and long deserted, with weeds growing in the vacant round of the interior, which is open to the sky, and grass and wild-flowers rooting themselves into the chinks of the stones, look already like relics of antiquity, and may yet be overspread with the lichens of centuries to come. Others, where the lime-burner still feeds his daily and nightlong fire, afford points of interest to the wanderer among the hills, who seats himself on a log of wood or a fragment of marble, to hold a chat with the solitary man. It is a lonesome, and, when the character is inclined to thought, may be an intensely thoughtful occupation; as it proved in the case of Ethan Brand, who had mused to such strange purpose, in days gone by, while the fire in this very kiln was burning.\n" +
"The man who now watched the fire was of a different order, and troubled himself with no thoughts save the very few that were requisite to his business. At frequent intervals, he flung back the clashing weight of the iron door, and, turning his face from the insufferable glare, thrust in huge logs of oak, or stirred the immense brands with a long pole. Within the furnace were seen the curling and riotous flames, and the burning marble, almost molten with the intensity of heat; while without, the reflection of the fire quivered on the dark intricacy of the surrounding forest, and showed in the foreground a bright and ruddy little picture of the hut, the spring beside its door, the athletic and coal-begrimed figure of the lime-burner, and the half-frightened child, shrinking into the protection of his father's shadow. And when again the iron door was closed, then reappeared the tender light of the half-full moon, which vainly strove to trace out the indistinct shapes of the neighboring mountains; and, in the upper sky, there was a flitting congregation of clouds, still faintly tinged with the rosy sunset, though thus far down into the valley the sunshine had vanished long and long ago."
private static var _japaneseContent:String = '文字コードが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクションでは、このようなグリフスする方法について解説しまが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクす。\n文字コードが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクションでは、このようなグリフスする方法について解説しまが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクす。\n' +
'文字コードが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクションでは、このようなグリフスする方法について解説しまが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクす。\n文字コードが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクションでは、このようなグリフスする方法について解説しまが割り当てられていないグリフの大半は既に文字コードが割り当てられているグリフの異体字です。次のセクす。';
public function FloatTest(methodName:String, testID:String, testConfig:TestConfig, testXML:XML = null)
{
super (methodName, testID, testConfig);
_testXML = testXML;
TestData.fileName = null;
// Note: These must correspond to a Watson product area (case-sensitive)
metaData.productArea = "Text Composition";
_floatColor = 0xFF0000;
}
public static function suite(testConfig:TestConfig, ts:TestSuiteExtended):void
{
addTestCase(ts, testConfig, "atFlowStart");
addTestCase(ts, testConfig, "atFlowStartSpaceBefore");
addTestCase(ts, testConfig, "atParagraphStart");
addTestCase(ts, testConfig, "atParagraphStartSpaceBefore");
addTestCase(ts, testConfig, "atParagraphEnd");
addTestCase(ts, testConfig, "atLineStart");
addTestCase(ts, testConfig, "atLineMiddle");
addTestCase(ts, testConfig, "atLineEnd");
addTestCase(ts, testConfig, "stackedFloats");
addTestCase(ts, testConfig, "onTwoSidesSameLine");
addTestCase(ts, testConfig, "onTwoSidesSuccessiveLines");
ts.addTestDescriptor (new TestDescriptor (FloatTest,"fillsColumn", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"noEmergencyBreakByFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"fillsColumnRecursion", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"widerThanColumn", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"widerThanColumnScroll", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"contentHeightCheck", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"noFloatsWithMeasureOrExplicit", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"floatOnly", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"noVJ", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"verticalAlignMiddleFloatAtEnd", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"verticalAlignMiddleTextAtEnd", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"verticalAlignBottomFloatAtEnd", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"verticalAlignBottomTextAtEnd", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"verticalAlignBottomFloat2636122", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"textAlignRightAtStart", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"textAlignRightInMiddle", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"leftIndent", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"rightIndent", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"leftBigIndent", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"rightBigIndent", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"clearOneAll", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"clearTwoAll", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"paddingAndMargins", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"negativePaddingAndMargins", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"rightIndentWithTab", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"leftIndentWithTab", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"hoistFailure", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"clearNoPrecedingFloatAll", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"stackedLeftFloats", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"stackedRightFloats", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"smallFloatBigText", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"lineHeightIgnoredOnFloatingImages", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"convertFloatToInline", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"cursorByAnchor", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"insertTextBeforeFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"atControllerEnd", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"resizeControllerWithFloats", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"textIndentAfterFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"composeAcrossControllers", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"deleteAtStart", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"measureWidth", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"inlineWideAndFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"narrowColumnFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"infiniteLoop2769562", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest, "verticalAlignInline", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest, "pasteManyFloatsWithLoading", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"contentBoundsWithFactoryComposition", testConfig, null) );
// We only need one version of these tests
if (testConfig.writingDirection[0] == BlockProgression.TB && testConfig.writingDirection[1] == Direction.LTR)
{
ts.addTestDescriptor (new TestDescriptor (FloatTest,"inlineAndFloat", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"htmlImportTest", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"overFlowAtStart", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"caretOnEmptyInlineGraphic", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"restartComposeFromStart", testConfig, null) );
ts.addTestDescriptor (new TestDescriptor (FloatTest,"convertInlineToFloat", testConfig, null) );
}
}
private static function addTestCase(ts:TestSuiteExtended, testConfig:TestConfig, methodName:String):void
{
//ts.addTestDescriptor (new TestDescriptor (MeasurementGridTest,methodName, testConfig, creationType, measureType, lineBreak) );
var testXML:XML = <TestCase>
<TestData name="methodName">{methodName}</TestData>
<TestData name="id">{methodName}</TestData>
</TestCase>;
ts.addTestDescriptor (new TestDescriptor (FloatTest,"callTestMethod", testConfig, testXML) );
}
override public function setUp() : void
{
super.setUp();
initializeSourceTextFlow();
initializeFlow(TextConverter.importToFlow(_englishContent, TextConverter.PLAIN_TEXT_FORMAT));
}
override public function tearDown(): void
{
if (TestFrame && TestFrame.textFlow && !_disableBoundsCheck)
{
var s:Sprite = new Sprite();
testApp.getDisplayObject().rawChildren.addChild(s);
BoundsChecker.validateAll(TestFrame.textFlow, s, 10, true);
testApp.getDisplayObject().rawChildren.removeChild(s);
}
super.tearDown();
}
private function initializeFlow(textFlow:TextFlow):void
{
_textFlow = textFlow;
_flowComposer = _textFlow.flowComposer;
VellumTestCase.testApp.contentChange (_textFlow);
TestDisplayObject = VellumTestCase.testApp.getDisplayObject();
TestFrame = _textFlow.flowComposer.getControllerAt(0);
if (TestFrame.rootElement)
{
// Set the writing direction specified by the test
_textFlow.blockProgression = writingDirection[0];
_textFlow.direction = writingDirection[1];
SelManager = EditManager(_textFlow.interactionManager);
if(SelManager)
{
SelManager.selectRange(0, 0);
//make sure there is never any blinking when running these tests
setCaretBlinkRate (0);
}
_editManager = SelManager;
}
_textFlow.flowComposer.updateAllControllers();
}
private static var sourceTextFlow:Array;
private function setUpFlow(content:String):void
{
var sourceFlow:TextFlow;
if (content == _englishContent)
sourceFlow = sourceTextFlow[0];
else if (content == _japaneseContent)
sourceFlow = sourceTextFlow[1];
else
sourceFlow = TextConverter.importToFlow(content, TextConverter.PLAIN_TEXT_FORMAT);
_textFlow.replaceChildren(0, _textFlow.numChildren);
assertTrue("Empty TextFlow has incorrect ContainerLength",_textFlow.textLength == _textFlow.flowComposer.getControllerAt(0).textLength);
var newFlow:TextFlow = sourceFlow.deepCopy() as TextFlow;
var childCount:int = newFlow.numChildren;
for (var i:int = newFlow.numChildren - 1; i >= 0; --i)
{
var child:FlowElement = newFlow.getChildAt(i);
_textFlow.addChildAt(0, child);
}
_textFlow.flowComposer.updateAllControllers();
_textFlow.interactionManager.selectRange(0, 0);
_currentContent = content;
}
private function initializeSourceTextFlow():void
{
sourceTextFlow = [];
// Create english content
var englishFlow:TextFlow = TextConverter.importToFlow(_englishContent, TextConverter.PLAIN_TEXT_FORMAT);
sourceTextFlow.push(englishFlow);
// Create japanese content
var japaneseFlow:TextFlow = TextConverter.importToFlow(_japaneseContent, TextConverter.PLAIN_TEXT_FORMAT);
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat();
textFlowFormat.locale = "ja";
japaneseFlow.format = textFlowFormat;
sourceTextFlow.push(japaneseFlow);
}
// axies
static private var floatTypeList:Array = [Float.LEFT, Float.RIGHT /*, Float.START, Float.END */]; // start & end disabled to make tests run faster
static private var contentLanguageList:Array = [ _englishContent, _japaneseContent];
static private var floatWidthList:Array = [ 5, 20, 50, 100, 200, 400 ]
static private var floatHeightList:Array = [ 5, 20, 50, 100, 200, 400 ];
public function callTestMethod():void
{
for each (var content:String in contentLanguageList)
{
var TestCase:XML = _testXML;
var methodName:String = TestCase.TestData.(@name == "methodName").toString();
for each (var floatValue:String in floatTypeList)
for each (var floatWidth:String in floatWidthList)
for each (var floatHeight:String in floatHeightList)
{
setUpFlow(content);
// trace(methodName, floatValue, floatWidth.toString(), floatHeight.toString());
this[methodName](floatValue, floatWidth, floatHeight);
}
}
}
// Test Cases:
// float at paragraph start (left, right)
// float at line start (left, right)
// float in middle of line (left, right)
// stacked floats (left, right)
// multiple (stacked) floats at start
// floats with no graphic
// float doesn't fit in container (width/height) (*on end last para height = 400 this happens)
// float does fit in container, following line does not
// float at end of container
// floats in multiple columns
// float fits, not enough space for text (min-width??)
import flashx.textLayout.edit.ElementRange;
import flashx.textLayout.edit.ParaEdit;
private function addFloatAtPosition(position:int, width:Number, height:Number, float:String):DisplayObject
{
var secondColor:int = 0;
switch(_floatColor)
{
case 0xFF0000: secondColor = 0x770000;
break;
case 0x00FF00: secondColor = 0x007700;
break;
case 0x0000FF: secondColor = 0x000077;
break;
}
// Create a simple rectangular display object for the float
// Rectangle is two tone, to make it easier to know which part you're looking at
var displayObject:Sprite = new Sprite();
var g:Graphics = displayObject.graphics;
g.beginFill(_floatColor);
g.drawRect(0, 0, width/2, height);
g.endFill();
g.beginFill(secondColor);
g.drawRect(width/2, 0, width/2, height);
g.endFill();
// Cycle through colors so multiple floats can be visually disintguished
switch (_floatColor)
{
case 0xFF0000: _floatColor = 0x00FF00;
break;
case 0x00FF00: _floatColor = 0x0000FF;
break;
case 0x0000FF: _floatColor = 0xFF0000;
break;
}
// Add it to the TextFlow at the specified location
// _editManager.insertInlineGraphic(displayObject, width, height, float, new SelectionState(_textFlow, position, position));
var range:ElementRange = ElementRange.createElementRange(_textFlow,position, position);
var leafNode:FlowElement = range.firstLeaf;
var leafNodeParent:FlowGroupElement = leafNode.parent;
ParaEdit.createImage(leafNodeParent, position - leafNodeParent.getAbsoluteStart(), displayObject, width, height, float, null);
return displayObject;
}
private function atParagraphStartInternal(leaf:FlowLeafElement, width:Number, height:Number, float:String, paragraphSpaceBefore:Number = 0):void
{
var paragraph:ParagraphElement = leaf.getParagraph();
var paraStart:int = paragraph.getAbsoluteStart();
if (paragraph.computedFormat.paragraphSpaceBefore != paragraphSpaceBefore)
{
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat();
paragraphFormat.paragraphSpaceBefore = paragraphSpaceBefore;
paragraph.format = paragraphFormat;
}
var floatObject:DisplayObject = addFloatAtPosition(paraStart, width, height, float);
verifyFloatInLine(paraStart, width, height, float, floatObject);
}
/** Test adding a float to the start of the first and last paragraphs, with either left or right float, and with
* spaceBefore either 0 or 15. */
private function atFlowStart(float:String, width:Number, height:Number):void
{
// On the first paragraph, add a float
atParagraphStartInternal(_textFlow.getFirstLeaf(), width, height, float);
}
/** Test adding a float to the start of the first and last paragraphs, with either left or right float, and with
* spaceBefore either 0 or 15. */
private function atFlowStartSpaceBefore(float:String, width:Number, height:Number):void
{
// On the first paragraph, add a float
atParagraphStartInternal(_textFlow.getFirstLeaf(), width, height, float, 15);
}
/** Test adding a float to the start of the first and last paragraphs, with either left or right float, and with
* spaceBefore either 0 or 15. */
private function atParagraphStart(float:String, width:Number, height:Number):void
{
// On the last paragraph, add a float
atParagraphStartInternal(_textFlow.getLastLeaf(), width, height, float);
}
private function atParagraphStartSpaceBefore(float:String, width:Number, height:Number):void
{
// On the last paragraph, add a spaceBefore and a float
atParagraphStartInternal(_textFlow.getFirstLeaf(), width, height, float, 15);
}
// Certify that the float was added to the container
// Certify that the float appears below the previous line's descenders
// Check that float appears at the correct horizontal alignment (left or right)
// If there's an intersecting float that comes before, it would appear to the left or right of that float (i.e., stacked)
// Look to see if they overlap in the blockProgression direction; if so, they're going to stack if they have the same float property
// Check the vertical location of the float. It should go below the previous line's descender, and at or above the next line.
// The EXCEPTION is if the float was displaced lower because it didn't fit on it's natural position (too wide). In that case,
// float may appear below following lines. Test needs to flag this so we don't assert false positive.
private function verifyFloatInLine(pos:int, width:Number, height:Number, float:String, floatObject:DisplayObject):void
{
if (float == Float.NONE) // not a float, nothing to check
return;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(pos);
var previousTextFlowLine:TextFlowLine;
var textFlowLine:TextFlowLine;
// Certify that the float was added to the container
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var firstLine:TextFlowLine = controller.getFirstVisibleLine();
var lastLine:TextFlowLine = controller.getLastVisibleLine();
var firstLineIndex:int = firstLine ? _textFlow.flowComposer.findLineIndexAtPosition(firstLine.absoluteStart) : -1;
var lastLineIndex:int = lastLine ? _textFlow.flowComposer.findLineIndexAtPosition(lastLine.absoluteStart) : -1;
if (lineIndex >= firstLineIndex && lineIndex <= lastLineIndex)
{
assertTrue("Float not added as child of the container", controller.container.contains(floatObject));
// Certify that the float appears below the previous line's descenders
if (lineIndex > firstLineIndex)
{
previousTextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex - 1);
}
textFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
// Check that float appears at the correct horizontal alignment (left or right)
// If there's an intersecting float that comes before, it would appear to the left or right of that float (i.e., stacked)
var currentPos:int = textFlowLine.absoluteStart + textFlowLine.textLength;
var floatRect:Rectangle = new Rectangle(floatHolder.x, floatHolder.y, floatObject.width, floatObject.height);
var pos:int = 0;
var paraFormat:ITextLayoutFormat = textFlowLine.paragraph.computedFormat;
var maxLeft:Number = 0;
var maxRight:Number = verticalText ? controller.compositionHeight : controller.compositionWidth;
var otherDirection:String;
var otherFloatType:String;
for (var leaf:FlowLeafElement = _textFlow.getFirstLeaf(); leaf && pos < currentPos; leaf = leaf.getNextLeaf())
{
var otherInline:InlineGraphicElement = leaf as InlineGraphicElement;
if (otherInline)
{
if (otherInline.graphic == floatObject) // this is our float, we're done
break;
// Look to see if they overlap in the blockProgression direction; if so, they're going to stack if they have the same float property
if (verticalText)
{
if (Math.floor(otherInline.graphic.parent.x) < Math.floor(floatRect.right))
{
otherDirection = otherInline.getParagraph().computedFormat.direction;
otherFloatType = otherInline.computedFloat;
if (otherFloatType == Float.START)
otherFloatType = (otherDirection == Direction.LTR) ? Float.LEFT : Float.RIGHT;
else if (otherFloatType == Float.END)
otherFloatType = (otherDirection == Direction.RTL) ? Float.LEFT : Float.RIGHT;
if (otherFloatType == Float.RIGHT)
maxRight -= otherInline.elementHeight;
if (otherFloatType == Float.LEFT)
maxLeft += otherInline.elementHeight;
}
}
else
{
if (otherInline.graphic.parent.y + otherInline.elementHeight > floatRect.top)
{
otherDirection = otherInline.getParagraph().computedFormat.direction;
otherFloatType = otherInline.computedFloat;
if (otherFloatType == Float.START)
otherFloatType = (otherDirection == Direction.LTR) ? Float.LEFT : Float.RIGHT;
else if (otherFloatType == Float.END)
otherFloatType = (otherDirection == Direction.RTL) ? Float.LEFT : Float.RIGHT;
if (otherFloatType == Float.LEFT)
maxLeft += otherInline.elementWidth;
if (otherFloatType == Float.RIGHT)
maxRight -= otherInline.elementWidth;
}
}
}
pos += leaf.textLength;
}
// Check the vertical location of the float. It should go below the previous line's descender, and at or above the next line.
// The EXCEPTION is if the float was displaced lower because it didn't fit on it's natural position (too wide). In that case,
// float may appear below following lines. Test needs to flag this so we don't assert false positive.
if (!_disableVerticalCheck)
{
var floatAlignsWithPrevious:Boolean = false;
if (previousTextFlowLine)
{
if (verticalText)
floatAlignsWithPrevious = Math.abs((floatHolder.x + floatObject.width) - (previousTextFlowLine.x - previousTextFlowLine.descent)) < 1;
else
floatAlignsWithPrevious = Math.abs(floatHolder.y - (previousTextFlowLine.y + previousTextFlowLine.ascent + previousTextFlowLine.descent)) < 1;
}
else // no previous line, so check it against the container logical top (assume 0)
if (verticalText)
floatAlignsWithPrevious = true;
else
floatAlignsWithPrevious = Math.abs(floatHolder.y) < 1;
var floatAlignsWithSameLine:Boolean = false;
if (verticalText)
floatAlignsWithSameLine = Math.abs((floatHolder.x + floatObject.width) - (textFlowLine.x - textFlowLine.descent)) < 1;
else
floatAlignsWithSameLine = Math.abs(floatHolder.y - (textFlowLine.y + textFlowLine.ascent + textFlowLine.descent)) < 1;
assertTrue("Float has incorrect logical vertical position", floatAlignsWithPrevious || floatAlignsWithSameLine);
}
// Check horizontal location of the float
if (float == Float.START)
float = (paraFormat.direction == Direction.LTR) ? Float.LEFT : Float.RIGHT;
else if (float == Float.END)
float = (paraFormat.direction == Direction.RTL) ? Float.LEFT : Float.RIGHT;
if (float == Float.LEFT)
{
if (verticalText)
assertTrue("Float should be on the left", Math.abs(floatHolder.y - maxLeft) < 1);
else
assertTrue("Float should be on the left", Math.abs(floatHolder.x - maxLeft) < 1);
}
else if (float == Float.RIGHT)
{
if (verticalText)
assertTrue("Float should be on the right", Math.abs(floatRect.bottom - maxRight) < 1);
else
assertTrue("Float should be on the right", Math.abs(floatRect.right - maxRight) < 1);
}
}
}
private function atLineStartInternal(lineIndex:int, width:Number, height:Number, float:String):void
{
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var pos:int = textFlowLine.absoluteStart;
var floatObject:DisplayObject = addFloatAtPosition(pos, width, height, float);
verifyFloatInLine(pos, width, height, float, floatObject);
}
private function atLineMiddleInternal(lineIndex:int, width:Number, height:Number, float:String):void
{
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
if (!textFlowLine)
return;
var pos:int = textFlowLine.absoluteStart + (textFlowLine.textLength/2);
var floatObject:DisplayObject = addFloatAtPosition(pos, width, height, float);
verifyFloatInLine(pos, width, height, float, floatObject); // aligns with next line
}
private function atLineEndInternal(lineIndex:int, width:Number, height:Number, float:String):void
{
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var pos:int = textFlowLine.absoluteStart + textFlowLine.textLength - 1;
var floatObject:DisplayObject = addFloatAtPosition(pos, width, height, float);
verifyFloatInLine(pos, width, height, float, floatObject); // aligns with next line
}
/** Test adding a float at the start of a line, float should appear below and to the left or right of the line. */
private function atLineStart(float:String, width:Number, height:Number):void
{
// At the start of the second line, add a left float
atLineStartInternal(1, width, height, float);
}
public function atLineMiddle(float:String, width:Number, height:Number):void
{
// At the start of the second line, add a left float
atLineMiddleInternal(1, width, height, float);
}
public function atLineEnd(float:String, width:Number, height:Number):void
{
// At the start of the second line, add a left float
atLineEndInternal(1, width, height, float);
}
private function atParagraphEndInternal(paragraph:ParagraphElement, width:Number, height:Number, float:String):void
{
var paragraph:ParagraphElement = _textFlow.getFirstLeaf().getParagraph();
var pos:int = paragraph.getAbsoluteStart() + paragraph.textLength - 1;
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(pos);
atLineEndInternal(lineIndex, width, height, float);
}
public function atParagraphEnd(float:String, width:Number, height:Number):void
{
if (height >= 400)
return;
// Add float to the end of the first paragraph
atParagraphEndInternal(_textFlow.getFirstLeaf().getParagraph(), width, height, float);
}
// Test multiple floats on successive lines
public function stackedFloats(float:String, width:Number, height:Number):void
{
if (width >= 400)
return;
atLineMiddleInternal(1, width, height, float);
// With a set of wide stacked floats, the second float gets pushed to after the
// preceding float, and therefore won't align with previous line's descender.
// This is correct, but will assert so we turn off the asserts here.
if ((_textFlow.blockProgression == BlockProgression.RL && height >= 400) ||
(_textFlow.blockProgression == BlockProgression.TB && width >= 400))
_disableVerticalCheck = true; // floats get pushed down b/c the second doesn't fit on the line, so don't check
atLineMiddleInternal(2, width, height, float);
}
private function flipFloat(float:String):String { return Float.LEFT ? Float.RIGHT : Float.LEFT; }
// Test multiple floats on successive lines on each side
public function onTwoSidesSuccessiveLines(float:String, width:Number, height:Number):void
{
// On successive lines
atLineMiddleInternal(1, width, height, float);
// With a set of wide stacked floats, the second float gets pushed to after the
// preceding float, and therefore won't align with previous line's descender.
// This is correct, but will assert so we turn off the asserts here.
if ((_textFlow.blockProgression == BlockProgression.RL && height >= 400) ||
(_textFlow.blockProgression == BlockProgression.TB && width >= 400))
_disableVerticalCheck = true; // floats get pushed down b/c the second doesn't fit on the line, so don't check
atLineMiddleInternal(2, width, height, flipFloat(float));
}
// Test multiple floats on the same line, one on each side
public function onTwoSidesSameLine(float:String, width:Number, height:Number):void
{
// On the same line
atLineMiddleInternal(2, width/2, height/2, float);
// With a set of wide stacked floats, the second float gets pushed to after the
// preceding float, and therefore won't align with previous line's descender.
// This is correct, but will assert so we turn off the asserts here.
if ((_textFlow.blockProgression == BlockProgression.RL && height >= 400) ||
(_textFlow.blockProgression == BlockProgression.TB && width >= 400))
_disableVerticalCheck = true; // floats get pushed down b/c the second doesn't fit on the line, so don't check
atLineMiddleInternal(2, width, height, flipFloat(float));
}
private function logicalContentHeight(controller:ContainerController, verticalText:Boolean):Number { return verticalText ? controller.contentWidth : controller.contentHeight; }
private function logicalContentWidth(controller:ContainerController, verticalText:Boolean):Number { return verticalText ? controller.contentHeight : controller.contentWidth; }
public function contentHeightCheck():void
{
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
_textFlow.flowComposer.composeToPosition();
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var contentHeight:Number = logicalContentHeight(controller, verticalText);
// Add a float to the end of the text, make sure it gets taller
atLineMiddleInternal(_textFlow.flowComposer.numLines - 1, 100, 100, Float.LEFT);
// The float goes even with the line, so not all the 100 pixels are added into the content height...
assertTrue("Expected larger content height because of trailing float", logicalContentHeight(controller, verticalText) > contentHeight + 70);
}
public function contentWidthCheckLongFloat():void
{ // Should be adapted for RL
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.lineBreak = LineBreak.EXPLICIT;
_textFlow.format = textFlowFormat;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
_textFlow.flowComposer.updateAllControllers();
var lineNumber:int;
var contentWidth:Number = logicalContentWidth(controller, verticalText);
atLineStartInternal(1, 7000, 115, Float.LEFT); // insert graphic longer than longest line
// assertTrue("Expected larger content width because of trailing float", logicalContentWidth(controller, verticalText) > contentWidth);
}
public function noFloatsWithMeasureOrExplicit():void
{
// We expect that when text is not wrapping, floats will behave as inlines.
var oldLinePos:Array;
var newLinePos:Array;
var flowComposer:IFlowComposer = _textFlow.flowComposer;
var controller:ContainerController = flowComposer.getControllerAt(0);
var textFlowFormat:TextLayoutFormat;
var width:Number = controller.compositionWidth;
var height:Number = controller.compositionHeight;
// Create baseline to compare against, using inlines
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
textFlowFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.lineBreak = LineBreak.EXPLICIT;
_textFlow.format = textFlowFormat;
atLineMiddleInternal(1, 100, 100, Float.NONE);
atLineMiddleInternal(2, 100, 100, Float.NONE);
flowComposer.updateAllControllers();
oldLinePos = getCompositionResults(verticalText, flowComposer);
// Flip inlines to floats
for (var leaf:FlowLeafElement = _textFlow.getFirstLeaf(); leaf; leaf = leaf.getNextLeaf())
{
if (leaf is InlineGraphicElement)
(leaf as InlineGraphicElement).float = Float.LEFT;
}
// Test lineBreak=explicit, with floats
flowComposer.updateAllControllers();
newLinePos = getCompositionResults(verticalText, flowComposer);
assertCompositionMatches(oldLinePos, newLinePos);
// Test with lineBreak=toFit, with measuring
textFlowFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.lineBreak = LineBreak.TO_FIT;
_textFlow.format = textFlowFormat;
if (verticalText)
controller.setCompositionSize(width, NaN);
else
controller.setCompositionSize(NaN, height);
flowComposer.updateAllControllers();
newLinePos = getCompositionResults(verticalText, flowComposer);
assertCompositionMatches(oldLinePos, newLinePos);
}
public function hoistFailure():void
// Test case where a graphic is narrow enough to get a hoist request, but too tall to fit once its composed.
// Should fall back to pushing to the next parcel.
{
var width:Number = 100;
var height:Number = 100;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
controller.horizontalScrollPolicy = ScrollPolicy.OFF;
controller.verticalScrollPolicy = ScrollPolicy.OFF;
if (verticalText)
width = controller.compositionWidth;
else
height = controller.compositionHeight;
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(1);
if (!textFlowLine)
return;
var pos:int = textFlowLine.absoluteStart + (textFlowLine.textLength/2);
var floatObject:DisplayObject = addFloatAtPosition(pos, width, height, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
assertTrue("Expected float to get pushed out of controller, but its a child of container", !controller.container.contains(floatObject));
assertTrue("Expected float to get pushed out of controller, but its within controller textLength bounds", pos > controller.absoluteStart + controller.textLength);
}
public function noEmergencyBreakByFloat():void
{
// We should get breaks in the middle of words because a float fills up most but not all of the column.
// Text should appear below the float if the word doesn't fit next to the float.
var secondParagraph:ParagraphElement = _textFlow.getChildAt(1) as ParagraphElement;
var width:Number = (_textFlow.computedFormat.blockProgression == BlockProgression.RL) ? 458 : 807;
var floatPosition:int = secondParagraph.getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, width, 60, Float.START);
_textFlow.flowComposer.updateAllControllers();
var textFlowLine:TextFlowLine = _textFlow.flowComposer.findLineAtPosition(floatPosition + 1);
var lastCharInLine:String = _textFlow.getText(textFlowLine.absoluteStart + textFlowLine.textLength - 1, textFlowLine.absoluteStart + textFlowLine.textLength);
assertTrue("Line should end with a legal word separator (expected space", lastCharInLine == " ");
}
public function fillsColumnRecursion():void
{
// Detects an infinite recursion in composition
// Add a float that almost but not quite fits the whole column
var secondParagraph:ParagraphElement = _textFlow.getChildAt(1) as ParagraphElement;
var width:Number = (_textFlow.computedFormat.blockProgression == BlockProgression.RL) ? 458 : 807;
var floatObject:DisplayObject = addFloatAtPosition(secondParagraph.getAbsoluteStart(), width, 60, Float.START);
_textFlow.flowComposer.updateAllControllers();
}
public function fillsColumn():void
{
var width:Number = 100;
var height:Number = 100;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
if (verticalText)
height = _textFlow.flowComposer.getControllerAt(0).compositionHeight;
else
width = _textFlow.flowComposer.getControllerAt(0).compositionWidth;
atLineMiddleInternal(1, width, height, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
}
public function atControllerEnd():void
{
// Float at the end of a scrollable container should appear in the container even if it
// would otherwise be too tall.
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
controller.verticalScrollPolicy = ScrollPolicy.ON;
var width:Number = 50;
var height:Number = controller.compositionHeight + 50;
if (verticalText)
{
width = controller.compositionWidth + 50;
height = 50;
}
var secondPara:ParagraphElement = _textFlow.getChildAt(1) as ParagraphElement;
var floatPosition:int = secondPara.getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, width, height, Float.START);
_textFlow.flowComposer.updateAllControllers();
assertTrue("Float should be in the container", controller.container.contains(floatObject));
if (verticalText)
controller.horizontalScrollPolicy = ScrollPolicy.OFF;
else
controller.verticalScrollPolicy = ScrollPolicy.OFF;
_textFlow.flowComposer.updateAllControllers();
assertTrue("Float should not be composed in the container", controller.absoluteStart + controller.textLength <= floatPosition);
assertTrue("Float should not be displayed in the container", !controller.container.contains(floatObject));
// Turning scrolling off changes the basic coordinate system
if (verticalText)
_disableBoundsCheck = true;
}
public function widerThanColumn():void
{
// Float is wider than the container. If the height of the float fits, and there are
// no preceeding floats, it should still go in the column, and overlap the adjacent
// columns
setUpContainers(3);
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var width:Number = controller.compositionWidth + 50;
var height:Number = 100;
if (verticalText)
{
width = 100;
height = controller.compositionHeight + 50;
}
_textFlow.flowComposer.updateAllControllers();
var contentBoundsTextOnly:Rectangle = controller.getContentBounds();
var floatObject:DisplayObject = addFloatAtPosition(0, width, height, Float.START);
verifyFloatInLine(0, width, height, Float.START, floatObject);
_textFlow.flowComposer.updateAllControllers();
var contentBoundsWithFloat:Rectangle = controller.getContentBounds();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
{
assertTrue("Content bounds with a float wider than the column should be larger than content bounds with just text", contentBoundsWithFloat.height > contentBoundsTextOnly.height);
assertTrue("Content bounds with a float should be equal to or greater than float alone", contentBoundsWithFloat.height >= height);
}
else
{
assertTrue("Content bounds with a float wider than the column should be larger than content bounds with just text", contentBoundsWithFloat.width > contentBoundsTextOnly.width);
assertTrue("Content bounds with a float should be equal to or greater than float alone", contentBoundsWithFloat.width >= width);
}
// Check that if the float protrudes past the text it's factored into the content height
SelManager.deleteText(new SelectionState(_textFlow, 50, int.MAX_VALUE)); // delete so there's not so much text
_textFlow.flowComposer.updateAllControllers();
var contentBoundsAfterDelete:Rectangle = controller.getContentBounds();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
{
assertTrue("Content bounds doesn't include logical height of float", contentBoundsAfterDelete.width >= width);
}
else
{
assertTrue("Content bounds doesn't include height of float", contentBoundsAfterDelete.height >= height);
}
SelManager.undo(); // undo the delete of the text
// Resize the first container smaller, so the float goes overset
if (verticalText)
controller.setCompositionSize(width - 1, controller.compositionHeight);
else
controller.setCompositionSize(controller.compositionWidth, height - 1);
_textFlow.flowComposer.updateAllControllers();
var secondController:ContainerController = _textFlow.flowComposer.getControllerAt(1);
assertTrue("Expected the float to get pushed to second container", secondController.absoluteStart == 0);
assertTrue("Float should be in the second container", secondController.container.contains(floatObject));
// Try it again with columns instead of containers -- should be the same
setUpContainers(1);
controller = _textFlow.flowComposer.getControllerAt(0);
controller.columnCount = 3;
verifyFloatInLine(0, width, height, Float.START, floatObject);
// Make the first float smaller, and add a second large float afterwards
var inlineElement:InlineGraphicElement = _textFlow.findLeaf(0) as InlineGraphicElement;
inlineElement.width = 50;
inlineElement.height = 50;
var secondFloat:DisplayObject = addFloatAtPosition(4, width, height, Float.START);
_textFlow.flowComposer.updateAllControllers();
assertTrue("Second float should not appear on the first line", verticalText ? (secondFloat.parent.x < floatObject.parent.x) : (secondFloat.parent.y > floatObject.parent.y));
assertTrue("Second float should be in the container", controller.container.contains(secondFloat));
}
public function widerThanColumnScroll():void // Watson 2762393
{
// Float is wider than the container. If any part of the float is visible, the
// float should appear in the container. Width of float should be counted in
// the contentWidth.
var xml:XML =
<TextFlow xmlns='http://ns.adobe.com/textLayout/2008'>
<span fontSize="20">Hello, Dear Guest,</span>
<p></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
<p></p>
<p></p>
<p></p>
<p><span>Donec sed risus nec risus elementum cursus eget non nulla. Integer dui mauris, lobortis at varius quis, elementum at justo. Ut lacinia arcu vitae ipsum pulvinar feugiat a ut risus. Vivamus nulla nisi, varius vitae commodo ut, volutpat quis magna. Cras posuere quam magna. Aenean felis purus, pellentesque nec fringilla id, dignissim quis elit. Praesent velit libero, laoreet quis dignissim id, varius quis neque. Suspendisse vulputate placerat purus. Fusce euismod fringilla ornare. Nulla et urna est. Proin a tellus et tortor feugiat iaculis.</span></p>
</TextFlow>;
initializeFlow(TextConverter.importToFlow(xml, TextConverter.TEXT_LAYOUT_FORMAT));
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
// Insert a float wider than the column into the empty second paragraph
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var width:Number = controller.compositionWidth + 100;
var height:Number = controller.compositionHeight + 100;
var floatPosition:int = _textFlow.getChildAt(1).getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, width, height, Float.END);
_textFlow.flowComposer.updateAllControllers();
verifyFloatInLine(floatPosition, width, height, Float.END, floatObject);
assertTrue("Float should be visible", controller.container.contains(floatObject));
var contentBoundsWithFloat:Rectangle = controller.getContentBounds();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
{
assertTrue("Content bounds with a float wider than the column should be larger than content bounds with just text", contentBoundsWithFloat.height > controller.compositionHeight);
assertTrue("Content bounds with a float should be equal to or greater than float alone", contentBoundsWithFloat.height >= height);
}
else
{
assertTrue("Content bounds with a float wider than the column should be larger than content bounds with just text", contentBoundsWithFloat.width > controller.compositionWidth);
assertTrue("Content bounds with a float should be equal to or greater than float alone", contentBoundsWithFloat.width >= width);
}
controller.verticalScrollPosition = contentBoundsWithFloat.height;
_textFlow.flowComposer.updateAllControllers();
// assertTrue("Float should not be visible", !controller.container.contains(floatObject));
controller.verticalScrollPosition = 0;
_textFlow.flowComposer.updateAllControllers();
assertTrue("Float should be visible", controller.container.contains(floatObject));
}
public function floatOnly():void
{
// TextFlow contains only a single float, no text
setUpFlow("");
atParagraphStartInternal(_textFlow.getFirstLeaf(), 100, 100, Float.LEFT);
// hittest (Watson 2617901)
// In RTL, we're getting different results from the Player depending on Astro or Argo...
if (_textFlow.computedFormat.direction == Direction.LTR || Configuration.playerEnablesArgoFeatures)
{
SelManager.selectRange(0, 0);
_flowComposer.updateAllControllers();
var controller:ContainerController = _flowComposer.getControllerAt(0);
var mouseEvent:MouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, 200, 200, controller.container, false, false, false, false);
controller.container.dispatchEvent(mouseEvent);
assertTrue("Expected insertion point after float", SelManager.absoluteStart == 1);
}
}
public function inlineAndFloat():void
{
// Inline as first leaf, followed by float. Watson 2636066
// TextFlow contains only a single float, no text
setUpFlow("A");
var inlineDO:DisplayObject = addFloatAtPosition(0, 100, 100, Float.NONE);
var floatDO:DisplayObject = addFloatAtPosition(1, 100, 100, Float.LEFT);
}
public function convertFloatToInline():void
{
var floatValueList:Array = [Float.LEFT, Float.RIGHT , Float.NONE, Float.START, Float.END ]; // start & end disabled to make tests run faster
// Test switching the float type of an inline graphic element
var floatValue:String = floatValueList[floatTypeList.length - 1];
var secondParagraph:FlowElement = _textFlow.getChildAt(1);
var floatPosition:int = secondParagraph.getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, 30, 30, floatValue);
_textFlow.flowComposer.updateAllControllers();
var inlineGraphicElement:InlineGraphicElement = _textFlow.findLeaf(floatPosition) as InlineGraphicElement;
SelManager.selectRange(floatPosition, floatPosition + 1);
for each (floatValue in floatValueList)
SelManager.modifyInlineGraphic(inlineGraphicElement.source, inlineGraphicElement.width, inlineGraphicElement.height, floatValue);
}
public function verticalAlignInline():void
// Make sure that vertical alignment (especially justification) is working correctly with inlines. See 2772554
{
// TextFlow contains a single line of text with an inline, should be centered vertically
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
setUpFlow("Vertical align with inlines test");
// Check for middle
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.verticalAlign = VerticalAlign.MIDDLE;
_textFlow.format = textFlowFormat;
var floatObject:DisplayObject = addFloatAtPosition(0, 100, 100, Float.NONE);
_textFlow.flowComposer.updateAllControllers();
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var bounds:Rectangle = floatObject.getBounds(controller.container);
if (verticalText)
assertTrue("Expected float would be in the middle of the container", Math.abs((controller.compositionWidth + bounds.x) - Math.abs(bounds.x + bounds.width)) < controller.compositionWidth * .1);
else
assertTrue("Expected float would be in the middle of the container", Math.abs((bounds.y + (bounds.height/2)) - (controller.compositionHeight / 2)) < controller.compositionHeight * .1);
// Check for bottom. Leave a little wiggle room in this test because the inline is on the baseline and not against the bottom
textFlowFormat.verticalAlign = VerticalAlign.BOTTOM;
_textFlow.format = textFlowFormat;
_textFlow.flowComposer.updateAllControllers();
bounds = floatObject.getBounds(controller.container);
if (verticalText)
assertTrue("Expected float would be in the bottom of the container", Math.abs(bounds.x + controller.compositionWidth) < 10);
else
assertTrue("Expected float would be in the bottom of the container", Math.abs(bounds.y + bounds.height - controller.compositionHeight) < 10);
// Check for justify -- this needs multiple lines. Set alignment to TOP, check position, reset to JUSTIFY, position should have changed.
setUpFlow("Vertical align with inlines test dlfkj sdlk jsdlfkj sdlkfj dslkfj sdlkfj dlskfj dslkfj lkdsfj ldksfj dlksfj dslkfj dlskjfdslkjf lsdkjf lsdkfj sdlkfj sdlkfj dslkfj dslkfj sdlkfj dslkf jdslkfj sdlkfj sdlkfj ldskfj ldksfj lsdkfjldskfj lsdkfjdslkfj");
textFlowFormat.verticalAlign = VerticalAlign.TOP;
_textFlow.format = textFlowFormat;
floatObject = addFloatAtPosition(0, 100, 100, Float.NONE);
_textFlow.flowComposer.updateAllControllers();
controller = _textFlow.flowComposer.getControllerAt(0);
var topBounds:Rectangle = floatObject.getBounds(controller.container);
textFlowFormat.verticalAlign = VerticalAlign.JUSTIFY;
_textFlow.format = textFlowFormat;
_textFlow.flowComposer.updateAllControllers();
bounds = floatObject.getBounds(controller.container);
assertTrue(!bounds.equals(topBounds), "Line should have been moved when vertical justification applied");
}
private function verticalAlignMiddle(content:String):void
{
// TextFlow contains a single line of text with a float, should be centered vertically
// Floats extends past the text
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
setUpFlow(content);
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.verticalAlign = VerticalAlign.MIDDLE;
_textFlow.format = textFlowFormat;
var floatObject:DisplayObject = addFloatAtPosition(0, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
if (verticalText)
assertTrue("Expected float would be in the middle of the container", Math.abs((controller.compositionWidth + floatHolder.x) - Math.abs(floatHolder.x + floatObject.width)) < controller.compositionWidth * .1);
else
assertTrue("Expected float would be in the middle of the container", Math.abs((floatHolder.y + (floatObject.height/2)) - (controller.compositionHeight / 2)) < controller.compositionHeight * .1);
}
public function verticalAlignMiddleFloatAtEnd():void
{
// TextFlow contains a single line of text with a float, should be centered vertically
// Floats extends past the text
verticalAlignMiddle("A");
}
public function verticalAlignMiddleTextAtEnd():void
{
// TextFlow contains a single line of text with a float, should be centered vertically
// Text extends past the float
verticalAlignMiddle("A\nBBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB ");
}
private function verticalAlignBottom(content:String):void
{
// TextFlow contains a single line of text with a float, should be on the bottom of the container
// Floats extends past the text
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
setUpFlow(content);
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.verticalAlign = VerticalAlign.BOTTOM;
_textFlow.format = textFlowFormat;
var floatObject:DisplayObject = addFloatAtPosition(0, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
if (verticalText)
assertTrue("Expected float would be in the bottom of the container", Math.abs(floatHolder.x + controller.compositionWidth) < 1);
else
assertTrue("Expected float would be in the bottom of the container", Math.abs(floatHolder.y + floatObject.height - controller.compositionHeight) < 1);
}
public function verticalAlignBottomFloat2636122():void
{
// test for bug 2636122 - very similar to verticalAlignBottom, but not quite
// BoundsChecker fails on this because it sets verticalAlign on controller, BoundsChecker checks whole flow
_disableBoundsCheck = true;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
setUpFlow("A");
_textFlow.flowComposer.updateAllControllers();
var floatObject:DisplayObject = addFloatAtPosition(1, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(controller.format);
textFlowFormat.verticalAlign = VerticalAlign.BOTTOM;
controller.format = textFlowFormat;
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
if (verticalText)
assertTrue("Expected float would be in the bottom of the container", Math.abs(floatHolder.x + controller.compositionWidth) < 1);
else
assertTrue("Expected float would be in the bottom of the container", Math.abs(floatHolder.y + floatObject.height - controller.compositionHeight) < 1);
var tfl:TextFlowLine = _textFlow.flowComposer.getLineAt(0);
if (verticalText)
assertTrue("Expected line would be in the bottom of the container", Math.abs((tfl.x + tfl.height) - (floatHolder.x + floatHolder.width)) < 1);
else
assertTrue("Expected line would be in the bottom of the container", Math.abs(tfl.y + floatObject.height - controller.compositionHeight) < 1);
}
public function verticalAlignBottomFloatAtEnd():void
{
// TextFlow contains a single line of text with a float, should be centered vertically
// Floats extends past the text
verticalAlignBottom("A");
}
public function verticalAlignBottomTextAtEnd():void
{
// TextFlow contains a single line of text with a float, should be centered vertically
// Text extends past the float
verticalAlignBottom("A\nBBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB BBB ");
}
private function getCompositionResults(verticalText:Boolean, flowComposer:IFlowComposer):Array
{
var linePos:Array = [];
var numLines:int = flowComposer.numLines;
for (var i:int = 0; i < numLines; ++i)
{
var line:TextFlowLine = flowComposer.getLineAt(i);
linePos.push(verticalText ? line.x : line.y);
}
return linePos;
}
private function assertCompositionMatches(oldLineArray:Array, newLineArray:Array):void
{
assertTrue("Expected same composition, found different line count", oldLineArray.length == newLineArray.length);
for (var i:int = 0; i < oldLineArray.length; ++i)
{
assertTrue("Expected same composition, found line " + i.toString() + "moved in logical vertical direction", oldLineArray[i] == newLineArray[i]);
}
}
public function noVJ():void
{
// We expect that verticalAlign = justify in the presence of floats is identical to verticalAlign = top (i.e.
// the verticalAlign is ignored.
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var flowComposer:IFlowComposer = _textFlow.flowComposer;
var line:TextFlowLine;
atLineMiddleInternal(1, 100, 100, Float.LEFT);
flowComposer.updateAllControllers();
var oldLinePos:Array = getCompositionResults(verticalText, flowComposer);
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.verticalAlign = VerticalAlign.JUSTIFY;
_textFlow.format = textFlowFormat;
flowComposer.updateAllControllers();
var newLinePos:Array = getCompositionResults(verticalText, flowComposer);
assertCompositionMatches(oldLinePos, newLinePos);
}
private function textAlignRight(pos:int):void
{
// Test that right-aligned floats do not overlap right aligned lines
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
var textFlowFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
textFlowFormat.textAlign = TextAlign.RIGHT;
_textFlow.format = textFlowFormat;
var floatObject:DisplayObject = addFloatAtPosition(pos, 100, 100, Float.RIGHT);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(pos);
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex + 1);
var textLine:TextLine
var bbox:Rectangle = textFlowLine.getBounds();
if (verticalText)
assertTrue("Expected float would not overlap text", floatHolder.y >= textFlowLine.y + bbox.width);
else
assertTrue("Expected float would not overlap text", Math.abs(floatHolder.x - (textFlowLine.x + bbox.width)) < 2);
}
public function textAlignRightAtStart():void
{
textAlignRight(0);
}
public function textAlignRightInMiddle():void
{
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(3);
textAlignRight(textFlowLine.absoluteStart + textFlowLine.textLength/2);
}
private const INDENT_AMOUNT:Number = 20;
public function leftIndent():void
{
// Test that floats in indented paragraphs are indented
// Try a left float with a start indent
var leaf:FlowLeafElement = _textFlow.getFirstLeaf();
var firstPara:ParagraphElement = leaf.getParagraph();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(firstPara.format);
if (firstPara.computedFormat.direction == Direction.LTR)
paragraphFormat.paragraphStartIndent = INDENT_AMOUNT;
else
paragraphFormat.paragraphEndIndent = INDENT_AMOUNT;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
firstPara.format = paragraphFormat;
var floatObject:DisplayObject = addFloatAtPosition(200, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
assertTrue("Expected float to be indented with paragraph", floatHolder.y == INDENT_AMOUNT);
else
assertTrue("Expected float to be indented with paragraph", floatHolder.x == INDENT_AMOUNT);
}
public function rightIndent():void
{
// Test that floats in indented paragraphs are indented
// Try a right float with a right indent
var leaf:FlowLeafElement = _textFlow.getFirstLeaf();
var firstPara:ParagraphElement = leaf.getParagraph();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(firstPara.format);
if (firstPara.computedFormat.direction == Direction.RTL)
paragraphFormat.paragraphStartIndent = INDENT_AMOUNT;
else
paragraphFormat.paragraphEndIndent = INDENT_AMOUNT;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
firstPara.format = paragraphFormat;
var floatObject:DisplayObject = addFloatAtPosition(200, 100, 100, Float.RIGHT);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
assertTrue("Expected float to be indented with paragraph", Math.abs((floatHolder.y + floatObject.height) - (controller.compositionHeight - INDENT_AMOUNT)) < 1);
else
assertTrue("Expected float to be indented with paragraph", Math.abs((floatHolder.x + floatObject.width) - (controller.compositionWidth - INDENT_AMOUNT)) < 1);
}
public function leftBigIndent():void
{
var indentAmount:Number = 200; // bigger than float width
// Add a float, and check that a paragraph with a big indent will wrap to the max of the indent & float
var leaf:FlowLeafElement = _textFlow.getLastLeaf();
var secondPara:ParagraphElement = leaf.getParagraph();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(secondPara.format);
if (secondPara.computedFormat.direction == Direction.LTR)
paragraphFormat.paragraphStartIndent = indentAmount;
else
paragraphFormat.paragraphEndIndent = indentAmount;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
secondPara.format = paragraphFormat;
var floatObject:DisplayObject = addFloatAtPosition(200, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(secondPara.getAbsoluteStart());
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var bbox:Rectangle = textFlowLine.getBounds();
if (secondPara.computedFormat.direction == Direction.LTR)
{
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
assertTrue("Expected line in second paragraph to have large indent", bbox.top == indentAmount);
else
assertTrue("Expected line in second paragraph to have large indent", bbox.left == indentAmount);
}
}
public function rightBigIndent():void
{
var indentAmount:Number = 200; // bigger than float width
// Add a float, and check that a paragraph with a big indent will wrap to the max of the indent & float
var leaf:FlowLeafElement = _textFlow.getLastLeaf();
var secondPara:ParagraphElement = leaf.getParagraph();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(secondPara.format);
if (secondPara.computedFormat.direction == Direction.LTR)
paragraphFormat.paragraphEndIndent = indentAmount;
else
paragraphFormat.paragraphStartIndent = indentAmount;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
secondPara.format = paragraphFormat;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var floatObject:DisplayObject = addFloatAtPosition(200, 100, 100, Float.RIGHT);
_textFlow.flowComposer.updateAllControllers();
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(secondPara.getAbsoluteStart());
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var bbox:Rectangle = textFlowLine.getBounds();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
assertTrue("Expected line in second paragraph to have large indent", Math.abs(bbox.bottom - (controller.compositionHeight - indentAmount)) < 1);
else
assertTrue("Expected line in second paragraph to have large indent", Math.abs(bbox.right - (controller.compositionWidth - indentAmount)) < 1);
}
public function clearNoPrecedingFloatAll():void
{
clearAll(clearNoPrecedingFloat, 0);
}
private function clearNoPrecedingFloat(clear:String, floatCount:int):void
{
var indentAmount:Number = 200;
var leaf:FlowLeafElement = _textFlow.getLastLeaf();
var secondPara:ParagraphElement = leaf.getParagraph();
_textFlow.flowComposer.updateAllControllers();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
var secondPara_x:int = secondPara.getAbsoluteStart();
else
var secondPara_y:int = secondPara.getAbsoluteStart();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(secondPara.format);
paragraphFormat.clearFloats = clear;
if (secondPara.computedFormat.direction == Direction.LTR)
paragraphFormat.paragraphEndIndent = indentAmount;
else
paragraphFormat.paragraphStartIndent = indentAmount;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
secondPara.format = paragraphFormat;
_textFlow.flowComposer.updateAllControllers();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
assertTrue("Second paragraph should not be impacted by clear", secondPara_x == secondPara.getAbsoluteStart());
else
assertTrue("Second paragraph should not be impacted by clear", secondPara_y == secondPara.getAbsoluteStart());
}
public function leftIndentWithTab():void
{
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
SelManager.selectAll();
SelManager.deleteText();
SelManager.insertText("\tThis is test");
_textFlow.flowComposer.updateAllControllers();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
var leaf:FlowLeafElement = _textFlow.getFirstLeaf();
var firstPara:ParagraphElement = leaf.getParagraph();
if (firstPara.computedFormat.direction == Direction.LTR)
paragraphFormat.paragraphStartIndent = INDENT_AMOUNT;
else
paragraphFormat.paragraphEndIndent = INDENT_AMOUNT;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
firstPara.format = paragraphFormat;
var floatObject:DisplayObject = addFloatAtPosition(0, 100, 100, Float.LEFT);
paragraphFormat.tabStops = "e318";
SelManager.applyParagraphFormat(paragraphFormat);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var paragraph:ParagraphElement = _textFlow.getFirstLeaf().getParagraph();
var posStart:int = paragraph.getAbsoluteStart();
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(posStart);
var tfl:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
if (verticalText)
assertTrue("Expected float to be indented with paragraph", floatHolder.x <= tfl.x);
else
assertTrue("Expected float to be indented with paragraph", floatHolder.y <= tfl.y);
}
public function rightIndentWithTab():void
{
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
SelManager.selectAll();
SelManager.deleteText();
SelManager.insertText("\tThis is test");
_textFlow.flowComposer.updateAllControllers();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(_textFlow.format);
var leaf:FlowLeafElement = _textFlow.getFirstLeaf();
var firstPara:ParagraphElement = leaf.getParagraph();
if (firstPara.computedFormat.direction == Direction.RTL)
paragraphFormat.paragraphStartIndent = INDENT_AMOUNT;
else
paragraphFormat.paragraphEndIndent = INDENT_AMOUNT;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
firstPara.format = paragraphFormat;
var floatObject:DisplayObject = addFloatAtPosition(5, 100, 100, Float.RIGHT);
paragraphFormat.tabStops = "e300";
SelManager.applyParagraphFormat(paragraphFormat);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var paragraph:ParagraphElement = _textFlow.getFirstLeaf().getParagraph();
var posStart:int = paragraph.getAbsoluteStart();
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(posStart);
var tfl:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
if (verticalText)
assertTrue("Expected float to be indented with paragraph", (floatHolder.y >= (tfl.y + tfl.textLength)));
else
assertTrue("Expected float to be indented with paragraph", (( tfl.x+ tfl.textLength )<= floatHolder.x ));
}
private function stackedLeftRightFloats(float:String):void
{
var width:Number = 100;
var height:Number = 100;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
SelManager.selectAll();
SelManager.deleteText();
SelManager.insertText("AAAAAAAAAAAAAAAAAAAAAA\n");
SelManager.insertText("BBBBBBBBBBBBBBBBBBBBBB\n");
_textFlow.flowComposer.updateAllControllers();
var tlf1:TextFlowLine = _textFlow.flowComposer.getLineAt(1);
var tlf2:TextFlowLine = _textFlow.flowComposer.getLineAt(2);
var pos1:int = tlf1.absoluteStart;
var floatObject1:DisplayObject = addFloatAtPosition(pos1, width, height, float);
var pos2:int = tlf2.absoluteStart;
var floatObject2:DisplayObject = addFloatAtPosition(pos2, width, height, float);
verifyFloatInLine(pos1, width, height, float, floatObject1);
verifyFloatInLine(pos2, width, height, float, floatObject2);
}
public function stackedLeftFloats():void
{
var float:String = "left";
stackedLeftRightFloats(float);
}
public function stackedRightFloats():void
{
var float:String = "right";
stackedLeftRightFloats(float);
}
private var clearArray:Array = [ ClearFloats.LEFT, ClearFloats.RIGHT, ClearFloats.BOTH, ClearFloats.START, ClearFloats.END ];
private function clearAll(method:Function, floatCount:int):void
{
for each (var content:String in contentLanguageList)
{
for each (var clearValue:String in clearArray)
{
setUpFlow(content);
method(clearValue, floatCount);
}
}
}
public function clearOneAll():void
{
clearAll(clearFloatTest, 1);
}
public function clearTwoAll():void
{
clearAll(clearFloatTest, 2);
}
private function clearFloatTest(clear:String, floatCount:int):void
{
var indentAmount:Number = 200; // bigger than float width
// Add a float, and check that a paragraph with a big indent will wrap to the max of the indent & float
var leaf:FlowLeafElement = _textFlow.getLastLeaf();
var secondPara:ParagraphElement = leaf.getParagraph();
var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(secondPara.format);
paragraphFormat.clearFloats = clear;
paragraphFormat.textAlign = TextAlign.JUSTIFY;
secondPara.format = paragraphFormat;
var floatAttr:String = (clear == ClearFloats.LEFT) || (clear == ClearFloats.START) ? Float.LEFT : Float.RIGHT;
if (_textFlow.computedFormat.direction == Direction.RTL)
{
if (clear == ClearFloats.START) floatAttr = Float.RIGHT;
if (clear == ClearFloats.END) floatAttr = Float.LEFT;
}
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var floatObject:DisplayObject = addFloatAtPosition(200, 100, 100, floatAttr);
if (floatCount == 2)
{
floatObject = addFloatAtPosition(200, 100, 100, floatAttr);
}
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = floatObject.parent;
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(secondPara.getAbsoluteStart());
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var bbox:Rectangle = textFlowLine.getBounds();
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
{
assertTrue("ClearFloat:" + clear + " - Second paragraph should be cleared past float " + floatCount, bbox.x + bbox.width < floatHolder.x);
}
else
{
assertTrue("ClearFloat:" + clear + " - Second paragraph should be cleared past float " + floatCount, bbox.top > floatHolder.y + floatObject.height);
}
}
public function paddingAndMarginsInternal(float:String, width:Number, height:Number, paddingLeft:Number, paddingTop:Number, paddingRight:Number, paddingBottom:Number):void
{
var verticalText:Boolean = (_textFlow.computedFormat.blockProgression == BlockProgression.RL);
var graphic:DisplayObject = addFloatAtPosition(0, width, height, float);
var ilgElement:InlineGraphicElement = _textFlow.findLeaf(0) as InlineGraphicElement;
var format:TextLayoutFormat = new TextLayoutFormat(ilgElement.format);
format.paddingLeft = paddingLeft;
format.paddingTop = paddingTop;
format.paddingRight = paddingRight;
format.paddingBottom = paddingBottom;
ilgElement.format = format;
format = new TextLayoutFormat(_textFlow.format);
format.textAlign = TextAlign.JUSTIFY;
_textFlow.format = format;
_flowComposer.updateAllControllers();
var floatHolder:DisplayObjectContainer = graphic.parent;
assertTrue("Expected to get inline inserted", ilgElement != null);
var tfl:TextFlowLine = _flowComposer.getLineAt(0);
assertTrue("Expected padding between container edge and float", Math.abs(paddingTop - floatHolder.y) <= 1);
if (verticalText)
{
assertTrue("Expected padding between float and text", Math.abs(floatHolder.y + graphic.height + paddingBottom - tfl.y) <= 1);
assertTrue("Expected padding between container edge and float", Math.abs(paddingRight + (floatHolder.x + graphic.width)) <= 1);
}
else
{
assertTrue("Expected padding between float and text", Math.abs(floatHolder.x + graphic.width + paddingRight - tfl.x) <= 1);
assertTrue("Expected padding between container edge and float", Math.abs(paddingLeft - floatHolder.x) <= 1);
}
}
public function negativePaddingAndMargins():void
{
_disableBoundsCheck = true;
paddingAndMarginsInternal(Float.LEFT, 100, 100, -5, -10, -8, -12);
}
public function paddingAndMargins():void
{
paddingAndMarginsInternal(Float.LEFT, 100, 100, 20, 30, 40, 50);
}
public function lineHeightIgnoredOnFloatingImages():void
{
// LineHeight is supposed to be ignored on floating images when calculating line positions. Check that this is so.
// Insert a float at the start of the paragraph, and set lineheight on it.
var secondParagraph:ParagraphElement = _textFlow.getChildAt(1) as ParagraphElement;
var floatPosition:int = secondParagraph.getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, 10, 10, Float.START);
verifyFloatInLine(floatPosition, 10, 10, Float.START, floatObject);
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(floatPosition + 1);
var textFlowLine:TextFlowLine =_textFlow.flowComposer.getLineAt(lineIndex);
var verticalText:Boolean = (_textFlow.computedFormat.blockProgression == BlockProgression.RL);
var originalPosition:Number = verticalText ? textFlowLine.x : textFlowLine.y;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var originalContentBounds:Rectangle = new Rectangle(controller.contentLeft, controller.contentTop, controller.contentWidth, controller.contentHeight);
var format:TextLayoutFormat = new TextLayoutFormat();
format.lineHeight = 100;
SelManager.selectRange(floatPosition, floatPosition + 1);
SelManager.applyLeafFormat(format);
lineIndex = _textFlow.flowComposer.findLineIndexAtPosition(floatPosition + 1);
textFlowLine =_textFlow.flowComposer.getLineAt(lineIndex);
assertTrue("TextLine moved when lineHeight applied to floating graphic", originalPosition == (verticalText ? textFlowLine.x : textFlowLine.y));
var contentBounds:Rectangle = new Rectangle(controller.contentLeft, controller.contentTop, controller.contentWidth, controller.contentHeight);
assertTrue("Content bounds changed when lineHeight applied to floating graphic", contentBounds.equals(originalContentBounds));
}
private function setUpContainers(containerCount:int):void
{
testApp.changeContainerSetup("arrangeSideBySide", 0, containerCount);
}
public function smallFloatBigText():void
{
// Test case where there is a small initial (leading) float that fits in the container, and a larger line of text that
// gets pushed to the following container. Both the float and the line should get pushed to the following container.
try {
setUpContainers(2);
format = new TextLayoutFormat();
format.fontSize = 14;
format.paragraphSpaceAfter = 15;
format.fontFamily = "Times New Roman";
SelManager.applyFormatToElement(_textFlow, format);
_textFlow.flowComposer.updateAllControllers();
var secondControllerStart:int = _textFlow.flowComposer.getControllerAt(1).absoluteStart;
var floatObject:DisplayObject = addFloatAtPosition(secondControllerStart - 10, 10, 10, _textFlow.computedFormat.direction == Direction.RTL ? Float.RIGHT : Float.LEFT);
_textFlow.interactionManager.selectRange(secondControllerStart - 9 , secondControllerStart - 8);
var format:TextLayoutFormat = new TextLayoutFormat();
format.fontSize = 36;
SelManager.applyLeafFormat(format);
// Float should appear in the top of the second container
var secondController:ContainerController = _textFlow.flowComposer.getControllerAt(1);
var verticalText:Boolean = _textFlow.computedFormat.blockProgression == BlockProgression.RL;
assertTrue("Float should appear in the second container", secondController.container.contains(floatObject));
var inlineHolder:DisplayObject = floatObject.parent;
assertTrue("Float should appear at the top of the container", verticalText ? (inlineHolder.x == -inlineHolder.width) : (inlineHolder.y == 0));
}
finally {
//setUpContainers(1);
}
}
public function cursorByAnchor():void
{
// Blinking text cursor should be placed by the anchor point and sized to the line
// NOT put next to the float and sized to the float -- see bug 2609350
var secondParagraph:ParagraphElement = _textFlow.getChildAt(1) as ParagraphElement;
var floatPosition:int = secondParagraph.getAbsoluteStart();
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, 30, 30, Float.START);
// Turn on the blinking cursor
_textFlow.interactionManager.focusedSelectionFormat = new SelectionFormat(0xffffff, 1.0, "difference", 0xffffff, 1.0, "difference", 500);
_textFlow.interactionManager.selectRange(floatPosition, floatPosition);
_textFlow.flowComposer.updateAllControllers();
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var selectionSprite:DisplayObjectContainer = controller.getSelectionSprite(false);
assertTrue("Expected there to be a blinking cursor selection drawn", selectionSprite != null);
var cursorBounds:Rectangle = selectionSprite.getBounds(controller.container);
var lineIndex:int = _textFlow.flowComposer.findLineIndexAtPosition(floatPosition);
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(lineIndex);
var textLine:TextLine = textFlowLine.getTextLine();
var atomIndex:int = textLine.getAtomIndexAtCharIndex(floatPosition - secondParagraph.getAbsoluteStart());
var atomBounds:Rectangle = textLine.getAtomBounds(atomIndex);
var atomTopLeft:Point = textLine.localToGlobal(atomBounds.topLeft);
var atomBottomRight:Point = textLine.localToGlobal(atomBounds.bottomRight);
atomTopLeft = selectionSprite.parent.globalToLocal(atomTopLeft);
atomBottomRight = selectionSprite.parent.globalToLocal(atomBottomRight);
atomBounds.topLeft = atomTopLeft;
atomBounds.bottomRight = atomBottomRight;
var verticalText:Boolean = _textFlow.computedFormat.blockProgression == BlockProgression.RL;
if (verticalText)
{
assertTrue("Expected logical left edge of cursor to align with anchor's atom bounds left", Math.abs(cursorBounds.top - atomBounds.top) < 1);
assertTrue("Expected logical height of cursor to align with anchor's atom height", Math.abs(cursorBounds.width - textFlowLine.height) < 1);
}
else
{
assertTrue("Expected left edge of cursor to align with anchor's atom bounds left", Math.abs(cursorBounds.left - atomBounds.left) < 1);
assertTrue("Expected height of cursor to align with anchor's atom height", Math.abs(cursorBounds.height - textFlowLine.height) < 1);
}
}
public function insertTextBeforeFloat():void
{
// Test for unreported bug that is caused by retrying lines in composition (backing up to retry floats) and reusing TextLines.
// Bug is now fixed, this tests the fix.
// Insert a float about 2/3 way along the second line
_textFlow.flowComposer.updateAllControllers();
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(1);
var floatPosition:int = textFlowLine.absoluteStart + ((textFlowLine.textLength * 2) / 3);
var floatObject:DisplayObject = addFloatAtPosition(floatPosition, 100, 100, Float.RIGHT);
// Start editing in the previous line, about half way along
textFlowLine = _textFlow.flowComposer.getLineAt(0);
var editPosition:int = textFlowLine.absoluteStart + (textFlowLine.textLength / 2);
SelManager.selectRange(editPosition, editPosition);
SelManager.allowDelayedOperations = false;
for (var i:int = 0; i < 100; ++i)
{
SelManager.insertText("x");
SelManager.insertText(" ");
}
}
public function textIndentAfterFloat():void
{
var textIndentValue:int = 50;
var leaf:FlowLeafElement = _textFlow.getFirstLeaf();
var firstPara:ParagraphElement = leaf.getParagraph();
var format:TextLayoutFormat = new TextLayoutFormat(firstPara.format);
format.textIndent = textIndentValue;
firstPara.format = format;
var floatObject:DisplayObject = addFloatAtPosition(0, 100, 100, Float.START);
_textFlow.flowComposer.updateAllControllers();
var textFlowLine:TextFlowLine = _textFlow.flowComposer.getLineAt(0);
var textLine:TextLine = textFlowLine.getTextLine();
var verticalText:Boolean = _textFlow.computedFormat.blockProgression == BlockProgression.RL;
if (!verticalText)
{
if (firstPara.computedFormat.direction == Direction.LTR)
assertTrue("There should be 50 pixel indent between float and text", Math.abs(floatObject.parent.x + floatObject.width + textIndentValue - textLine.x) < 1);
else
assertTrue("There should be 50 pixel indent between float and text", Math.abs(floatObject.parent.x - textIndentValue - (textFlowLine.x + textLine.textWidth)) < 1);
}
else
assertTrue("There should be 50 pixel indent between float and text", Math.abs(floatObject.parent.y + floatObject.height + textIndentValue - textLine.y) < 1);
// Check that we still get the indent even if the text is pushed to the next line
_textFlow.interactionManager.selectRange(0, 1);
EditManager(_textFlow.interactionManager).deleteText();
floatObject = addFloatAtPosition(0, 400, 400, Float.START);
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
if (!verticalText)
controller.setCompositionSize(428, controller.compositionHeight);
else
controller.setCompositionSize(controller.compositionWidth, 434);
_textFlow.flowComposer.updateAllControllers();
textFlowLine = _textFlow.flowComposer.getLineAt(0);
textLine = textFlowLine.getTextLine();
if (!verticalText)
{
if (firstPara.computedFormat.direction == Direction.LTR)
assertTrue("There should be 50 pixel indent before 1st line of text", Math.abs(textIndentValue - textLine.x) < 1);
else
assertTrue("There should be 50 pixel indent before 1st line of text", Math.abs(controller.compositionWidth - textIndentValue - (textFlowLine.x + textLine.textWidth)) < 1);
}
else
assertTrue("There should be 50 pixel indent before 1st line of text", Math.abs(textIndentValue - textLine.y) < 1);
}
public function resizeControllerWithFloats():void
{
// Repeatedly recompose the text to different bounds
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var maxWidth:Number = controller.compositionWidth;
var maxHeight:Number = controller.compositionHeight;
var iterations:int = 200;
// Add a bunch of floats to the text
addFloatAtPosition(0, 100, 100, Float.LEFT);
addFloatAtPosition(30, 30, 60, Float.RIGHT);
addFloatAtPosition(45, 90, 40, Float.RIGHT);
addFloatAtPosition(80, 50, 50, Float.LEFT);
addFloatAtPosition(300, 100, 100, Float.LEFT);
addFloatAtPosition(400, 80, 4, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var newWidth:Number = maxWidth;
var newHeight:Number = maxHeight;
var deltaWidth:Number = maxWidth / iterations;
var deltaHeight:Number = maxHeight / iterations;
for (var i:int = 0; i < iterations; ++i)
{
newWidth -= deltaWidth;
newHeight -= deltaHeight;
controller.setCompositionSize(newWidth, newHeight);
_textFlow.flowComposer.updateAllControllers();
}
}
public function composeAcrossControllers():void // 2661626
{
_textFlow.interactionManager.selectAll();
_editManager.deleteText();
_editManager.insertText("kldslkfjdlkfjsdlkfjsdlkfjsldkfj");
_editManager.flushPendingOperations();
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var verticalText:Boolean = _textFlow.computedFormat.blockProgression == BlockProgression.RL;
if (verticalText)
{
addFloatAtPosition(0, 100, 100, Float.LEFT);
controller.setCompositionSize(97, 491);
}
else
{
addFloatAtPosition(0, 400, 400, Float.LEFT);
controller.setCompositionSize(855, 396);
}
var format:TextLayoutFormat = new TextLayoutFormat(controller.format);
format.columnCount = 2;
controller.format = format;
_textFlow.flowComposer.updateAllControllers();
// Expect to get float with one line in second column, containing only the anchor
// Second line is overset
var firstLine:TextFlowLine = _textFlow.flowComposer.getLineAt(0);
assertTrue(firstLine.textLength == 1 && firstLine.columnIndex == 1, "Expected float in second column in a line by itself");
/* for (var i:int = 0; i < _textFlow.flowComposer.numLines; ++i)
{
var line:TextFlowLine = _textFlow.flowComposer.getLineAt(i);
trace("Line from ", line.absoluteStart, "length", line.textLength, "x", line.x, "y", line.y, "column", line.columnIndex);
}
assertTrue("Expected two lines", _textFlow.flowComposer.numLines > 1); */
// Do it again, but this time make the float wide enough that it overflows the column bounds
if (!verticalText)
controller.setCompositionSize(773, 426);
else
controller.setCompositionSize(155, 97);
/*for (var i:int = 0; i < _textFlow.flowComposer.numLines; ++i)
{
var line:TextFlowLine = _textFlow.flowComposer.getLineAt(i);
trace("Line from ", line.absoluteStart, "length", line.textLength, "x", line.x, "y", line.y, "column", line.columnIndex);
} */
if (verticalText)
_disableBoundsCheck = true;
}
private function findFloat(textFlow:TextFlow):InlineGraphicElement
{
var ilg:InlineGraphicElement = null;
var leaf:FlowLeafElement = textFlow.getFirstLeaf();
while (leaf && leaf != textFlow.getLastLeaf())
{
if (leaf is InlineGraphicElement)
ilg = leaf as InlineGraphicElement;
leaf = leaf.getNextLeaf();
}
return ilg;
}
public function htmlImportTest():void
{
var htmlString:String = "<HTML><BODY><p>Example paragraph, with a img aligned left<img align='left' src='http://mozcom-cdn.mozilla.net/img/tignish/template/mozilla-logo.png'>more text</p></BODY></HTML>";
var textFlow:TextFlow = TextConverter.importToFlow(htmlString, TextConverter.TEXT_FIELD_HTML_FORMAT);
var ilg:InlineGraphicElement = findFloat(textFlow);
assertTrue(ilg != null, "Expected to find InlineGraphicElement from <img> import");
assertTrue(ilg.float != Float.LEFT, "align=left <img> import, expected float=left");
htmlString = "<HTML><BODY><p>Example paragraph, with a img aligned left<img align='right' src='http://mozcom-cdn.mozilla.net/img/tignish/template/mozilla-logo.png'>more text</p></BODY></HTML>";
textFlow = TextConverter.importToFlow(htmlString, TextConverter.TEXT_FIELD_HTML_FORMAT);
ilg = findFloat(textFlow);
assertTrue(ilg != null, "Expected to find InlineGraphicElement from <img> import");
assertTrue(ilg.float != Float.RIGHT, "align=right <img> import, expected float=right");
htmlString = "<HTML><BODY><p>Example paragraph, with a img aligned left<img align='foo' src='http://mozcom-cdn.mozilla.net/img/tignish/template/mozilla-logo.png'>more text</p></BODY></HTML>";
textFlow = TextConverter.importToFlow(htmlString, TextConverter.TEXT_FIELD_HTML_FORMAT);
ilg = findFloat(textFlow);
assertTrue(ilg != null, "Expected to find InlineGraphicElement from <img> import");
assertTrue(ilg.float != Float.NONE, "align=foo (invalid value) <img> import, expected float=none");
}
public function deleteAtStart():void
{
var firstFloat:DisplayObject = addFloatAtPosition(0, 100, 100, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
var secondFloat:DisplayObject = addFloatAtPosition(795, 100, 50, Float.LEFT);
_textFlow.flowComposer.updateAllControllers();
SelManager.deleteText(new SelectionState(_textFlow, 0, 1));
// Check to make sure the first float is still in the display list
assertTrue("First float was deleted and should not still be visible", !isInDisplayList(TestDisplayObject as DisplayObjectContainer, firstFloat));
// Check to make sure the second float is still in the display list
assertTrue("Second float was not deleted and should still be visible", isInDisplayList(TestDisplayObject as DisplayObjectContainer, secondFloat));
_disableBoundsCheck = true;
}
private function isInDisplayList(container: DisplayObjectContainer, objectToFind:DisplayObject):Boolean
{
var child:DisplayObject;
if (container == objectToFind)
return true;
for (var i:int = container.numChildren - 1; i >= 0; i--)
{
child = container.getChildAt(i);
if (child == objectToFind)
return true;
if ((child is DisplayObjectContainer) && isInDisplayList(child as DisplayObjectContainer, objectToFind))
return true;
}
if (container is Container)
{
var uiComponent:Container = container as Container;
for (i = uiComponent.rawChildren.numChildren - 1; i >= 0; i--)
{
child = uiComponent.rawChildren.getChildAt(i);
if (child == objectToFind)
return true;
if ((child is DisplayObjectContainer) && isInDisplayList(child as DisplayObjectContainer, objectToFind))
return true;
}
}
return false; // not found
}
public function overFlowAtStart():void // 2661625
{
addFloatAtPosition(0, 400, 400, Float.LEFT);
_textFlow.fontFamily = "Times New Roman";
_textFlow.textIndent = 15;
_textFlow.fontSize = 14;
_textFlow.paragraphSpaceAfter = 15;
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
controller.setCompositionSize(controller.compositionWidth, 404);
controller.columnCount = 2;
_textFlow.flowComposer.updateAllControllers();
controller.verticalScrollPosition = 300;
_textFlow.flowComposer.updateAllControllers();
var bounds:Rectangle = controller.getContentBounds();
assertTrue("Content bounds should include float at top", bounds.top < _textFlow.flowComposer.getLineAt(0).y);
_disableBoundsCheck = true;
// Check for a different bug -- text disappears
controller.setCompositionSize(controller.compositionWidth, 424);
_textFlow.flowComposer.updateAllControllers();
controller.setCompositionSize(controller.compositionWidth, 200);
_textFlow.flowComposer.updateAllControllers();
assertTrue("We should be seeing something!", controller.container.numChildren > 0);
}
public function measureWidth():void
{
// When we're measuring, floats come out as inlines
var floatObject:DisplayObject = addFloatAtPosition(0, 10, 10, Float.LEFT);
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
if (_textFlow.computedFormat.blockProgression == BlockProgression.RL)
controller.setCompositionSize(500, NaN);
else
controller.setCompositionSize(NaN, 500);
_textFlow.flowComposer.updateAllControllers();
var floatHolder:DisplayObject = floatObject.parent;
assertTrue("Float should be treated as inline when measuring in the logical width direction", floatHolder.parent is TextLine);
_disableBoundsCheck = true;
}
//watson 2644509
public function inlineWideAndFloat():void
{
var width:Number = 100;
var height:Number = 100;
var float:String = "left";
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
SelManager.selectAll();
SelManager.deleteText();
SelManager.insertText("A" + "\n");
_textFlow.flowComposer.updateAllControllers();
var tlf1:TextFlowLine = _textFlow.flowComposer.getLineAt(0);
var pos1:int = tlf1.absoluteStart;
var floatObject:DisplayObject = addFloatAtPosition(pos1, width, height, float);
//to make controller as wide as float
if (!verticalText)
controller.setCompositionSize(100, controller.compositionHeight);
else
controller.setCompositionSize(controller.compositionWidth, 100);
_textFlow.flowComposer.updateAllControllers();
verifyFloatInLine(pos1, width, height, float, floatObject);
var numlines:int = _textFlow.flowComposer.numLines;
assertTrue ("incorrect TextLine number", numlines==2);
//update the first TextFlowLine
tlf1 = _textFlow.flowComposer.getLineAt(0);
//get the TextLine with the Text "A"
var tlf2:TextFlowLine = _textFlow.flowComposer.getLineAt(1);
var tl2:TextLine = tlf2.getTextLine();
//verify there is no overlap for float and the text, make sure float is at the previous line
assertTrue ("float at wrong position.", tl2.previousLine.hasGraphicElement == true);
//verify second line with "A" is under the float
if (!verticalText)
assertTrue ("TextLine with text 'A' should be below float TextLine ", tlf1.y < tlf2.y);
else
assertTrue ("TextLine with text 'A' should be at left of float TextLine ", tlf1.x > tlf2.x);
_disableBoundsCheck = true;
}
//watson 2617914: RTE composing many floats in narrow columns
public function narrowColumnFloat():void
{
try {
var width:Number = 100;
var height:Number = 100;
var float:String = "right";
//set up multiple columns to make the display narrow
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
controller.columnCount = 3;
var verticalText:Boolean = _textFlow.blockProgression == BlockProgression.RL;
_textFlow.flowComposer.updateAllControllers();
//to add 10 floats to the first 10 text flow lines
var tlf:TextFlowLine;
var pos:int;
tlf = _textFlow.flowComposer.getLineAt(1);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(2);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(3);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(4);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(5);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(6);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(7);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(8);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(9);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
tlf = _textFlow.flowComposer.getLineAt(10);
pos = tlf.absoluteStart;
addFloatAtPosition(pos + 10, width, height, float);
//to reduce the container size to recomposie, make sure display correctly without RTE
controller.setCompositionSize(controller.compositionWidth -20, controller.compositionHeight -20);
_textFlow.flowComposer.updateAllControllers();
//to reduce the container size again to recomposie, make sure display correctly without RTE
controller.setCompositionSize(controller.compositionWidth -20, controller.compositionHeight -20);
_textFlow.flowComposer.updateAllControllers();
//to reduce the container size again to recomposie, make sure display correctly without RTE
controller.setCompositionSize(controller.compositionWidth -20, controller.compositionHeight -20);
_textFlow.flowComposer.updateAllControllers();
_disableBoundsCheck = true;
}
catch (e:Error)
{
assertTrue ("RTE occurs", !e);
}
}
public function caretOnEmptyInlineGraphic():void // Bug 2719488
{
var markup:String = '<TextFlow whiteSpaceCollapse="preserve" xmlns="http://ns.adobe.com/textLayout/2008"><p textAlign="center" textIndent="0"><span fontSize="24">Amid Blight and Scanenging, Old G.M. Plants Linger</span></p><p textAlign="center" textIndent="0"><span></span></p><p textIndent="0"><img height="auto" width="auto" source="Auto-articleLarge.jpg" float="start"/><span>FLINT, Mich. — By day, hundreds of </span><a href="http://topics.nytimes.com/top/news/business/companies/general_motors_corporation/index.html?inline=nyt-org"><span>General Motors</span></a><span> work­ers make pis­tons and other en­gine parts at a fac­tory on this city’s east side. </span></p></TextFlow>';
_textFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT);
_flowComposer = _textFlow.flowComposer;
_textFlow.interactionManager = new EditManager();
var flintPara:ParagraphElement = _textFlow.getChildAt(2) as ParagraphElement;
var pos:int = flintPara.getAbsoluteStart() + 1;
VellumTestCase.testApp.contentChange (_textFlow);
TestDisplayObject = VellumTestCase.testApp.getDisplayObject();
TestFrame = _textFlow.flowComposer.getControllerAt(0);
_textFlow.flowComposer.updateAllControllers();
_textFlow.interactionManager.selectRange(pos, pos);
_textFlow.interactionManager.setFocus();
var charCode:int = 0;
var keyCode:int = 37; // left arrow key
var shiftDown:Boolean = true;
var selState:SelectionState = _textFlow.interactionManager.getSelectionState();
var keyEvent:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN,
true, false, charCode, keyCode, KeyLocation.STANDARD, false, false, shiftDown);
TestFrame.container["dispatchEvent"](keyEvent);
_disableBoundsCheck = true; // for debugging test
}
public function restartComposeFromStart():void // 2730934
{
var pos:int = 81;
var markup:String = '<TextFlow blockProgression="tb" direction="ltr" whiteSpaceCollapse="preserve" version="2.0.0" xmlns="http://ns.adobe.com/textLayout/2008"><p blockProgression="rl" columnCount="inherit" columnGap="inherit" columnWidth="inherit" direction="ltr" textAlign="justify" verticalAlign="inherit"><img height="100" width="100" source="../../test/testFiles/assets/smiling.png" float="left"/><span backgroundColor="#33ff00">This is Markup float left test</span></p><p blockProgression="rl" columnCount="inherit" columnGap="inherit" columnWidth="inherit" direction="ltr" textAlign="justify" verticalAlign="inherit"><img height="100" width="100" source="../../test/testFiles/assets/smiling.png" float="right"/><span>This is Markup float right test</span></p><p blockProgression="rl" columnCount="inherit" columnGap="inherit" columnWidth="inherit" direction="ltr" textAlign="justify" verticalAlign="inherit"><img height="100" width="100" source="../../test/testFiles/assets/smiling.png" float="none"/><span>This is Markup float none test</span></p></TextFlow>';
_textFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT);
VellumTestCase.testApp.contentChange (_textFlow);
TestDisplayObject = VellumTestCase.testApp.getDisplayObject();
TestFrame = _textFlow.flowComposer.getControllerAt(0);
TestFrame.setCompositionSize(NaN, TestFrame.compositionHeight); // we're measuring
var editManager:IEditManager = _textFlow.interactionManager as IEditManager;
editManager.selectRange(pos, pos + 1);
var leafFormat:TextLayoutFormat = new TextLayoutFormat();
leafFormat.color = 0xFF0000;
editManager.applyLeafFormat(leafFormat); // force the span creation here
_textFlow.flowComposer.updateAllControllers();
var resultsBefore:Array = CompositionResults.getContainerResults(TestFrame.container); // Save off TextLine positions
_textFlow.flowComposer.updateAllControllers();
leafFormat = new TextLayoutFormat();
leafFormat.color = 0xFF00; // only change the color here
var leaf:FlowLeafElement = _textFlow.findLeaf(pos);
leaf.format = leafFormat;
_textFlow.flowComposer.updateAllControllers();
var resultsAfter:Array = CompositionResults.getContainerResults(TestFrame.container); // Save off TextLine positions
assertTrue("Expected TextLines not to change", CompositionResults.compareResults(resultsBefore, resultsAfter));
}
public function convertInlineToFloat():void
{
var inline:DisplayObject = addFloatAtPosition(954, 100, 100, Float.NONE);
_textFlow.flowComposer.updateAllControllers();
assertTrue("Inline should appear as descendent of container", TestFrame.container.contains(inline));
assertTrue("Inline should appear as descendent of container", inline.parent.parent is TextLine);
var inlineGraphicElement:InlineGraphicElement = _textFlow.findLeaf(954) as InlineGraphicElement;
inlineGraphicElement.float = Float.LEFT;
_textFlow.flowComposer.updateAllControllers();
assertTrue("Inline should appear as descendent of container", TestFrame.container.contains(inline));
assertTrue("Inline should appear as child of container", inline.parent.parent == TestFrame.container);
}
public function infiniteLoop2769562():void
{
// Start with empty flow. Add a float left, a float right, and some text with long words following.
SelManager.allowDelayedOperations = false; // execute inserts immediately
SelManager.deleteText(new SelectionState(_textFlow, 0, _textFlow.textLength));
addFloatAtPosition(0, 100, 100, Float.LEFT);
addFloatAtPosition(1, 100, 100, Float.RIGHT);
SelManager.selectRange(_textFlow.textLength - 1, _textFlow.textLength - 1);
SelManager.insertText("thisisalongword hereis some more text just typing on for a bit then it will be long enough.");
var controller:ContainerController = _textFlow.flowComposer.getControllerAt(0);
var originalWidth:Number = controller.compositionWidth;
controller.setCompositionSize(220, controller.compositionHeight);
_textFlow.flowComposer.updateAllControllers();
SelManager.selectRange(0, 0);
SelManager.splitParagraph();
// bug caused infinite loop here
controller.setCompositionSize(220, controller.compositionHeight);
}
private static var pasteCount:int = 12;
private static var waitingImageCount:int = 0;
private function imageIsReady(event:StatusChangeEvent):void
{
if (event.status == InlineGraphicElementStatus.READY)
--waitingImageCount;
}
public function pasteManyFloatsWithLoading(callback:Object = null):void
{
if(!callback)
{
callback = true;
pasteCount = 12;
TestFrame.container.addEventListener(Event.ENTER_FRAME,addAsync(pasteManyFloatsWithLoading,2500,null),false,0,true);
SelManager.textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE, imageIsReady);
// Delete current text
SelManager.selectRange(0, int.MAX_VALUE);
SelManager.deleteText();
var baseImageURL:String = LoaderUtil.createAbsoluteURL(baseURL, "../../test/testFiles/assets/");
var src:String = "gremlin.jpg"; // image to use
var width:int = 20;
var height:int = 20;
SelManager.selectRange(0, 0);
var inlineGraphicElement1:InlineGraphicElement = SelManager.insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseImageURL,src),FormatValue.AUTO,FormatValue.AUTO, Float.LEFT);
var inlineGraphicElement2:InlineGraphicElement = SelManager.insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseImageURL,src),FormatValue.AUTO,FormatValue.AUTO, Float.LEFT);
var inlineGraphicElement3:InlineGraphicElement = SelManager.insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseImageURL,src),FormatValue.AUTO,FormatValue.AUTO, Float.LEFT);
var inlineGraphicElement4:InlineGraphicElement = SelManager.insertInlineGraphic(LoaderUtil.createAbsoluteURL(baseImageURL,src),FormatValue.AUTO,FormatValue.AUTO, Float.LEFT);
SelManager.insertText("abcdef ghijklmopqr stuvwxyz");
SelManager.flushPendingOperations();
waitingImageCount = 4;
}
else // Make sure the images are ready before we let the snapshot go
{
if (waitingImageCount > 0)
{
SelManager.textFlow.addEventListener(Event.ENTER_FRAME,addAsync(pasteManyFloatsWithLoading,2500,null),false,0,true);
}
else
{
if (pasteCount > 0) // images have loaded -- redraw & do another paste
{
TestFrame.container.addEventListener(Event.ENTER_FRAME,addAsync(pasteManyFloatsWithLoading,2500,null),false,0,true);
SelManager.updateAllControllers();
var textScrap:TextScrap = TextScrap.createTextScrap(new TextRange(SelManager.textFlow, 0, 32));
var pos:int = SelManager.textFlow.textLength - 1;
SelManager.pasteTextScrap(textScrap, new SelectionState(SelManager.textFlow, pos, pos)); // paste to end of story
waitingImageCount += 4;
--pasteCount;
}
else // we're done!
SelManager.textFlow.removeEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE, imageIsReady);
SelManager.textFlow.flowComposer.updateAllControllers();
if (SelManager.textFlow.computedFormat.blockProgression == BlockProgression.RL)
_disableBoundsCheck = true;
}
}
}
public function contentBoundsWithFactoryComposition():void
{
_disableBoundsCheck = true;
VellumTestCase.testApp.contentChange (null);
var TestCanvas:Canvas;
TestDisplayObject = testApp.getDisplayObject();
if (TestDisplayObject)
{
TestCanvas = Canvas(TestDisplayObject);
}
var tf:TextFlow;
var lineDisplays:Array = new Array();
var lineCounter:Number = 0;
var textFlowFactory:TextFlowTextLineFactory = new TextFlowTextLineFactory();
var clearArributes:Array = ["left" , "right", "start", "end", "both", "none"];
var floatArributes:Array = ["left", "right", "start", "end", "none"];
var clearArribute:String;
var floatArribute:String;
var fs:Sprite;
var container:Sprite;
var span:SpanElement = new SpanElement();
var pic:InlineGraphicElement = new InlineGraphicElement();
var para1:ParagraphElement = new ParagraphElement();
var para2:ParagraphElement = new ParagraphElement();
var factoryFlow:TextFlow;
var format:TextLayoutFormat;
var controller:ContainerController;
para1.addChild( pic );
para2.addChild( span );
textFlowFactory.compositionBounds = new Rectangle( 0, 0, 300, 400 );
span.text = "The man who now watched the fire was of a different order, and troubled himself with no thoughts save the very few that were requisite to his business. At frequent intervals, he flung back the clashing weight of the iron door, and, turning his face from the insufferable glare, thrust in huge logs of oak, or stirred the immense brands with a long pole. Sentences removed. lime-kilns in that tract of country, for the purpose of burning the white marble which composes a large part of the substance of the hills. Some of them, built years ago, and long deserted, with weeds growing in the vacant round of the interior, which is open to the sky, and grass and wild-flowers rooting themselves into the chinks of the stones, look already like relics of antiquity, and may yet be overspread with the lichens of centuries to come. Sentences removed.";
[Embed (source="../../../../test/testFiles/assets/smiley.gif")]
var Smiley:Class;
pic.source = Smiley;
function callback(lineOrShape:DisplayObject):void
{
fs.addChild(lineOrShape);
lineDisplays[lineCounter] = lineOrShape;
lineCounter ++;
}
for each(floatArribute in floatArributes){
pic.float = floatArribute;
for each(clearArribute in clearArributes){
para2.clearFloats = clearArribute;
//sprite
if(fs != null){
fs.graphics.clear();
testApp.getDisplayObject().rawChildren.removeChild(fs);
}
fs = new Sprite();
//draw our bounds
fs.graphics.beginFill(0x555555,.5);
fs.graphics.drawRect( 0, 0, 300, 400);
fs.graphics.endFill();
//set text direction and block progression
if( format != null)
format = null;
format = new TextLayoutFormat();
format.direction = _textFlow.direction;
format.blockProgression = _textFlow.blockProgression;
//default text flow in vellum unit, used to get line number
tf = new TextFlow();
tf.flowComposer = new StandardFlowComposer();
tf.addChild(para1);
tf.addChild(para2);
if(container != null){
container.graphics.clear();
testApp.getDisplayObject().rawChildren.removeChild(container);
}
container = new Sprite();
if(controller != null)
controller = null;
var width:Number = 300;
var height:Number = 400;
controller = new ContainerController(container,300,400);
tf.hostFormat = format;
tf.flowComposer.addController(controller);
tf.interactionManager = new EditManager();
tf.flowComposer.updateAllControllers();
//text flow by factory composition
if(factoryFlow != null){
factoryFlow = null;
}
factoryFlow = new TextFlow();
factoryFlow.replaceChildren(0, factoryFlow.numChildren, [para1, para2]);
factoryFlow.replaceChildren(0, factoryFlow.numChildren, para1.deepCopy());
factoryFlow.replaceChildren(factoryFlow.numChildren, factoryFlow.numChildren, para2.deepCopy());
factoryFlow.flowComposer.updateAllControllers();
factoryFlow.hostFormat = format;
factoryFlow.flowComposer.updateAllControllers();
textFlowFactory.createTextLines(callback, factoryFlow);
//add sprite to vellum unit UI
container.x = 300;
container.y = 0;
container.width = 300;
container.height = 400;
TestCanvas.rawChildren.addChild(fs);
TestCanvas.rawChildren.addChild(container);
//check points
for(var i:int = 0; i<tf.flowComposer.numLines ;i++){
var textLine:TextFlowLine = tf.flowComposer.getLineAt(i);
var textLineBounds:Rectangle = textLine.getTextLine().getBounds(container);
var bbox:Rectangle = lineDisplays[i].getBounds(fs);
trace("Line "+i+"'s left : "+textLineBounds.left +" "+ bbox.left);
trace("Line "+i+"'s right : "+textLineBounds.right +" "+ bbox.right);
trace("Line "+i+"'s top : "+textLineBounds.top +" "+ bbox.top);
trace("Line "+i+"'s bottom : "+textLineBounds.bottom +" "+ bbox.bottom);
//The code below I cannot explain...but it is correct
if(_textFlow.blockProgression == BlockProgression.TB){
assertTrue("contentBounds left doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.left - bbox.left) < 0.1 );
assertTrue("contentBounds right doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.right - bbox.right) < 0.1 );
}else{
assertTrue("contentBounds left doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.left+300 - bbox.left) < 0.1 );
assertTrue("contentBounds right doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.right+300 - bbox.right) < 0.1 );
}
assertTrue("contentBounds top doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.top - bbox.top) < 0.1 );
assertTrue("contentBounds bottom doesn't match sprite inked bounds when {\"clear\" : \"" + clearArribute + "\" , \"float\" : \"" + floatArribute + "\"} at Line "+i+"/"+tf.flowComposer.numLines , Math.abs(textLineBounds.bottom - bbox.bottom) < 0.1 );
}
lineCounter = 0;
}
}
}
}
}