| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // This file contains content from Ethan Brand by Nathaniel Hawthorne, |
| // now in the public domain. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package UnitTest.Tests |
| { |
| import UnitTest.ExtendedClasses.TestConfigurationLoader; |
| import UnitTest.ExtendedClasses.VellumTestCase; |
| import UnitTest.Fixtures.TestCaseVo; |
| import UnitTest.Fixtures.TestConfig; |
| |
| import flash.display.DisplayObject; |
| import flash.display.Sprite; |
| import flash.events.*; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| import flash.system.*; |
| import flash.text.engine.*; |
| |
| import flashx.textLayout.compose.IFlowComposer; |
| import flashx.textLayout.compose.StandardFlowComposer; |
| import flashx.textLayout.compose.TextFlowLine; |
| import flashx.textLayout.container.ContainerController; |
| import flashx.textLayout.container.TextContainerManager; |
| import flashx.textLayout.conversion.TextConverter; |
| import flashx.textLayout.edit.EditManager; |
| import flashx.textLayout.edit.EditingMode; |
| import flashx.textLayout.edit.IEditManager; |
| import flashx.textLayout.edit.SelectionState; |
| import flashx.textLayout.elements.*; |
| import flashx.textLayout.formats.ITextLayoutFormat; |
| import flashx.textLayout.formats.TextLayoutFormat; |
| import flashx.textLayout.utils.NavigationUtil; |
| |
| import mx.containers.Canvas; |
| |
| import org.flexunit.asserts.assertTrue; |
| import org.flexunit.asserts.fail; |
| |
| [TestCase(order=11)] |
| [RunWith("org.flexunit.runners.Parameterized")] |
| public class ContainerTypeTest extends VellumTestCase |
| { |
| [DataPoints(loader=singleTextLineLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var singleTextLineDp:Array; |
| |
| public static var singleTextLineLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "singleTextLine"); |
| |
| [DataPoints(loader=tenTextLinesLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var tenTextLinesDp:Array; |
| |
| public static var tenTextLinesLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "tenTextLinesDp"); |
| |
| [DataPoints(loader=clickLinkedContainerTestLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var clickLinkedContainerTestDp:Array; |
| |
| public static var clickLinkedContainerTestLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "clickLinkedContainerTest"); |
| |
| [DataPoints(loader=checkContainerAttributesAfterTextInsertionLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var checkContainerAttributesAfterTextInsertionDp:Array; |
| |
| public static var checkContainerAttributesAfterTextInsertionLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "checkContainerAttributesAfterTextInsertion"); |
| |
| [DataPoints(loader=navigateByLineTestLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var navigateByLineTestDp:Array; |
| |
| public static var navigateByLineTestLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "navigateByLineTest"); |
| |
| [DataPoints(loader=tenTextLinesStaticLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var tenTextLinesStaticDp:Array; |
| |
| public static var tenTextLinesStaticLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "tenTextLinesStatic"); |
| |
| [DataPoints(loader=singleTextLineStaticLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var singleTextLineStaticDp:Array; |
| |
| public static var singleTextLineStaticLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "singleTextLineStatic"); |
| |
| [DataPoints(loader=clickMultiLinkedContainerTestLoader)] |
| [ArrayElementType("UnitTest.Fixtures.TestCaseVo")] |
| public static var clickMultiLinkedContainerTestDp:Array; |
| |
| public static var clickMultiLinkedContainerTestLoader:TestConfigurationLoader = new TestConfigurationLoader("../../test/testCases/ContainerTypeTests.xml", "clickMultiLinkedContainerTest"); |
| |
| private var TestCanvas:Canvas = null; |
| private var ItemsToRemove:Array; |
| private var hostFormat:TextLayoutFormat; |
| |
| private var markup:String; |
| |
| public function ContainerTypeTest() |
| { |
| super("", "ContainerTypeTest2", TestConfig.getInstance()); |
| //super(methodName, testID, testConfig, testCaseXML); |
| //reset containerType and ID |
| containerType = "custom"; |
| metaData = {}; |
| // Note: These must correspond to a Watson product area (case-sensitive) |
| metaData.productArea = "Text Container"; |
| markup = getTestMarkup(); |
| } |
| |
| [Before] |
| override public function setUpTest():void |
| { |
| cleanUpTestApp(); |
| ItemsToRemove = []; |
| TestDisplayObject = testApp.getDisplayObject(); |
| if (TestDisplayObject) |
| { |
| TestCanvas = Canvas(TestDisplayObject); |
| } |
| else |
| { |
| fail("Did not get a blank canvas to work with"); |
| } |
| } |
| |
| [After] |
| override public function tearDownTest():void |
| { |
| super.tearDownTest(); |
| } |
| |
| /** |
| * Have a single TextLine on the canvas instead of a vellum container |
| */ |
| [Test(dataProvider=singleTextLineDp)] |
| public function singleTextLine(testCaseVo:TestCaseVo):void |
| { |
| //TODO: Piotr: Not sure what is for bitmapSnapshot but will invastigate soon |
| //TestData.bitmapSnapshot = Boolean(testCaseVo.bitmapSnapshot); |
| |
| var cf:ElementFormat = new ElementFormat(); |
| cf.fontSize = 24; |
| var fd:FontDescription = new FontDescription("Times New Roman") |
| cf.fontDescription = fd; |
| var te:TextElement = new TextElement("A TextLine on the Canvas", cf); |
| var tb:TextBlock = new TextBlock(); |
| tb.content = te; |
| var tl1:TextLine = tb.createTextLine(null, 400); |
| tl1.x = 50; |
| tl1.y = 50; |
| //need to keep track of what I've added in order to remove at teardown? |
| TestCanvas.rawChildren.addChild(DisplayObject(tl1)); |
| ItemsToRemove.push(tl1); |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| /** |
| * Have ten TextLines on the canvas instead of a vellum container |
| */ |
| [Test(dataProvider=tenTextLinesDp)] |
| public function tenTextLines(testCaseVo:TestCaseVo):void |
| { |
| TestData.bitmapSnapshot = testCaseVo.bitmapSnapshot; |
| |
| for (var i:int = 0; i < 10; i++) |
| { |
| var cf:ElementFormat = new ElementFormat(); |
| cf.fontSize = 24; |
| var fd:FontDescription = new FontDescription("Times New Roman") |
| cf.fontDescription = fd |
| var te:TextElement = new TextElement("TextLine " + i, cf); |
| var tb:TextBlock = new TextBlock(); |
| tb.content = te; |
| var tl1:TextLine = tb.createTextLine(null, 400); |
| tl1.x = 40; |
| tl1.y = 40 + (40 * i); |
| //need to keep track of what I've added in order to remove at teardown? |
| TestCanvas.rawChildren.addChild(DisplayObject(tl1)); |
| ItemsToRemove.push(tl1); |
| } |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| /** |
| * Have one hundred TextLines on the canvas instead of a vellum container |
| */ |
| [Test] |
| public function oneHundredTextLines():void |
| { |
| for (var i:int = 0; i < 100; i++) |
| { |
| var cf:ElementFormat = new ElementFormat(); |
| cf.fontSize = 2.4; |
| var fd:FontDescription = new FontDescription("Times New Roman"); |
| cf.fontDescription = fd; |
| var te:TextElement = new TextElement("TextLine " + i, cf); |
| var tb:TextBlock = new TextBlock(); |
| tb.content = te; |
| var tl1:TextLine = tb.createTextLine(null, 400); |
| tl1.x = 40; |
| tl1.y = 40 + (4 * i); |
| //need to keep track of what I've added in order to remove at teardown? |
| TestCanvas.rawChildren.addChild(DisplayObject(tl1)); |
| ItemsToRemove.push(tl1); |
| } |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| [Test(dataProvider=singleTextLineStaticDp)] |
| public function singleTextLineStatic(testCaseVo:TestCaseVo):void |
| { |
| singleTextLine(testCaseVo); |
| TextLine(ItemsToRemove[0]).validity = TextLineValidity.STATIC; |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| [Test(dataProvider=tenTextLinesStaticDp)] |
| public function tenTextLinesStatic(testCaseVo:TestCaseVo):void |
| { |
| tenTextLines(testCaseVo); |
| for (var i:int = 0; i < ItemsToRemove.length; i++) |
| { |
| TextLine(ItemsToRemove[i]).validity = TextLineValidity.STATIC; |
| } |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| [Test] |
| public function oneHundredTextLinesStatic():void |
| { |
| oneHundredTextLines(); |
| for (var i:int = 0; i < ItemsToRemove.length; i++) |
| { |
| TextLine(ItemsToRemove[i]).validity = TextLineValidity.STATIC; |
| } |
| System.gc(); |
| System.gc(); //garbage collect at end so we can compare memory usage versus static lines |
| } |
| |
| [Test(dataProvider=clickLinkedContainerTestDp)] |
| public function clickLinkedContainerTest(testCaseVo:TestCaseVo):void |
| { |
| var posOfSelection:int = testCaseVo.posOfSelection; |
| var format:TextLayoutFormat = new TextLayoutFormat(); |
| format.paddingLeft = 20; |
| format.paddingRight = 20; |
| format.paddingTop = 20; |
| format.paddingBottom = 20; |
| |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| |
| format.firstBaselineOffset = "auto"; |
| editManager.applyContainerFormat(format); |
| editManager.applyFormatToElement(editManager.textFlow, format); |
| editManager.selectRange(0, 0); |
| |
| //create two containers |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var controllerOne:ContainerController = new ContainerController(container1, 200, 250); |
| var controllerTwo:ContainerController = new ContainerController(container2, 150, 300); |
| |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controllerOne); |
| textFlow.flowComposer.addController(controllerTwo); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| var tfl:TextFlowLine = textFlow.flowComposer.findLineAtPosition(posOfSelection); |
| var adjustedPosOfSelection:int = posOfSelection - tfl.absoluteStart; |
| var tl:TextLine = tfl.getTextLine(); |
| var bounds:Rectangle = tl.getAtomBounds(adjustedPosOfSelection); |
| |
| var mouseX:Number = 0; |
| var mouseY:Number = 0; |
| |
| if (testCaseVo.id == "clickLeftToLinkedContainer") |
| { |
| mouseX = bounds.x - 1; |
| mouseY = tl.y; |
| } |
| else if (testCaseVo.id == "clickRightToLinkedContainer") |
| { |
| mouseX = bounds.x + 1; |
| mouseY = tl.y; |
| } |
| else if (testCaseVo.id == "clickTopLinkedContainer") |
| { |
| mouseX = bounds.x; |
| mouseY = tl.y - 1; |
| } |
| else if (testCaseVo.id == "clickBottomLinkedContainer") |
| { |
| mouseX = bounds.x; |
| mouseY = tl.y + 1; |
| } |
| |
| editManager.setFocus(); |
| var mEvent:MouseEvent; |
| mEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, mouseX, mouseY); |
| container1.dispatchEvent(mEvent); |
| editManager.setFocus(); |
| |
| editManager.flushPendingOperations(); |
| var posAfterClick:int = editManager.activePosition; |
| |
| assertTrue("Position changed after click." + " Position of selected is: " + posOfSelection |
| + " Position of after Click: " + posAfterClick, |
| posOfSelection == posAfterClick); |
| |
| } |
| |
| /** |
| * linked containers, check if attribute changed after texts insertion |
| */ |
| [Test(dataProvider=checkContainerAttributesAfterTextInsertionDp)] |
| public function checkContainerAttributesAfterTextInsertion(testCaseVo:TestCaseVo):void |
| { |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| |
| //create two linked containers containers |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var controllerOne:ContainerController = new ContainerController(container1, 200, 250); |
| var controllerTwo:ContainerController = new ContainerController(container2, 150, 300); |
| |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controllerOne); |
| textFlow.flowComposer.addController(controllerTwo); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| editManager.selectRange(0, 0); |
| editManager.setFocus(); |
| |
| var format:TextLayoutFormat = new TextLayoutFormat(); |
| format.paddingLeft = 20; |
| format.paddingRight = 20; |
| format.paddingTop = 20; |
| format.paddingBottom = 20; |
| |
| format.firstBaselineOffset = "auto"; |
| editManager.applyContainerFormat(format); |
| editManager.applyFormatToElement(editManager.textFlow, format); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| //get container attributes before insertion |
| var containerAtts_before:ITextLayoutFormat = controllerOne.format; |
| var paddingLeft_before:Number = containerAtts_before.paddingLeft; |
| var paddingRight_before:Number = containerAtts_before.paddingRight; |
| var paddingTop_before:Number = containerAtts_before.paddingTop; |
| var paddingBottom_before:Number = containerAtts_before.paddingBottom; |
| |
| var firstContStart:int = controllerOne.absoluteStart; |
| var firstContLen:int = controllerOne.textLength; |
| var firstContEnd:int = firstContStart + firstContLen; |
| |
| //get the insertion position |
| if (testCaseVo.id == "insertionEndOf1stContainer") |
| { |
| editManager.selectRange(firstContEnd - 1, firstContEnd - 1); |
| } |
| else if (testCaseVo.id == "insertionBeginOf2ndContainer") |
| { |
| editManager.selectRange(firstContEnd, firstContEnd); |
| } |
| editManager.insertText("BBB"); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| //check attributes after insertion |
| var containerAtts_after:ITextLayoutFormat = controllerOne.format; |
| var paddingLeft_after:Number = containerAtts_after.paddingLeft; |
| var paddingRight_after:Number = containerAtts_after.paddingRight; |
| var paddingTop_after:Number = containerAtts_after.paddingTop; |
| var paddingBottom_after:Number = containerAtts_after.paddingBottom; |
| |
| //check if attributes changed after insertion |
| assertTrue("Attributes have been changed after insertion to end of 1st container.", |
| paddingLeft_before === paddingLeft_after && |
| paddingRight_before === paddingRight_after && |
| paddingTop_before === paddingTop_after && |
| paddingBottom_before === paddingBottom_after); |
| } |
| |
| private var firstFlow:TextFlow; |
| private var secondFlow:TextFlow; |
| private var firstController:ContainerController; |
| private var secondController:ContainerController; |
| |
| private function resizeHandler(event:Event):void |
| { |
| const verticalGap:Number = 25; |
| const stagePadding:Number = 16; |
| var stageWidth:Number = TestCanvas.width - stagePadding; |
| var stageHeight:Number = TestCanvas.height - stagePadding; |
| var firstContaierWidth:Number = stageWidth; |
| var firstContaierHeight:Number = stageHeight; |
| // Initial compose to get height of headline after resize |
| firstController.setCompositionSize(firstContaierWidth, firstContaierHeight); |
| firstFlow.flowComposer.compose(); |
| var rect:Rectangle = firstController.getContentBounds(); |
| firstContaierHeight = rect.height; |
| // Resize and place headline text container |
| // Call setCompositionSize() again with updated headline height |
| firstController.setCompositionSize(firstContaierWidth, firstContaierHeight); |
| firstController.container.x = stagePadding / 2; |
| firstController.container.y = stagePadding / 2; |
| firstFlow.flowComposer.updateAllControllers(); |
| // Resize and place second text container |
| var secondContainerHeight:Number = (stageHeight - verticalGap - |
| firstContaierHeight); |
| secondController.setCompositionSize(stageWidth, secondContainerHeight); |
| secondController.container.x = (stagePadding / 2); |
| secondController.container.y = (stagePadding / 2) + firstContaierHeight + |
| verticalGap; |
| secondFlow.flowComposer.updateAllControllers(); |
| } |
| |
| [Test] |
| public function SelectionChangeFocusTest():void |
| { |
| |
| const firstMarkup:String = "<flow:TextFlow xmlns:flow='http://ns.adobe.com/textLayout/2008'>" + |
| "<flow:p>" + "<flow:span fontSize='14'>first text flow: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</flow:span>" + |
| "</flow:p>" + |
| "</flow:TextFlow>"; |
| const secondMarkup:String = "<flow:TextFlow xmlns:flow='http://ns.adobe.com/textLayout/2008' fontSize='14'> " + |
| "<flow:p>" + |
| "<flow:span>second text flow: " + |
| "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.</flow:span>" + |
| "</flow:p>" + |
| "</flow:TextFlow>"; |
| var posOfSelection1:int = TestData.posOfSelection1; |
| var posOfSelection2:int = TestData.posOfSelection2; |
| |
| TestCanvas.addEventListener(Event.RESIZE, resizeHandler); |
| |
| //create first text flow, import first text, and assign composer |
| firstFlow = new TextFlow(); |
| firstFlow = TextConverter.importToFlow(firstMarkup, TextConverter.TEXT_LAYOUT_FORMAT); |
| firstFlow.flowComposer = new StandardFlowComposer(); |
| //create second text flow, import second text, and assign flow composer |
| secondFlow = new TextFlow(); |
| secondFlow = TextConverter.importToFlow(secondMarkup, TextConverter.TEXT_LAYOUT_FORMAT); |
| secondFlow.flowComposer = new StandardFlowComposer(); |
| // create first container, add controller, position container and add to stage |
| var firstContainer:Sprite = new Sprite(); |
| firstController = new ContainerController(firstContainer, 300, 50); |
| var editManager1:IEditManager = new EditManager(); |
| firstFlow.interactionManager = editManager1; |
| firstFlow.flowComposer.addController(firstController); |
| firstContainer.x = 120; |
| firstContainer.y = 20; |
| TestCanvas.rawChildren.addChild(firstContainer); |
| firstFlow.flowComposer.updateAllControllers(); |
| |
| // create container for second text and position it |
| var secondContainer:Sprite = new Sprite(); |
| secondController = new ContainerController(secondContainer, 300, 200); |
| secondContainer.x = 125; |
| secondContainer.y = 185; |
| var editManager2:IEditManager = new EditManager(); |
| secondFlow.interactionManager = editManager2; |
| // add controller, add container to stage, and display second text |
| secondFlow.flowComposer.addController(secondController); |
| TestCanvas.rawChildren.addChild(secondContainer); |
| secondFlow.flowComposer.updateAllControllers(); |
| |
| //get focus for first flow |
| editManager1.selectRange(posOfSelection1, posOfSelection1); |
| editManager1.flushPendingOperations(); |
| editManager1.setFocus(); |
| |
| assertTrue("Selection Focus doesn't change after selection change from Text Flow 1 to Text Flow 2. ", |
| posOfSelection1 == editManager1.activePosition); |
| |
| //get focus for second flow |
| editManager2.selectRange(posOfSelection2, posOfSelection2); |
| editManager2.flushPendingOperations(); |
| editManager2.setFocus(); |
| |
| assertTrue("Selection Focus doesn't change properly after selection change from Text Flow 1 to Text Flow 2. " |
| + ". The expected focus poisiton should be in second text flow at: " + posOfSelection2 |
| + " and the actual text flow focus poisiton is: " + editManager2.activePosition, |
| posOfSelection2 == editManager2.activePosition); |
| } |
| |
| [Test(dataProvider=clickMultiLinkedContainerTestDp)] |
| public function clickMultiLinkedContainerTest(testCaseVo:TestCaseVo):void |
| { |
| var posOfSelection:int = testCaseVo.posOfSelection; |
| var format:TextLayoutFormat = new TextLayoutFormat(); |
| format.paddingLeft = 20; |
| format.paddingRight = 20; |
| format.paddingTop = 20; |
| format.paddingBottom = 20; |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| format.firstBaselineOffset = "auto"; |
| editManager.applyContainerFormat(format); |
| editManager.applyFormatToElement(editManager.textFlow, format); |
| editManager.selectRange(0, 0); |
| |
| //create five containers |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var container3:Sprite = new Sprite(); |
| var container4:Sprite = new Sprite(); |
| var container5:Sprite = new Sprite(); |
| var controller1:ContainerController = new ContainerController(container1, 200, 200); |
| var controller2:ContainerController = new ContainerController(container2, 200, 200); |
| var controller3:ContainerController = new ContainerController(container3, 200, 200); |
| var controller4:ContainerController = new ContainerController(container4, 200, 200); |
| var controller5:ContainerController = new ContainerController(container5, 200, 200); |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| TestCanvas.rawChildren.addChild(container3); |
| TestCanvas.rawChildren.addChild(container4); |
| TestCanvas.rawChildren.addChild(container5); |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| container3.x = 535; |
| container3.y = 50; |
| container4.x = 790; |
| container4.y = 50; |
| container5.x = 1045; |
| container5.y = 50; |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controller1); |
| textFlow.flowComposer.addController(controller2); |
| textFlow.flowComposer.addController(controller3); |
| textFlow.flowComposer.addController(controller4); |
| textFlow.flowComposer.addController(controller5); |
| textFlow.flowComposer.updateAllControllers(); |
| var tfl:TextFlowLine = textFlow.flowComposer.findLineAtPosition(posOfSelection); |
| var adjustedPosOfSelection:int = posOfSelection - tfl.absoluteStart; |
| var tl:TextLine = tfl.getTextLine(); |
| var bounds:Rectangle = tl.getAtomBounds(adjustedPosOfSelection); |
| var mouseX:Number = 0; |
| var mouseY:Number = 0; |
| if (testCaseVo.id == "clickLeftToMultiLinkedContainer") |
| { |
| mouseX = bounds.x - 1; |
| mouseY = tl.y; |
| } |
| else if (testCaseVo.id == "clickRightToMultiLinkedContainer") |
| { |
| mouseX = bounds.x + 1; |
| mouseY = tl.y; |
| } |
| else if (testCaseVo.id == "clickTopMultiLinkedContainer") |
| { |
| mouseX = bounds.x; |
| mouseY = tl.y - 1; |
| } |
| else if (testCaseVo.id == "clickBottomMultiLinkedContainer") |
| { |
| mouseX = bounds.x; |
| mouseY = tl.y + 1; |
| } |
| editManager.setFocus(); |
| var mEvent:MouseEvent; |
| mEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, mouseX, mouseY); |
| container1.dispatchEvent(mEvent); |
| editManager.setFocus(); |
| editManager.flushPendingOperations(); |
| var posAfterClick:int = editManager.activePosition; |
| assertTrue("Position changed after click." + " Position of selected is: " + posOfSelection |
| + " Position of after Click: " + posAfterClick, |
| posOfSelection == posAfterClick); |
| |
| } |
| |
| /***************************************************************** |
| Drag selection using mouse events and verify the selected range. |
| ******************************************************************/ |
| //two text flows, two containers |
| [Test] |
| [Ignore] |
| public function draggingSelectioinMultiFlows():void |
| { |
| //create the first text flow, import texts from markups, and assign flow composer to a container |
| var flow_1:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| flow_1.flowComposer = new StandardFlowComposer(); |
| var container_1:Sprite = new Sprite(); |
| var controller_1:ContainerController = new ContainerController(container_1, 300, 250); |
| container_1.x = 25; |
| container_1.y = 25; |
| |
| //Create EditManager to manage edting changes in TextFlow |
| var eManager_1:IEditManager = new EditManager(); |
| flow_1.interactionManager = eManager_1; |
| eManager_1.selectRange(0, 0); |
| |
| //add controllers to the first text flow and update all controller to display texts |
| flow_1.flowComposer.addController(controller_1); |
| TestCanvas.rawChildren.addChild(container_1); |
| flow_1.flowComposer.updateAllControllers(); |
| |
| //set points for the selection beginning and end |
| var startFlowLine:TextFlowLine = flow_1.flowComposer.getLineAt(2); |
| var startLine:TextLine = startFlowLine.getTextLine(); |
| var endFlowLine:TextFlowLine = flow_1.flowComposer.getLineAt(10); |
| var endLine:TextLine = endFlowLine.getTextLine(); |
| var endRect:Rectangle = endLine.getAtomBounds(54); |
| var startPoint:Point = new Point(startLine.x, startLine.y); |
| var endPoint:Point = new Point(endRect.x, endLine.y); |
| var x_point:Number; |
| var y_point:Number; |
| |
| x_point = startPoint.x; |
| y_point = startPoint.y; |
| |
| //selection start point in the first text flow |
| eManager_1.setFocus(); |
| var downPoint:MouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, x_point, y_point, container_1); |
| container_1.dispatchEvent(downPoint); |
| |
| var startInt:int = startFlowLine.absoluteStart; |
| var activeInt:int = eManager_1.activePosition; |
| var charCount:int = endLine.atomCount; |
| var endLineStart:int = endFlowLine.absoluteStart; |
| var endInt:int = (endLineStart + charCount) - 1; |
| |
| if (startInt == activeInt) |
| { |
| x_point = endPoint.x; |
| y_point = endPoint.y; |
| |
| //dragging selection |
| eManager_1.setFocus(); |
| var movePoint:MouseEvent = |
| new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, x_point, y_point, container_1, false, false, false, true); |
| container_1.dispatchEvent(movePoint); |
| |
| //dragging is done |
| var upPoint:MouseEvent = |
| new MouseEvent(MouseEvent.MOUSE_UP, true, false, x_point, y_point, container_1); |
| container_1.dispatchEvent(upPoint); |
| } |
| |
| else |
| { |
| fail("Mouse down event in the first text flow didn't happen!"); |
| } |
| |
| //create the second text flow, import texts from markups, and assign flow composer to a container |
| var flow_2:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| flow_2.flowComposer = new StandardFlowComposer(); |
| |
| //Create EditManager to manage edting changes in TextFlow |
| var eManager_2:IEditManager = new EditManager(); |
| flow_2.interactionManager = eManager_2; |
| eManager_2.selectRange(0, 0); |
| |
| var container_2:Sprite = new Sprite(); |
| var controller_2:ContainerController = new ContainerController(container_2, 300, 250); |
| container_2.x = 350; |
| container_2.y = 25; |
| |
| //add controllers to the second text flow and update all controller to display texts |
| flow_2.flowComposer.addController(controller_2); |
| TestCanvas.rawChildren.addChild(container_2); |
| flow_2.flowComposer.updateAllControllers(); |
| |
| //set points for the selection beginning and end |
| var startFlowLine2:TextFlowLine = flow_2.flowComposer.getLineAt(5); |
| var startLine2:TextLine = startFlowLine.getTextLine(); |
| var endFlowLine2:TextFlowLine = flow_2.flowComposer.getLineAt(13); |
| var endLine2:TextLine = endFlowLine2.getTextLine(); |
| var endRect2:Rectangle = endLine2.getAtomBounds(54); |
| |
| var startPoint2:Point = new Point(startLine2.x, startLine2.y); |
| var endPoint2:Point = new Point(endRect2.x, endLine2.y); |
| |
| var x_point2:Number; |
| var y_point2:Number; |
| |
| x_point2 = startPoint2.x; |
| y_point2 = startPoint2.y; |
| |
| //selection start point in the sencond text flow |
| eManager_2.setFocus(); |
| var downPoint2:MouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, x_point2, y_point2, container_2); |
| container_2.dispatchEvent(downPoint2); |
| |
| x_point2 = endPoint2.x; |
| y_point2 = endPoint2.y; |
| |
| //dragging selection |
| eManager_2.setFocus(); |
| var movePoint2:MouseEvent = |
| new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, x_point2, y_point2, container_2, false, false, false, true); |
| container_2.dispatchEvent(movePoint2); |
| |
| //dragging is done |
| var upPoint2:MouseEvent = |
| new MouseEvent(MouseEvent.MOUSE_UP, true, false, x_point2, y_point2, container_2); |
| container_2.dispatchEvent(upPoint2); |
| |
| var charCount2:int = endLine2.atomCount; |
| var startInt2:int = startFlowLine2.absoluteStart; |
| var endLineStart2:int = endFlowLine2.absoluteStart; |
| var endInt2:int = (endLineStart2 + charCount2) - 1; |
| |
| var start:int = 101; |
| var end:int = 573; |
| assertTrue("Selection range for the first text flow should have been from ".concat(start, " to ", end, " but it was from ", |
| startInt, " to ", endInt, startInt == start && endInt == end)); |
| |
| var start2:int = 252; |
| var end2:int = 733; |
| assertTrue("Selection range for the second text flow should have been from ".concat(start2, " to ", end2, |
| " but it was from ", startInt2, " to ", endInt2, startInt2 == start2 && endInt2 == end2)); |
| } |
| |
| /** |
| * two text flows, two containers, select from one flow to another |
| */ |
| [Test] |
| public function DraggingSelectionOneFlowToAnotherTest():void |
| { |
| |
| const firstMarkup:String = "<flow:TextFlow xmlns:flow='http://ns.adobe.com/textLayout/2008'>" + |
| "<flow:p>" + "<flow:span fontSize='14'>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</flow:span>" + |
| "</flow:p>" + |
| "</flow:TextFlow>"; |
| const secondMarkup:String = "<flow:TextFlow xmlns:flow='http://ns.adobe.com/textLayout/2008' fontSize='14'> " + |
| "<flow:p>" + |
| "<flow:span>second text flow: " + |
| "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.</flow:span>" + |
| "</flow:p>" + |
| "</flow:TextFlow>"; |
| var posOfSelection1:int = TestData.posOfSelection1; |
| var posOfSelection2:int = TestData.posOfSelection2; |
| |
| //create first text flow, import first text, and assign composer |
| firstFlow = new TextFlow(); |
| firstFlow = TextConverter.importToFlow(firstMarkup, TextConverter.TEXT_LAYOUT_FORMAT); |
| firstFlow.flowComposer = new StandardFlowComposer(); |
| //create second text flow, import second text, and assign flow composer |
| secondFlow = new TextFlow(); |
| secondFlow = TextConverter.importToFlow(secondMarkup, TextConverter.TEXT_LAYOUT_FORMAT); |
| secondFlow.flowComposer = new StandardFlowComposer(); |
| // create first container, add controller, position container |
| var firstContainer:Sprite = new Sprite(); |
| firstController = new ContainerController(firstContainer, 300, 50); |
| var editManager1:IEditManager = new EditManager(); |
| firstFlow.interactionManager = editManager1; |
| firstFlow.flowComposer.addController(firstController); |
| firstContainer.x = 120; |
| firstContainer.y = 20; |
| TestCanvas.rawChildren.addChild(firstContainer); |
| firstFlow.flowComposer.updateAllControllers(); |
| |
| // create container for second text and position it |
| var secondContainer:Sprite = new Sprite(); |
| secondController = new ContainerController(secondContainer, 300, 200); |
| secondContainer.x = 125; |
| secondContainer.y = 185; |
| var editManager2:IEditManager = new EditManager(); |
| secondFlow.interactionManager = editManager2; |
| // add controller, add container to stage, and display second text |
| secondFlow.flowComposer.addController(secondController); |
| TestCanvas.rawChildren.addChild(secondContainer); |
| secondFlow.flowComposer.updateAllControllers(); |
| |
| // make selection in first flow and second flow |
| editManager1.selectRange(0, 0); |
| var tfl1:TextFlowLine = firstFlow.flowComposer.findLineAtPosition(posOfSelection1); |
| var adjustedPosOfSelection1:int = posOfSelection1 - tfl1.absoluteStart; |
| var tl1:TextLine = tfl1.getTextLine(); |
| var bounds1:Rectangle = tl1.getAtomBounds(adjustedPosOfSelection1); |
| var tfl2:TextFlowLine = secondFlow.flowComposer.findLineAtPosition(posOfSelection2); |
| var adjustedPosOfSelection2:int = posOfSelection2 - tfl2.absoluteStart; |
| var tl2:TextLine = tfl2.getTextLine(); |
| var bounds2:Rectangle = tl2.getAtomBounds(adjustedPosOfSelection2); |
| |
| var mouseX:Number = bounds1.x; |
| var mouseY:Number = tl1.y; |
| |
| // mouse down in first container |
| editManager1.setFocus(); |
| var mEventD1:MouseEvent = new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, mouseX, mouseY, firstContainer); |
| firstContainer.dispatchEvent(mEventD1); |
| |
| // mouse move to second container and mouse up |
| mouseX = bounds2.x; |
| mouseY = tl2.y; |
| editManager2.selectRange(0, 0); |
| editManager2.setFocus(); |
| var mEventM1:MouseEvent = new MouseEvent(MouseEvent.MOUSE_MOVE, true, false, mouseX, mouseY, secondContainer, false, false, false, true); |
| secondContainer.dispatchEvent(mEventM1); |
| var mEventU1:MouseEvent = new MouseEvent(MouseEvent.MOUSE_UP, true, false, mouseX, mouseY, secondContainer); |
| secondContainer.dispatchEvent(mEventU1); |
| |
| var activePos:Number = editManager2.activePosition; |
| assertTrue("Selection should not extend to second container. ", |
| activePos == 0); |
| |
| } |
| |
| [Test] |
| public function addRemoveMulitiLinkedContainerTest():void |
| { |
| var format:TextLayoutFormat = new TextLayoutFormat(); |
| format.paddingLeft = 20; |
| format.paddingRight = 20; |
| format.paddingTop = 20; |
| format.paddingBottom = 20; |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| format.firstBaselineOffset = "auto"; |
| editManager.applyContainerFormat(format); |
| editManager.applyFormatToElement(editManager.textFlow, format); |
| editManager.selectRange(0, 0); |
| |
| //create five containers and hid two |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var container3:Sprite = new Sprite(); |
| var container4:Sprite = new Sprite(); |
| var container5:Sprite = new Sprite(); |
| var controller1:ContainerController = new ContainerController(container1, 100, 100); |
| var controller2:ContainerController = new ContainerController(container2, 200, 200); |
| var controller3:ContainerController = new ContainerController(container3, 300, 300); |
| var controller4:ContainerController = new ContainerController(container4, 400, 400); |
| var controller5:ContainerController = new ContainerController(container5, 500, 500); |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| TestCanvas.rawChildren.addChild(container3); |
| TestCanvas.rawChildren.addChild(container4); |
| TestCanvas.rawChildren.addChild(container5); |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| container3.x = 535; |
| container3.y = 50; |
| container4.x = 790; |
| container4.y = 50; |
| container5.x = 1045; |
| container5.y = 50; |
| container4.visible = false; |
| container5.visible = false; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controller1); |
| textFlow.flowComposer.addController(controller2); |
| textFlow.flowComposer.addController(controller3); |
| textFlow.flowComposer.addController(controller4); |
| textFlow.flowComposer.addController(controller5); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| //removeController |
| textFlow.flowComposer.removeController(controller5); |
| textFlow.flowComposer.updateAllControllers(); |
| var containerNumAfterRemove:int = textFlow.flowComposer.numControllers; |
| assertTrue("Container has not been removed correctly ", containerNumAfterRemove == 4); |
| |
| //removeControllerAt |
| textFlow.flowComposer.removeControllerAt(2); |
| textFlow.flowComposer.updateAllControllers(); |
| containerNumAfterRemove = textFlow.flowComposer.numControllers; |
| assertTrue("Container has not been removed correctly ", containerNumAfterRemove == 3); |
| |
| var c1:ContainerController = textFlow.flowComposer.getControllerAt(0); |
| var c2:ContainerController = textFlow.flowComposer.getControllerAt(1); |
| var c3:ContainerController = textFlow.flowComposer.getControllerAt(2); |
| var w1:int = c1.compositionWidth; |
| var w2:int = c2.compositionWidth; |
| var w3:int = c3.compositionWidth; |
| //check if removed correct containers |
| assertTrue("Wrong container has been removed ", w1 == 100 && w2 == 200 && w3 == 400); |
| |
| //addController |
| textFlow.flowComposer.addController(controller5); |
| textFlow.flowComposer.updateAllControllers(); |
| var containerNumAfterAdd:int = textFlow.flowComposer.numControllers; |
| assertTrue("Container has not been added correctly ", containerNumAfterAdd == 4); |
| //check if correct container added |
| var c4:ContainerController = textFlow.flowComposer.getControllerAt(3); |
| var w4:int = c4.compositionWidth; |
| assertTrue("Wrong container has been removed ", w4 == 500); |
| |
| //addControllerAt |
| textFlow.flowComposer.addControllerAt(controller3, 3); |
| textFlow.flowComposer.updateAllControllers(); |
| containerNumAfterAdd = textFlow.flowComposer.numControllers; |
| assertTrue("Container has not been added correctly ", containerNumAfterAdd == 5); |
| //check if correct container added at correct position |
| var c5:ContainerController = textFlow.flowComposer.getControllerAt(3); |
| var w5:int = c5.compositionWidth; |
| assertTrue("Container has not been added at corrent position ", w5 == 300); |
| c4 = textFlow.flowComposer.getControllerAt(4); |
| w4 = c4.compositionWidth; |
| assertTrue("Container has not been added at corrent position ", w4 == 500); |
| } |
| |
| [Test] |
| public function containerRecomposeAndConsistenceTest():void |
| { |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| editManager.selectRange(0, 0); |
| |
| //create five containers and hid two |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var container3:Sprite = new Sprite(); |
| var container4:Sprite = new Sprite(); |
| var container5:Sprite = new Sprite(); |
| var controller1:ContainerController = new ContainerController(container1, 200, 200); |
| var controller2:ContainerController = new ContainerController(container2, 200, 200); |
| var controller3:ContainerController = new ContainerController(container3, 200, 200); |
| var controller4:ContainerController = new ContainerController(container4, 200, 200); |
| var controller5:ContainerController = new ContainerController(container5, 200, 200); |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| TestCanvas.rawChildren.addChild(container3); |
| TestCanvas.rawChildren.addChild(container4); |
| TestCanvas.rawChildren.addChild(container5); |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| container3.x = 535; |
| container3.y = 50; |
| container4.x = 790; |
| container4.y = 50; |
| container5.x = 1045; |
| container5.y = 50; |
| container4.visible = false; |
| container5.visible = false; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controller1); |
| textFlow.flowComposer.addController(controller2); |
| textFlow.flowComposer.addController(controller3); |
| textFlow.flowComposer.addController(controller4); |
| textFlow.flowComposer.addController(controller5); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| if (TestData.id == "recomposeContainerTest") //to test if container will be re-composed correctly after some container update |
| { |
| //recompose controller3 |
| controller3.setCompositionSize(250, 250); |
| |
| var comp0:Boolean = textFlow.flowComposer.composeToController(0); |
| var comp1:Boolean = textFlow.flowComposer.composeToController(1); // shoud be true since last line before first damaged line will be re-composed |
| var comp2:Boolean = textFlow.flowComposer.composeToController(2); // should be true - controller3 |
| var comp3:Boolean = textFlow.flowComposer.composeToController(3); // should be true |
| var comp4:Boolean = textFlow.flowComposer.composeToController(4); // true due to overflow bydesign |
| textFlow.flowComposer.updateAllControllers(); |
| |
| assertTrue("composeToController returns wrong flag after re-composite.", |
| comp0 == false && comp1 == true && comp2 == true && comp3 == true && comp4 == true); |
| } |
| else if (TestData.id == "containerConsistenceTest") |
| { |
| var posOfSelection:int = TestData.posOfSelection; |
| var tfl:TextFlowLine = textFlow.flowComposer.findLineAtPosition(posOfSelection); |
| var tfl_abs:Number = tfl.absoluteStart; |
| var tfl_textLen:Number = tfl.textLength; |
| var controller:ContainerController = tfl.controller; |
| |
| var index:int = textFlow.flowComposer.getControllerIndex(controller); |
| var con_abs:Number = controller.absoluteStart; |
| var con_textLen:Number = controller.textLength; |
| var idx:Number = textFlow.flowComposer.findControllerIndexAtPosition(posOfSelection); |
| |
| assertTrue("abs start and text length are not consistent for textFlowLines in the container and the container", |
| con_abs <= tfl_abs <= con_textLen && tfl_textLen <= con_textLen && index == idx); |
| } |
| } |
| |
| private function findFirstAndLastVisibleLine(flowComposer:IFlowComposer, controller:ContainerController):Array |
| { |
| var firstLine:int = flowComposer.findLineIndexAtPosition(controller.absoluteStart); |
| var lastLine:int = flowComposer.findLineIndexAtPosition(controller.absoluteStart + controller.textLength - 1); |
| var lastColumn:int = 0; |
| var firstVisibleLine:int = -1; |
| var lastVisibleLine:int = -1; |
| for (var lineIndex:int = firstLine; lineIndex <= lastLine; lineIndex++) |
| { |
| var curLine:TextFlowLine = flowComposer.getLineAt(lineIndex); |
| if (curLine.controller != controller) |
| continue; |
| |
| // skip until we find the lines in the last column |
| if (curLine.columnIndex != lastColumn) |
| continue; |
| |
| if (curLine.textLineExists && curLine.getTextLine().parent) |
| { |
| if (firstVisibleLine < 0) |
| firstVisibleLine = lineIndex; |
| |
| lastVisibleLine = lineIndex; |
| } |
| } |
| |
| return [firstVisibleLine, lastVisibleLine]; |
| } |
| |
| [Test] |
| public function autoAndDragScrollingTest():void |
| { |
| |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| editManager.selectRange(0, 0); |
| |
| //create three containers |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var container3:Sprite = new Sprite(); |
| var controller1:ContainerController = new ContainerController(container1, 200, 200); |
| var controller2:ContainerController = new ContainerController(container2, 200, 200); |
| var controller3:ContainerController = new ContainerController(container3, 200, 200); |
| |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| TestCanvas.rawChildren.addChild(container3); |
| |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| container3.x = 535; |
| container3.y = 50; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controller1); |
| textFlow.flowComposer.addController(controller2); |
| textFlow.flowComposer.addController(controller3); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| //check first and last visible line in container1 before scrolling |
| var beforePosition1:Array = findFirstAndLastVisibleLine(textFlow.flowComposer, controller1); |
| var beforeFirstVisibleLine1:int = beforePosition1[0]; |
| var beforeLastVisibleLine1:int = beforePosition1[1]; |
| |
| var position1:int = controller1.textLength - 1; |
| //try to scroll to end of the container |
| controller1.scrollToRange(position1, position1); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| // verify that the first and last visible lines no change after scroll |
| var afterPosition1:Array = findFirstAndLastVisibleLine(textFlow.flowComposer, controller1); |
| var afterFirstVisibleLine1:int = afterPosition1[0]; |
| var afterLastVisibleLine1:int = afterPosition1[1]; |
| assertTrue("the container is scrollable. Expected not scrollable.", |
| beforeFirstVisibleLine1 == afterFirstVisibleLine1 && |
| beforeLastVisibleLine1 == afterLastVisibleLine1); |
| |
| //check first and last visible line in last container container3 before scrolling |
| var beforePosition3:Array = findFirstAndLastVisibleLine(textFlow.flowComposer, controller3); |
| var beforeFirstVisibleLine3:int = beforePosition3[0]; |
| var beforeLastVisibleLine3:int = beforePosition3[1]; |
| |
| var position3:int = textFlow.textLength - 1; |
| if (TestData.id == "dragScrollingTest") |
| { |
| editManager.selectRange(position3 - 20, position3); |
| editManager.setFocus(); |
| |
| } |
| controller3.scrollToRange(position3 - 20, position3); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| // verify that the first and last visible lines changed after scroll |
| var afterPosition3:Array = findFirstAndLastVisibleLine(textFlow.flowComposer, controller3); |
| var afterFirstVisibleLine3:int = afterPosition3[0]; |
| var afterLastVisibleLine3:int = afterPosition3[1]; |
| assertTrue("the last container is not scrollable. Expected scrollable.", |
| beforeFirstVisibleLine3 < afterFirstVisibleLine3 && |
| beforeLastVisibleLine3 < afterLastVisibleLine3); |
| |
| } |
| |
| [Test(dataProvider=navigateByLineTestDp)] |
| public function navigateByLineTest(testCaseVo:TestCaseVo):void |
| { |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| editManager.selectRange(0, 0); |
| |
| //create three containers |
| var container1:Sprite = new Sprite(); |
| var container2:Sprite = new Sprite(); |
| var container3:Sprite = new Sprite(); |
| var controller1:ContainerController = new ContainerController(container1, 200, 200); |
| var controller2:ContainerController = new ContainerController(container2, 200, 200); |
| var controller3:ContainerController = new ContainerController(container3, 200, 200); |
| |
| TestCanvas.rawChildren.addChild(container1); |
| TestCanvas.rawChildren.addChild(container2); |
| TestCanvas.rawChildren.addChild(container3); |
| |
| container1.x = 25; |
| container1.y = 50; |
| container2.x = 280; |
| container2.y = 50; |
| container3.x = 535; |
| container3.y = 50; |
| |
| // add the controllers to the text flow and update them to display the text |
| textFlow.flowComposer.addController(controller1); |
| textFlow.flowComposer.addController(controller2); |
| textFlow.flowComposer.addController(controller3); |
| textFlow.flowComposer.updateAllControllers(); |
| |
| //try to use previousLine to get to first container and nextLine to get to third container |
| var posSecondControllerBegin:int = controller2.absoluteStart; |
| var posSecondControllerEnd:int = posSecondControllerBegin + controller2.textLength; |
| if (testCaseVo.id == "navigateByPreviousLine") |
| { |
| //to get the selection range at beginning of second container then previousLine should go to the first container |
| editManager.selectRange(posSecondControllerBegin, posSecondControllerBegin + 10); |
| } |
| else if (testCaseVo.id == "navigateByNextLine") |
| { |
| //to get the selection range at end of second container then nextLine should go to the third container |
| editManager.selectRange(posSecondControllerEnd - 10, posSecondControllerEnd); |
| } |
| var selRange:SelectionState = editManager.getSelectionState(); |
| if (testCaseVo.id == "navigateByPreviousLine") |
| { |
| NavigationUtil.previousLine(selRange, true); |
| } |
| else if (testCaseVo.id == "navigateByNextLine") |
| { |
| NavigationUtil.nextLine(selRange, true); |
| } |
| |
| //composes all the text up-to date. |
| textFlow.flowComposer.updateAllControllers(); |
| var positionAfter:int = selRange.activePosition; |
| var curControllerIdx:int = textFlow.flowComposer.findControllerIndexAtPosition(positionAfter); |
| |
| if (TestData.id == "navigateByPreviousLine") |
| { |
| assertTrue("The previousLine didn't get to correct container.", curControllerIdx == 0); |
| } |
| else if (TestData.id == "navigateByNextLine") |
| { |
| assertTrue("The previousLine didn't get to correct container.", curControllerIdx == 2); |
| } |
| } |
| |
| [Test] |
| public function defaultContextMenuOnTest():void |
| { |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| editManager.selectRange(0, 0); |
| |
| //create a container |
| var container:Sprite = new Sprite(); |
| var controller:ContainerController = new ContainerController(container, 200, 200); |
| TestCanvas.rawChildren.addChild(container); |
| |
| // add the controller to the text flow and update it to display the text and setFocus to attach contextMenu |
| textFlow.flowComposer.addController(controller); |
| editManager.setFocus(); |
| textFlow.flowComposer.updateAllControllers(); |
| assertTrue("The default Context Menu should be on when editMode=readWrite.", container.contextMenu != null); |
| } |
| |
| /** |
| * Check if the contectMenu is off when editMode=readOnly |
| */ |
| [Test] |
| public function contextMenuOffTest():void |
| { |
| var textFlow:TextFlow = TextConverter.importToFlow(markup, TextConverter.TEXT_LAYOUT_FORMAT); |
| textFlow.flowComposer = new StandardFlowComposer(); |
| var editManager:IEditManager = new EditManager(); |
| textFlow.interactionManager = editManager; |
| editManager.selectRange(0, 0); |
| |
| //create a container |
| var container:Sprite = new Sprite(); |
| var controller:ContainerController = new ContainerController(container, 200, 200); |
| TestCanvas.rawChildren.addChild(container); |
| textFlow.flowComposer.addController(controller); |
| editManager.setFocus(); //attach default contextMenu |
| textFlow.flowComposer.updateAllControllers(); |
| textFlow.interactionManager = null; //make editMode=readOnly to disable contextMenu |
| assertTrue("The default Context Menu should be off when editMode=readOnly.", container.contextMenu == null); |
| } |
| |
| [Test] |
| public function overrideContextMenuTestNull():void |
| { |
| var s:Sprite = createInputManagerNull(hostFormat); |
| s.dispatchEvent(new FocusEvent(FocusEvent.FOCUS_IN)); |
| TestCanvas.rawChildren.addChild(s); |
| assertTrue("It should be no contextMenu with the override fuction.", s.contextMenu == null); |
| } |
| |
| static private function createInputManagerNull(hostFormat:ITextLayoutFormat):Sprite |
| { |
| var s:Sprite = new Sprite(); |
| var tcm:CustomTextContainerManagerNull = new CustomTextContainerManagerNull(s); |
| tcm.compositionWidth = 250; |
| tcm.compositionHeight = 100; |
| tcm.setText("Hello World"); |
| tcm.hostFormat = hostFormat; |
| tcm.updateContainer(); |
| return s; |
| } |
| |
| [Test] |
| public function overrideContextMenuTestAll():void |
| { |
| var s:Sprite = createInputManagerAll(hostFormat); |
| s.dispatchEvent(new FocusEvent(FocusEvent.FOCUS_IN)); |
| TestCanvas.rawChildren.addChild(s); |
| assertTrue("The contextMenu should be all true.", s.contextMenu.customItems[0].caption == "PageUp" |
| && s.contextMenu.customItems[1].caption == "PageDown") |
| } |
| |
| static private function createInputManagerAll(hostFormat:ITextLayoutFormat):Sprite |
| { |
| var s:Sprite = new Sprite(); |
| var tcm:CustomTextContainerManagerAll = new CustomTextContainerManagerAll(s); |
| tcm.compositionWidth = 250; |
| tcm.compositionHeight = 100; |
| tcm.setText("Hello World"); |
| tcm.hostFormat = hostFormat; |
| tcm.updateContainer(); |
| return s; |
| } |
| |
| /** |
| * to test bug 2500307: TCM shouldn't have contextMenu when read-only |
| */ |
| [Test] |
| public function contextMenuReadOnly():void |
| { |
| var s:Sprite = new Sprite(); |
| s.x = 0; |
| s.y = 0; |
| TestCanvas.rawChildren.addChild(s); |
| var tcm:TextContainerManager = new TextContainerManager(s); |
| tcm.compositionWidth = 250; |
| tcm.compositionHeight = NaN; |
| tcm.setText("Hello World, there should not be a context menu becasue field is read-only"); |
| var format:TextLayoutFormat = new TextLayoutFormat(TextLayoutFormat.defaultFormat); |
| format.fontFamily = "Arial"; |
| format.fontSize = 14; |
| tcm.hostFormat = format; |
| tcm.editingMode = EditingMode.READ_ONLY; |
| tcm.updateContainer(); |
| assertTrue("The default Context Menu should be off when editMode=readOnly.", tcm.container.contextMenu == null); |
| } |
| |
| /** |
| * to test bug 2504032: TCM contextMenu when using the factory and READ_SELECT should not enable the edit clipboard items such as cut and paste |
| */ |
| [Test] |
| public function contextMenuReadSelect():void |
| { |
| var s:Sprite = new Sprite(); |
| s.x = 0; |
| s.y = 0; |
| var tcm:TextContainerManager = new TextContainerManager(s); |
| tcm.compositionWidth = 250; |
| tcm.compositionHeight = NaN; |
| tcm.setText("Hello World, TCM contextMenu when using the factory and READ_SELECT should not enable the edit clipboard items such as cut and paste"); |
| var format:TextLayoutFormat = new TextLayoutFormat(TextLayoutFormat.defaultFormat); |
| format.fontFamily = "Arial"; |
| format.fontSize = 14; |
| tcm.hostFormat = format; |
| tcm.updateContainer(); |
| |
| //to make textMenu and clipboardMenu enabled |
| s.dispatchEvent(new FocusEvent(FocusEvent.FOCUS_IN)); |
| TestCanvas.rawChildren.addChild(s); |
| assertTrue("The edit clipboard items such as cut and paste were disabled when TCM contextMenu NOT using READ_SELECT", tcm.container.contextMenu.clipboardMenu == true); |
| |
| //to make textMenu and clipboardMenu disabled |
| tcm.editingMode = EditingMode.READ_SELECT; |
| tcm.updateContainer(); |
| assertTrue("The edit clipboard items such as cut and paste were enabled when TCM contextMenu using READ_SELECT", tcm.container.contextMenu == null); |
| } |
| |
| private function getTestMarkup():String |
| { |
| return "<flow:TextFlow xmlns:flow='http://ns.adobe.com/textLayout/2008' fontSize='14' " + |
| "textIndent='0' paragraphSpaceBefore='6' paddingTop='4' paddingBottom='4'>" + |
| "<flow:p paragraphSpaceAfter='15' >" + |
| "<flow:span>There are many </flow:span>" + |
| "<flow:span fontStyle='italic'>such</flow:span>" + |
| "<flow:span> 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.</flow:span>" + |
| "</flow:p>" + |
| "<flow:p paragraphSpaceAfter='15'>" + |
| "<flow:span>" + |
| "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 halffrightened 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.</flow:span>" + |
| "</flow:p>" + |
| "</flow:TextFlow>"; |
| } |
| } |
| } |
| |
| import flash.display.Sprite; |
| import flash.events.ContextMenuEvent; |
| import flash.events.KeyboardEvent; |
| import flash.ui.ContextMenu; |
| import flash.ui.ContextMenuItem; |
| import flash.ui.Keyboard; |
| |
| import flashx.textLayout.container.TextContainerManager; |
| import flashx.textLayout.elements.IConfiguration; |
| import flashx.textLayout.tlf_internal; |
| |
| use namespace tlf_internal; |
| |
| class CustomTextContainerManagerNull extends TextContainerManager |
| { |
| public function CustomTextContainerManagerNull(container:Sprite, configuration:IConfiguration = null) |
| { |
| super(container, configuration); |
| } |
| |
| override protected function createContextMenu():ContextMenu |
| { |
| return null; |
| } |
| } |
| |
| |
| class CustomTextContainerManagerAll extends TextContainerManager |
| { |
| public function CustomTextContainerManagerAll(container:Sprite, configuration:IConfiguration = null) |
| { |
| super(container, configuration); |
| } |
| |
| protected override function createContextMenu():ContextMenu |
| { |
| var menu:ContextMenu = super.createContextMenu(); |
| var item:ContextMenuItem; |
| item = new ContextMenuItem("PageUp"); |
| menu.customItems.push(item); |
| item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemSelectHandler); |
| item = new ContextMenuItem("PageDown"); |
| menu.customItems.push(item); |
| item.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, menuItemSelectHandler); |
| return menu; |
| } |
| |
| private function menuItemSelectHandler(e:ContextMenuEvent):void |
| { |
| var key:KeyboardEvent; |
| switch (e.currentTarget.caption) |
| { |
| case "PageUp": |
| key = new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, true, 0, Keyboard.PAGE_UP); |
| keyDownHandler(key); |
| break; |
| case "PageDown": |
| key = new KeyboardEvent(KeyboardEvent.KEY_DOWN, true, true, 0, Keyboard.PAGE_DOWN); |
| keyDownHandler(key); |
| break; |
| } |
| } |
| |
| |
| } |
| /****************************************************************************** |
| Truncation options test for truncation of text composed using TextlineFactory |
| This is temporary till creating indepndent test file for truncation options. |
| Most of functions are modification from ConpositionTest.as |
| ******************************************************************************/ |
| /**** |
| var lines:Array; |
| var textLength:int; |
| var bounds:Rectangle; |
| var contentTextLength:int = textLength; |
| var line0:TextLine = lines[0] as TextLine; |
| var line0Extent:Number = TextLineFactory.defaultConfiguration.overflowPolicy == OverflowPolicy.FIT_ANY ? line0.y - line0.ascent : line0.y + line0.descent; |
| var line0TextLen:int = line0.rawTextLength; |
| var line1:TextLine = lines[1] as TextLine; |
| var line1Extent:Number = TextLineFactory.defaultConfiguration.overflowPolicy == OverflowPolicy.FIT_ANY ? line1.y - line1.ascent : line1.y + line1.descent; |
| var contentHeight:Number = bounds.height; |
| var line:TextLine; |
| var lineExtent:Number; |
| var testTruncationIndicator:String |
| var testFactory:TextLineFactory = new TextLineFactory(); |
| var originalContentPrefix:String; |
| |
| var singleLineText:String = "A single text line for truncation options test."; |
| |
| var rtlText:String = |
| 'مدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسة'+ |
| 'مدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسة'+ |
| 'مدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسة'+ |
| 'مدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسةمدرسة'; |
| |
| var accentedText:String = |
| '\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A' + |
| '\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A' + |
| '\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A' + |
| '\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A' + |
| '\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A\u0041\u030A'; |
| |
| |
| //function to display the text object |
| private function Callback(t1:TextLine):void |
| { |
| textLength += t1.rawTextLength ; |
| lines.push(t1); |
| } |
| |
| public function TruncationOptSingleLineCustom():void |
| { |
| var bounds:Rectangle = new Rectangle(40,40,100,NaN); |
| testTruncationIndicator = "@@@" |
| testFactory.text = singleLineText; |
| var atMark:String = "@@@" |
| var truncatedTxt:String = "A text line fo@@@"; |
| var truncationIndicatorLength:int; |
| |
| testFactory.textLinesFromString(Callback,bounds,new TruncationOptions(testTruncationIndicator,1)); |
| truncationIndicatorLength = truncatedTxt.lastIndexOf(testTruncationIndicator); |
| assertTrue("Truncation indicator, was not @@@!", testTruncationIndicator == atMark); |
| assertTrue("Truncation indicator didn't appear at the end of sentence!", truncatedTxt.length == truncationIndicatorLength+testTruncationIndicator.length); |
| } |
| |
| public function TruncationOptSingleLineDefault():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; testFactory.text = singleLineText; |
| bounds.left = 0; bounds.top = 0; |
| testFactory.textLinesFromString(Callback, bounds, new TruncationOptions(null, 2)); |
| truncationIndicatorIndex = testFactory.truncatedText.lastIndexOf(TruncationOptions.HORIZONTAL_ELLIPSIS); |
| assertTrue("Default truncation indicator not present at the end of the truncated string", |
| truncationIndicatorIndex+TruncationOptions.HORIZONTAL_ELLIPSIS.length == testFactory.truncatedText.length); |
| originalContentPrefix = testFactory.truncatedText.slice(0, truncationIndicatorIndex); |
| assertTrue("Original content before truncation indicator mangled", singleLineText.indexOf(originalContentPrefix) == 0); |
| } |
| |
| |
| public function UnspecifiedWidthTruncation():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = NaN; bounds.height = NaN; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null,null,null,new TruncationOptions(null, 0)); |
| assertTrue("Caused truncation despite unspecified width", textLength == contentTextLength); |
| } |
| |
| public function ExplicitLineBreakingTruncation():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; |
| bounds.left = 0; bounds.top = 0; |
| var format:TextLayoutFormat = new TextLayoutFormat(); |
| format.lineBreak = LineBreak.EXPLICIT; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null,null, format,new TruncationOptions(null, 0)); |
| assertTrue("Caused truncation despite explicit line breaks", textLength == contentTextLength); |
| } |
| |
| public function ComposeHeightNoLine():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = line0Extent/2; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null,null, null,new TruncationOptions()); |
| assertTrue("Composed one or more lines when compose height allows none", lines.length == 0); |
| } |
| |
| public function ZeroLineCountLimit():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = contentHeight; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback, singleLineText, bounds, null, null, null,new TruncationOptions(null, 0)); |
| assertTrue("Composed one or more lines when line count limit is 0", lines.length == 0); |
| } |
| |
| public function UnfitTruncationIndicator():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = contentHeight -1; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null, null, null,new TruncationOptions(singleLineText)); |
| assertTrue("Composed one or more lines when compose height does not allow truncation indicator itself to fit", lines.length == 0); |
| } |
| |
| public function ComposingFitToBounds():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null, null, null,new TruncationOptions(null, 2)); |
| assertTrue("Invalid truncation results when composing to fit in a line count limit", lines.length == 2); |
| } |
| |
| public function CompostitngFitLineCountLimit():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null, null, null,new TruncationOptions(null, 2)); |
| assertTrue("Invalid truncation results when multiple truncation criteria provided",lines.length == 1); |
| line = lines[0] as TextLine; |
| lineExtent = TextLineFactory.defaultConfiguration.overflowPolicy == OverflowPolicy.FIT_ANY ? line.y - line.ascent : line.y + line.descent; |
| assertTrue("Invalid truncation results when multiple truncation criteria provided", lineExtent <= line0Extent); |
| } |
| |
| public function ComposingFitBoundsAndLineCountLimit():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null, null, null,new TruncationOptions(null, 2)); |
| assertTrue("Invalid truncation results when composing to fit in a line count limit", lines.length == 2); |
| } |
| |
| public function ComposingFitBoundsAndLineCountLimit_2():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = line1Extent; |
| bounds.left = 0; bounds.top = 0; |
| TextLineFactory.createTextLinesFromString(Callback,singleLineText,bounds,null, null, null,new TruncationOptions(null, 1)); |
| assertTrue("Invalid truncation results when multiple truncation criteria provided", lines.length == 1); |
| line = lines[0] as TextLine; |
| lineExtent = TextLineFactory.defaultConfiguration.overflowPolicy == OverflowPolicy.FIT_ANY ? line.y - line.ascent : line.y + line.descent; |
| assertTrue("Invalid truncation results when multiple truncation criteria provided", lineExtent <= line1Extent);; |
| } |
| |
| public function OriginalTextReplacement():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; testFactory.text = singleLineText; |
| bounds.left = 0; bounds.top = 0; |
| testTruncationIndicator = '\u200B'; |
| testFactory.textLinesFromString(Callback, bounds, new TruncationOptions(testTruncationIndicator, 1)); |
| assertTrue("Replacing more original content than is neccessary", testFactory.truncatedText.length == line0TextLen+customTruncationIndicator.length); |
| } |
| |
| public function OriginalTextReplacementRTL():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; testFactory.text = rtlText; |
| bounds.left = 0; bounds.top = 0; |
| testTruncationIndicator = '\u200B'; |
| testFactory.textLinesFromString(Callback, bounds, new TruncationOptions(testTruncationIndicator, 1)); |
| } |
| |
| public function TruncationAtomsBoundaries():void |
| { |
| lines.splice(0); textLength = 0; |
| bounds.width = 200; bounds.height = NaN; testFactory.text = accentedText; |
| bounds.left = 0; bounds.top = 0; |
| testTruncationIndicator = '<' + '\u200A' + '>'; // what precedes and succeeds the hair space is irrelevant |
| testFactory.textLinesFromString(Callback, bounds, new TruncationOptions(testTruncationIndicator, 1)); |
| assertTrue("[Not a code bug] Fix test case so that truncation indicator itself fits", lines.length == 1); // baseline |
| |
| var initialTruncationPoint:int = testFactory.truncatedText.length - testTruncationIndicator.length; |
| assertTrue("[Not a code bug] Fix test case so that some of the original content is left behind on first truncation attempt", initialTruncationPoint > 0); // baseline |
| assertTrue("Truncation in the middle of an atom!", initialTruncationPoint % 2 == 0); |
| var nextTruncationPoint:int; |
| do |
| { |
| bounds.height = NaN; |
| // add another hair space in each iteration, making truncation indicator wider (ever so slightly) |
| testTruncationIndicator = testTruncationIndicator.replace('\u200A', '\u200A\u200A'); |
| testFactory.textLinesFromString(Callback, bounds, new TruncationOptions(testTruncationIndicator, 1)); |
| |
| nextTruncationPoint = testFactory.truncatedText.length - testTruncationIndicator.length; |
| if (nextTruncationPoint != initialTruncationPoint) |
| { |
| assertTrue("Truncation in the middle of an atom!", nextTruncationPoint % 2 == 0); |
| assertTrue("Sub-optimal replacement of original content?", nextTruncationPoint == initialTruncationPoint-2); |
| initialTruncationPoint = nextTruncationPoint; |
| } |
| |
| } while (nextTruncationPoint); |
| } |
| ****/ |
| |