Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id BA30D200C48 for ; Thu, 16 Mar 2017 14:37:29 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id B8E41160B8E; Thu, 16 Mar 2017 13:37:29 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 42B1C160B8B for ; Thu, 16 Mar 2017 14:37:27 +0100 (CET) Received: (qmail 73250 invoked by uid 500); 16 Mar 2017 13:37:24 -0000 Mailing-List: contact commits-help@flex.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@flex.apache.org Delivered-To: mailing list commits@flex.apache.org Received: (qmail 70791 invoked by uid 99); 16 Mar 2017 13:37:23 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 Mar 2017 13:37:23 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7F998F4B73; Thu, 16 Mar 2017 13:37:22 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: harbs@apache.org To: commits@flex.apache.org Date: Thu, 16 Mar 2017 13:37:55 -0000 Message-Id: In-Reply-To: <7b210e1bcc5441c2b7bda61eb9d66eb0@git.apache.org> References: <7b210e1bcc5441c2b7bda61eb9d66eb0@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: =?utf-8?q?=5B35/42=5D_flex-asjs_git_commit=3A_And_here=E2=80=99s_T?= =?utf-8?b?TEbigKY=?= archived-at: Thu, 16 Mar 2017 13:37:30 -0000 http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowLineLocation.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowLineLocation.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowLineLocation.as new file mode 100644 index 0000000..e6483dc --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowLineLocation.as @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose +{ + /** + * The TextFlowLineLocation class is an enumeration class that defines constants for specifying the location + * of a line within a paragraph. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + * + * @see ParagraphElement + * @see TextFlow + */ + + public final class TextFlowLineLocation + { + /** Specifies the first line in a paragraph. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + public static const FIRST:uint = 1; + + /** Specifies a middle line in a paragraph - neither the first nor the last line. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + public static const MIDDLE:uint = 2; + + /** Specifies the last line in a paragraph. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + public static const LAST:uint = 4; + + /** Specifies both the first and last lines in a paragraph. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + public static const ONLY:uint = 5; + }; +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowTableBlock.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowTableBlock.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowTableBlock.as new file mode 100644 index 0000000..a1189c2 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextFlowTableBlock.as @@ -0,0 +1,266 @@ +// ////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose +{ + import org.apache.flex.textLayout.container.IContainerController; + import org.apache.flex.core.IParentIUIBase; + import org.apache.flex.graphics.ICompoundGraphic; + import org.apache.flex.text.engine.ITextLine; + import org.apache.flex.textLayout.edit.SelectionFormat; + import org.apache.flex.textLayout.elements.CellContainer; + import org.apache.flex.textLayout.elements.CellCoordinates; + import org.apache.flex.textLayout.elements.IParagraphElement; + import org.apache.flex.textLayout.elements.ITableCellElement; + import org.apache.flex.textLayout.elements.ITableElement; + import org.apache.flex.textLayout.elements.TableBlockContainer; + + /** + * + **/ + public class TextFlowTableBlock extends TextFlowLine implements ITextFlowTableBlock + { + private var _textHeight:Number; + + /** Constructor - creates a new TextFlowTableBlock instance. + *

Note: No client should call this. It's exposed for writing your own composer.

+ * + * @param index The index in the Table text flow. + * */ + public function TextFlowTableBlock(index:uint) + { + blockIndex = index; + _container = new TableBlockContainer(); + super(null, null); + } + + override public function get composable():Boolean + { + return false; + } + + /** + * @inheritDoc + **/ + override public function initialize(paragraph:IParagraphElement, outerTargetWidth:Number = 0, lineOffset:Number = 0, absoluteStart:int = 0, numChars:int = 0, textLine:ITextLine = null):void + { + _container.userData = this; + _lineOffset = lineOffset; + + super.initialize(paragraph, outerTargetWidth, lineOffset, absoluteStart, numChars, textLine); + } + + override public function setController(cont:IContainerController, colNumber:int):void + { + super.setController(cont, colNumber); + if (cont) + controller.addComposedTableBlock(container); + } + + /** + * The table that owns this table block + **/ + private var _parentTable:ITableElement; + /** + * The index of this block in the table text flow layout + **/ + public var blockIndex:uint = 0; + /** + * @private + **/ + private var _container:TableBlockContainer; + private var _cells:Array; + + /** + * Returns an array of table cells. + * @private + **/ + private function getCells():Array + { + if (_cells == null) + { + _cells = []; + } + return _cells; + } + + /** + * Returns a vector of table cell elements in the given cell range. + **/ + public function getCellsInRange(anchorCoords:CellCoordinates, activeCoords:CellCoordinates):Vector. + { + if (!parentTable) + return null; + return parentTable.getCellsInRange(anchorCoords, activeCoords, this); + } + + /** + * Clears the cells in the table block. Wraps clearCells(). + **/ + public function clear():void + { + clearCells(); + } + + /** + * Clears the cells in the table block + **/ + public function clearCells():void + { + while (_container.numElements) + { + _container.removeElement(_container.getElementAt(0)); + } + getCells().length = 0; + } + + /** + * Adds a cell container to table container. This adds it to the display list. + * If the cell is already added it does not add it twice. + **/ + public function addCell(cell:CellContainer):void + { + var cells:Array = getCells(); + if (cells.indexOf(cell) < 0) + { + cells.push(cell); + _container.addElement(cell); + } + } + + public function drawBackground(backgroundInfo:*):void + { + // TODO: need to figure this out... + } + + /** + * Container that displays this collection of cells + **/ + public function get container():TableBlockContainer + { + return _container; + } + + /** + * Triggers drawing of composed cell contents + **/ + public function updateCompositionShapes():void + { + var cells:Array = getCells(); + for each (var cell:CellContainer in cells) + { + cell.cellElement.updateCompositionShapes(); + } + } + + /** + * Sets the height of the container + **/ + override public function set height(value:Number):void + { + // _container.height = value; + _textHeight = value; + } + + /** + * @inheritDoc + **/ + override public function get height():Number + { + return _textHeight; + } + + /** + * Sets the width of the container + **/ + public function set width(value:Number):void + { + _container.width = value; + } + + /** + * Gets the width of the container + **/ + public function get width():Number + { + return _container.width; + } + + /** + * Sets the x position of the container + **/ + override public function set x(value:Number):void + { + super.x = _container.x = value; + } + + override public function get x():Number + { + return _container.x; + } + + /** + * Sets the y value of the container + **/ + override public function set y(value:Number):void + { + super.y = _container.y = value; + } + + override public function get y():Number + { + return _container.y; + } + + /** + * Returns a vector of table cell elements. + **/ + public function getTableCells():Vector. + { + var tCells:Vector. = new Vector.(); + var cells:Array = getCells(); + + for each (var cellContainer:CellContainer in cells) + { + tCells.push(cellContainer.cellElement); + } + + return tCells; + } + + public override function get textHeight():Number + { + return _textHeight; + } + + public override function hiliteBlockSelection(selObj:ICompoundGraphic, selFormat:SelectionFormat, container:IParentIUIBase, begIdx:int, endIdx:int, prevLine:ITextFlowLine, nextLine:ITextFlowLine):void + { + // do nothing for now... + } + + public function get parentTable():ITableElement + { + return _parentTable; + } + + public function set parentTable(parentTable:ITableElement):void + { + this._parentTable = parentTable; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextLineRecycler.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextLineRecycler.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextLineRecycler.as new file mode 100644 index 0000000..e2ae145 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/TextLineRecycler.as @@ -0,0 +1,129 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose +{ + import org.apache.flex.text.engine.ITextLine; + import org.apache.flex.utils.ObjectMap; + + CONFIG::debug { import org.apache.flex.textLayout.debug.assert; } + + + + + + /** + * The TextLineRecycler class provides support for recycling of TextLines. Some player versions support a recreateTextLine. Passing TextLines + * to the recycler makes them available for reuse. This improves Player performance. + * + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + public class TextLineRecycler + { + static private const _textLineRecyclerCanBeEnabled:Boolean = true; + static private var _textLineRecyclerEnabled:Boolean = _textLineRecyclerCanBeEnabled; + + /** Controls if the TLF recycler enabled. It can only be enabled in 10.1 or later players. + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + static public function get textLineRecyclerEnabled():Boolean + { return _textLineRecyclerEnabled; } + static public function set textLineRecyclerEnabled(value:Boolean):void + { _textLineRecyclerEnabled = value ? _textLineRecyclerCanBeEnabled : false; } + + // manage a cache of ITextLine's that can be reused + // This version uses a dictionary that holds the TextLines as weak references + static private var reusableLineCache:ObjectMap = new ObjectMap(true); + + /** + * Add a ITextLine to the pool for reuse. TextLines for reuse should have null userData and null parent. + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + static public function addLineForReuse(textLine:ITextLine):void + { + CONFIG::debug { assert(textLine.parent == null && textLine.userData == null && (textLine.validity == "invalid" || textLine.validity == "static"),"textLine not ready for reuse"); } + if (_textLineRecyclerEnabled) + { + CONFIG::debug + { + for each (var line:ITextLine in reusableLineCache) + { + assert(line != textLine,"READDING LINE TO CACHE"); + } + } + CONFIG::debug { cacheTotal++; } + reusableLineCache[textLine] = null; + } + } + CONFIG::debug + { + /** @private */ + static public var cacheTotal:int = 0; + /** @private */ + static public var fetchTotal:int = 0; + /** @private */ + static public var hitTotal:int = 0; + + static private function recordFetch(hit:int):void + { + fetchTotal++; + hitTotal += hit; + + /*if ((fetchTotal%100) == 0) + trace(fetchTotal,hitTotal,cacheTotal);*/ + } + } + + /** + * Return a ITextLine from the pool for reuse. + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @langversion 3.0 + */ + + static public function getLineForReuse():ITextLine + { + if (_textLineRecyclerEnabled) + { + for (var obj:Object in reusableLineCache) + { + // remove from the cache + delete reusableLineCache[obj]; + CONFIG::debug { assert(reusableLineCache[obj] === undefined,"Bad delete"); } + CONFIG::debug { recordFetch(1); } + return obj as ITextLine; + } + CONFIG::debug { recordFetch(0); } + } + return null; + } + + /** @private empty the reusableLineCache */ + static public function emptyReusableLineCache():void + { + reusableLineCache = new ObjectMap(true); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/VerticalJustifier.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/VerticalJustifier.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/VerticalJustifier.as new file mode 100644 index 0000000..0adee48 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/VerticalJustifier.as @@ -0,0 +1,351 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose +{ + import org.apache.flex.textLayout.container.IContainerController; + import org.apache.flex.textLayout.debug.assert; + import org.apache.flex.textLayout.formats.BlockProgression; + import org.apache.flex.textLayout.formats.Float; + import org.apache.flex.textLayout.formats.VerticalAlign; + + + + + /** @private + * Adjust line positions according to verticalAlign settings. Vertical alignment is perpendicular + * to the linebreak direction. + */ + public final class VerticalJustifier + { + [ ArrayElementType("org.apache.flex.textLayout.compose.IVerticalJustificationLine") ] + /** Vertical justify the subset of lines from startIndext to startIndex to numLines according to the rule specified by verticalAlignAttr. + * The assumption is that they are all the lines in a single column of cont. + * @see text.formats.VerticalAlign + * @return adjustment applied to the first line in the column. + * */ + static public function applyVerticalAlignmentToColumn(controller:IContainerController, verticalAlignAttr:String, lines:Array, startIndex:int, numLines:int,beginFloatIndex:int,endFloatIndex:int):Number + { + var helper:IVerticalAdjustmentHelper; + if (controller.rootElement.computedFormat.blockProgression == BlockProgression.RL) + helper = new RL_VJHelper(controller); + else + helper = new TB_VJHelper(controller); + + CONFIG::debug { assert(startIndex + numLines <= lines.length && numLines > 0,"applyVerticalAlignmentToColumn: bad indices"); } + + var i:int; + var rslt:Number; + + switch(verticalAlignAttr) + { + case VerticalAlign.MIDDLE: + case VerticalAlign.BOTTOM: + var lastLine:IVerticalJustificationLine = lines[(startIndex + numLines) - 1]; + var bottom:Number = helper.getBottom(lastLine, controller, beginFloatIndex, endFloatIndex); + rslt = (verticalAlignAttr == VerticalAlign.MIDDLE) ? helper.computeMiddleAdjustment(bottom) : helper.computeBottomAdjustment(bottom); + for (i = startIndex; i < startIndex + numLines; i++) // Adjust line positions + helper.applyAdjustment(lines[i]); + for (var floatIndex:int = beginFloatIndex; floatIndex < endFloatIndex; floatIndex++) // Adjust float positions + { + var floatInfo:FloatCompositionData = controller.getFloatAt(floatIndex); + if (floatInfo.floatType != Float.NONE) + helper.applyAdjustmentToFloat(floatInfo); + } + break; + case VerticalAlign.JUSTIFY: + rslt = helper.computeJustifyAdjustment(lines, startIndex, numLines); + helper.applyJustifyAdjustment(lines, startIndex, numLines); + break; + } + + //for (i = startIndex; i < startIndex + numLines; i++) + // trace("x=", sc[i].x, "y=", sc[i].y, "yAdj=", yAdj); + return rslt; + } + } +} + +import org.apache.flex.textLayout.compose.FloatCompositionData; +import org.apache.flex.textLayout.compose.IVerticalJustificationLine; +import org.apache.flex.textLayout.compose.ITextFlowLine; +import org.apache.flex.textLayout.container.IContainerController; +import org.apache.flex.textLayout.elements.IInlineGraphicElement; +import org.apache.flex.textLayout.formats.Float; + +interface IVerticalAdjustmentHelper +{ + function getBottom(line:IVerticalJustificationLine, controller:IContainerController, beginFloat:int, endFloat:int):Number; + + function computeMiddleAdjustment(bottom:Number):Number; + function applyAdjustment(line:IVerticalJustificationLine):void; + function applyAdjustmentToFloat(floatInfo:FloatCompositionData):void; + + function computeBottomAdjustment(bottom:Number):Number; + + function computeJustifyAdjustment(lineArray:Array, firstLine:int, numLines:int):Number; + function applyJustifyAdjustment(lineArray:Array, firstLine:int, numLines:int):void; +} + +class TB_VJHelper implements IVerticalAdjustmentHelper +{ + + + + private var _textFrame:IContainerController; + private var adj:Number; + + public function TB_VJHelper(tf:IContainerController):void + { + _textFrame = tf; + } + + public function getBottom(line:IVerticalJustificationLine, controller:IContainerController, beginFloat:int, endFloat:int):Number + { + var maxBottom:Number = getBaseline(line) + line.descent; + for (var i:int = beginFloat; i < endFloat; ++i) + { + var floatInfo:FloatCompositionData = controller.getFloatAt(i); + if (floatInfo.floatType != Float.NONE) + { + var ilg:IInlineGraphicElement = controller.rootElement.findLeaf(floatInfo.absolutePosition) as IInlineGraphicElement; + maxBottom = Math.max(maxBottom, floatInfo.y + ilg.elementHeightWithMarginsAndPadding()); + } + } + return maxBottom; + } + + public function getBottomOfLine(line:IVerticalJustificationLine):Number + { + return getBaseline(line) + line.descent; + } + + private function getBaseline(line:IVerticalJustificationLine):Number + { + if (line is ITextFlowLine) + return line.y + line.ascent; + else + return line.y; + } + + private function setBaseline(line:IVerticalJustificationLine, pos:Number):void + { + if (line is ITextFlowLine) + line.y = pos - line.ascent; + else + line.y = pos; + } + + // half of the available adjustment added to each y to shift the lines half way down the frame + public function computeMiddleAdjustment(contentBottom:Number):Number + { + var frameBottom:Number = _textFrame.compositionHeight - Number(_textFrame.getTotalPaddingBottom()); + adj = (frameBottom - contentBottom) / 2; + if (adj < 0) + adj = 0; // no space available to redistribute + return adj; + } + // the baseline of the last line should be at the bottom of the frame - paddingBottom. + public function computeBottomAdjustment(contentBottom:Number):Number + { + var frameBottom:Number = _textFrame.compositionHeight - Number(_textFrame.getTotalPaddingBottom()); + adj = frameBottom - contentBottom; + if (adj < 0) + adj = 0; // no space available to redistribute + return adj; + } + + public function applyAdjustment(line:IVerticalJustificationLine):void + { + line.y = line.y + adj; + } + + public function applyAdjustmentToFloat(floatInfo:FloatCompositionData):void + { + floatInfo.y += adj; + } + + // one line: untouched, two lines: first line untouched and descent of last line at the bottom of the frame, + // and more than two lines: line spacing increased proportionally, with first line untouched and descent of last line at the bottom of the frame + [ ArrayElementType("org.apache.flex.textLayout.compose.IVerticalJustificationLine") ] + public function computeJustifyAdjustment(lineArray:Array, firstLineIndex:int, numLines:int):Number + { + adj = 0; + + if (numLines == 1) + { + return 0; // do nothing + } + + // first line unchanged + var firstLine:IVerticalJustificationLine = lineArray[firstLineIndex]; + var firstBaseLine:Number = getBaseline(firstLine); + + // descent of the last line on the bottom of the frame + var lastLine:IVerticalJustificationLine = lineArray[firstLineIndex + numLines - 1]; + var frameBottom:Number = _textFrame.compositionHeight - Number(_textFrame.getTotalPaddingBottom()); + var allowance:Number = frameBottom - getBottomOfLine(lastLine); + if (allowance < 0) + { + return 0; // Some text scrolled out; don't justify + } + var lastBaseLine:Number = getBaseline(lastLine); + + adj = allowance/(lastBaseLine - firstBaseLine); // multiplicative factor by which the space between consecutive lines is increased + return adj; + } + + [ ArrayElementType("org.apache.flex.textLayout.compose.IVerticalJustificationLine") ] + public function applyJustifyAdjustment(lineArray:Array, firstLineIndex:int, numLines:int):void + { + if (numLines == 1 || adj == 0) + return; // do nothing + + var firstLine:IVerticalJustificationLine = lineArray[firstLineIndex]; + var prevBaseLine:Number = getBaseline(firstLine); + var prevBaseLineUnjustified:Number = prevBaseLine; + + var line:IVerticalJustificationLine; + var currBaseLine:Number; + var currBaseLineUnjustified:Number; + + for (var i:int = 1; i < numLines; i++) + { + line = lineArray[i + firstLineIndex]; + currBaseLineUnjustified = getBaseline(line); + + // Space between consecutive baselines scaled up by the calculated factor + currBaseLine = prevBaseLine + (currBaseLineUnjustified - prevBaseLineUnjustified)*(1 + adj); + setBaseline(line, currBaseLine); + + prevBaseLineUnjustified = currBaseLineUnjustified; + prevBaseLine = currBaseLine; + } + } +} + +class RL_VJHelper implements IVerticalAdjustmentHelper +{ + + + + private var _textFrame:IContainerController; + private var adj:Number = 0; + + public function RL_VJHelper(tf:IContainerController):void + { + _textFrame = tf; + } + + public function getBottom(lastLine:IVerticalJustificationLine, controller:IContainerController, beginFloat:int, endFloat:int):Number + { + var frameWidth:Number = _textFrame.compositionWidth - Number(_textFrame.getTotalPaddingLeft()); + var maxLeft:Number = (frameWidth + lastLine.x - lastLine.descent); + for (var i:int = beginFloat; i < endFloat; ++i) + { + var floatInfo:FloatCompositionData = controller.getFloatAt(i); + if (floatInfo.floatType != Float.NONE) + maxLeft = Math.min(maxLeft, floatInfo.x + frameWidth); + } + return maxLeft; + } + + // half of the available adjustment added to each x to shift the lines half way left across the frame + public function computeMiddleAdjustment(contentLeft:Number):Number + { + adj = contentLeft / 2; + if (adj < 0) + adj = 0; // no space available to redistribute + return -adj; + } + // the baseline of the last line should be at the bottom of the frame - paddingLeft. + public function computeBottomAdjustment(contentLeft:Number):Number + { + adj = contentLeft; + if (adj < 0) + adj = 0; // no space available to redistribute + return -adj; + } + + public function applyAdjustment(line:IVerticalJustificationLine):void + { + line.x = (line.x - adj); + } + + public function applyAdjustmentToFloat(floatInfo:FloatCompositionData):void + { + floatInfo.x -= adj; + } + + // one line: untouched, two lines: first line untouched and descent of last line at the bottom of the frame, + // and more than two lines: line spacing increased proportionally, with first line untouched and descent of last line at the bottom of the frame + [ ArrayElementType("org.apache.flex.textLayout.compose.IVerticalJustificationLine") ] + public function computeJustifyAdjustment(lineArray:Array, firstLineIndex:int, numLines:int):Number + { + adj = 0; + + if (numLines == 1) + return 0; // do nothing + + // first line unchanged + var firstLine:IVerticalJustificationLine = lineArray[firstLineIndex]; + var firstBaseLine:Number = firstLine.x; + + // descent of the last line on the left of the frame + var lastLine:IVerticalJustificationLine = lineArray[firstLineIndex + numLines - 1]; + var frameLeft:Number = Number(_textFrame.getTotalPaddingLeft()) - _textFrame.compositionWidth; + var allowance:Number = (lastLine.x - lastLine.descent) - frameLeft; + if (allowance < 0) + { + return 0; // Some text scrolled out; don't justify + } + var lastBaseLine:Number = lastLine.x; + + adj = allowance/(firstBaseLine - lastBaseLine); // multiplicative factor by which the space between consecutive lines is increased + return -adj; + } + + [ ArrayElementType("org.apache.flex.textLayout.compose.IVerticalJustificationLine") ] + public function applyJustifyAdjustment(lineArray:Array, firstLineIndex:int, numLines:int):void + { + if (numLines == 1 || adj == 0) + return; // do nothing + + var firstLine:IVerticalJustificationLine = lineArray[firstLineIndex]; + var prevBaseLine:Number = firstLine.x; + var prevBaseLineUnjustified:Number = prevBaseLine; + + var line:IVerticalJustificationLine; + var currBaseLine:Number; + var currBaseLineUnjustified:Number; + + for (var i:int = 1; i < numLines; i++) + { + line = lineArray[i + firstLineIndex]; + currBaseLineUnjustified = line.x; + + // Space between consecutive baselines scaled up by the calculated factor + currBaseLine = prevBaseLine - (prevBaseLineUnjustified - currBaseLineUnjustified)*(1 + adj); + line.x = currBaseLine; + + prevBaseLineUnjustified = currBaseLineUnjustified; + prevBaseLine = currBaseLine; + } + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/AdornmentUtils.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/AdornmentUtils.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/AdornmentUtils.as new file mode 100644 index 0000000..477e386 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/AdornmentUtils.as @@ -0,0 +1,685 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.elements.utils.GeometricElementUtils; + import org.apache.flex.core.IUIBase; + import org.apache.flex.textLayout.dummy.BoundsUtil; + import org.apache.flex.textLayout.elements.IFlowElement; + import org.apache.flex.textLayout.elements.ISubParagraphGroupElementBase; + import org.apache.flex.textLayout.formats.Float; + import org.apache.flex.graphics.SolidColor; + import org.apache.flex.textLayout.elements.ITCYElement; + import org.apache.flex.text.engine.TextBaseline; + import org.apache.flex.textLayout.elements.ITextFlow; + import org.apache.flex.graphics.SolidColorStroke; + import org.apache.flex.textLayout.formats.JustificationRule; + import org.apache.flex.textLayout.elements.IParagraphElement; + import org.apache.flex.graphics.PathBuilder; + import org.apache.flex.graphics.ICompoundGraphic; + import org.apache.flex.textLayout.debug.assert; + import org.apache.flex.textLayout.formats.BackgroundColor; + import org.apache.flex.textLayout.formats.TextDecoration; + import org.apache.flex.text.engine.TextRotation; + import org.apache.flex.textLayout.compose.ITextFlowLine; + import org.apache.flex.textLayout.formats.BlockProgression; + import org.apache.flex.core.IParentIUIBase; + import org.apache.flex.textLayout.elements.InlineGraphicElementStatus; + import org.apache.flex.textLayout.elements.IInlineGraphicElement; + import org.apache.flex.textLayout.formats.TextLayoutFormat; + import org.apache.flex.textLayout.formats.BaselineShift; + import org.apache.flex.geom.Rectangle; + import org.apache.flex.textLayout.formats.IMEStatus; + import org.apache.flex.text.engine.FontMetrics; + import org.apache.flex.textLayout.utils.CharacterUtil; + import org.apache.flex.text.engine.ITextLine; + import org.apache.flex.textLayout.elements.IFlowLeafElement; + + public class AdornmentUtils + { + /** @private */ + public static function getSpanBoundsOnLine(element:IFlowLeafElement,textLine:ITextLine, blockProgression:String):Array + { + var line:ITextFlowLine = ITextFlowLine(textLine.userData); + var paraStart:int = line.paragraph.getAbsoluteStart(); + var lineEnd:int = (line.absoluteStart + line.textLength) - paraStart; + var spanStart:int = element.getAbsoluteStart() - paraStart; // get start pos relative to the paragraph (which might not be the parent) + var endPos:int = spanStart + element.text.length; // so we don't include the paragraph terminator character, if present + + // Clip to start of line + var startPos:int = Math.max(spanStart, line.absoluteStart - paraStart); + + // Clip to end of line + // Heuristic for detecting spaces at the end of the line and eliminating them from the range so they won't be underlined. + if (endPos >= lineEnd) + { + endPos = lineEnd; + var spanText:String = element.text; + while (endPos > startPos && CharacterUtil.isWhitespace(spanText.charCodeAt(endPos - spanStart - 1))) + --endPos; + } + + var mainRects:Array = []; + line.calculateSelectionBounds(textLine, mainRects, startPos, endPos, blockProgression, [ line.textHeight,0]); + return mainRects; + } + + /** @private */ + static public function calculateStrikeThrough(element:IFlowLeafElement, textLine:ITextLine, blockProgression:String, metrics:FontMetrics):Number + { + if(element.className == "InlineGraphicElement" && IInlineGraphicElement(element).graphic && IInlineGraphicElement(element).status == InlineGraphicElementStatus.READY) + return calculateGraphicStrikeThrough(IInlineGraphicElement(element), textLine, blockProgression, metrics); + else + return calculateLeafStrikeThrough(element, textLine, blockProgression, metrics); + + } + /** + * @flexjsignorecoercion org.apache.flex.core.IParentIUIBase + * @flexjsignorecoercion org.apache.flex.textLayout.compose.ITextFlowLine + */ + static private function calculateGraphicStrikeThrough(element:IInlineGraphicElement, textLine:ITextLine, blockProgression:String, metrics:FontMetrics):Number + { + var stOffset:Number = 0; + var inlineHolder:IParentIUIBase = element.placeholderGraphic.parent as IParentIUIBase; + if (inlineHolder) + { + if(blockProgression != BlockProgression.RL) + stOffset = Object(element.placeholderGraphic.parent).y + (element.elementHeight/2 + Number(element.getEffectivePaddingTop())); + else + { + var paddingRight:Number = element.getEffectivePaddingRight(); + var line:ITextFlowLine = textLine.userData as ITextFlowLine; + var elemIdx:int = element.getAbsoluteStart() - line.absoluteStart; + if(textLine.getAtomTextRotation(elemIdx) != TextRotation.ROTATE_0) + stOffset = Object(element.placeholderGraphic.parent).x - (element.elementHeight/2 + paddingRight); + else + stOffset = Object(element.placeholderGraphic.parent).x - (element.elementWidth/2 + paddingRight); + } + } + + return blockProgression == BlockProgression.TB ? stOffset : -stOffset; + } + static private function calculateLeafStrikeThrough(element:IFlowLeafElement, textLine:ITextLine, blockProgression:String, metrics:FontMetrics):Number + { + var underlineAndStrikeThroughShift:int = 0; + var effectiveFontSize:Number = element.getEffectiveFontSize(); + if (element.computedFormat.baselineShift == BaselineShift.SUPERSCRIPT) + { + underlineAndStrikeThroughShift = -(metrics.superscriptOffset * effectiveFontSize); + } else if (element.computedFormat.baselineShift == BaselineShift.SUBSCRIPT) + { + underlineAndStrikeThroughShift = -(metrics.subscriptOffset * (effectiveFontSize / metrics.subscriptScale)); + } else { + underlineAndStrikeThroughShift = TextLayoutFormat.baselineShiftProperty.computeActualPropertyValue(element.computedFormat.baselineShift, effectiveFontSize); + } + + //grab the dominantBaseline and alignmentBaseline strings + var domBaselineString:String = GeometricElementUtils.resolveDomBaseline(element.computedFormat, element.getParagraph()); + var alignmentBaselineString:String = element.computedFormat.alignmentBaseline; + + //this value represents the position of the baseline used to align this text + var alignDomBaselineAdjustment:Number = textLine.getBaselinePosition(domBaselineString); + + //if the alignment baseline differs from the dominant, then we need to apply the delta between the + //dominant and the alignment to determine the line along which the glyphs are lining up... + if(alignmentBaselineString != org.apache.flex.text.engine.TextBaseline.USE_DOMINANT_BASELINE && + alignmentBaselineString != domBaselineString) + { + alignDomBaselineAdjustment = textLine.getBaselinePosition(alignmentBaselineString); + //take the alignmentBaseline offset and make it relative to the dominantBaseline + } + + + //first, establish the offset relative to the glyph based in fontMetrics data + var stOffset:Number = metrics.strikethroughOffset; + + + //why are we using the stOffset? Well, the stOffset effectively tells us where the mid-point + //of the glyph is. By using this value, we can determine how we need to offset the underline. + //now adjust the value. If it is center, then the glyphs are aligned along the ST position already + if(domBaselineString == org.apache.flex.text.engine.TextBaseline.IDEOGRAPHIC_CENTER) + { + stOffset = 0; + } + else if(domBaselineString == org.apache.flex.text.engine.TextBaseline.IDEOGRAPHIC_TOP || + domBaselineString == org.apache.flex.text.engine.TextBaseline.ASCENT) + { + stOffset *= -2; //if the glyphs are top or ascent, then we need to invert and double the offset + stOffset -= (2 * metrics.strikethroughThickness); + } + else if(domBaselineString == org.apache.flex.text.engine.TextBaseline.IDEOGRAPHIC_BOTTOM || + domBaselineString == org.apache.flex.text.engine.TextBaseline.DESCENT) + { + stOffset *= 2; //if they're bottom, then we need to simply double it + stOffset += (2 * metrics.strikethroughThickness); + } + else //Roman + { + stOffset -= metrics.strikethroughThickness; + } + + + //Now apply the actual dominant baseline position to the offset + stOffset += (alignDomBaselineAdjustment - underlineAndStrikeThroughShift); + return stOffset; + } + /** @private return number of shapes added */ + static public function updateAdornments(element:IFlowLeafElement, tLine:ITextLine, blockProgression:String):int + { + CONFIG::debug { assert(element.computedFormat != null,"invalid call to updateAdornments"); } + + // Don't underline for floats + if(element.className == "InlineGraphicElement" && Object(element).effectiveFloat != Float.NONE) + return 0; + if(element.className == "TableLeafElement") + return 0; + + // Only work on lines with strikethrough or underline + if (element.computedFormat.textDecoration == TextDecoration.UNDERLINE || element.computedFormat.lineThrough || element.computedFormat.backgroundAlpha > 0 && element.computedFormat.backgroundColor != BackgroundColor.TRANSPARENT) + { + var spanBoundsArray:Array = getSpanBoundsOnLine(element, tLine, blockProgression); + for (var i:int = 0; i < spanBoundsArray.length; i++) + updateAdornmentsOnBounds(element, tLine, blockProgression, spanBoundsArray[i]); + return spanBoundsArray.length ; + } + return 0; + } + + /** + * @flexjsignorecoercion org.apache.flex.textLayout.elements.IParagraphElement + */ + static private function updateAdornmentsOnBounds(element:IFlowLeafElement, tLine:ITextLine, blockProgression:String, spanBounds:Rectangle):void + { + CONFIG::debug { assert(element.computedFormat != null,"invalid call to updateAdornmentsOnBounds"); } + + var metrics:FontMetrics = element.getComputedFontMetrics(); + + + var backgroundOnly:Boolean = !(element.computedFormat.textDecoration == TextDecoration.UNDERLINE || element.computedFormat.lineThrough); + + if (!backgroundOnly) + { + var shape:ICompoundGraphic; + shape = element.getTextFlow().tlfFactory.getCompoundGraphic(); + shape.alpha = Number(element.computedFormat.textAlpha); + var builder:PathBuilder = new PathBuilder(); + shape.stroke = new SolidColorStroke(); + + var stOffset:Number = calculateStrikeThrough(element,tLine, blockProgression, metrics); + var ulOffset:Number = calculateUnderlineOffset(element, stOffset, blockProgression, metrics, tLine); + } + + if (blockProgression != BlockProgression.RL) + { + addBackgroundRect (element, tLine, metrics, spanBounds, true); + + if (element.computedFormat.textDecoration == TextDecoration.UNDERLINE) + { + shape.stroke.setLineStyle(metrics.underlineThickness, element.computedFormat.color as uint); + builder.moveTo(spanBounds.topLeft.x, ulOffset); + builder.lineTo(spanBounds.topLeft.x + spanBounds.width, ulOffset); + shape.drawPathCommands(builder); + builder.clear(); +// g.lineStyle(metrics.underlineThickness, _computedFormat.color as uint); +// g.moveTo(spanBounds.topLeft.x, ulOffset); +// g.lineTo(spanBounds.topLeft.x + spanBounds.width, ulOffset); + } + + if((element.computedFormat.lineThrough)) + { + shape.stroke.setLineStyle(metrics.strikethroughThickness, element.computedFormat.color as uint); + builder.moveTo(spanBounds.topLeft.x, stOffset); + builder.lineTo(spanBounds.topLeft.x + spanBounds.width, stOffset); + shape.drawPathCommands(builder); + builder.clear(); + +// g.lineStyle(metrics.strikethroughThickness, _computedFormat.color as uint); +// g.moveTo(spanBounds.topLeft.x, stOffset); +// g.lineTo(spanBounds.topLeft.x + spanBounds.width, stOffset); + } + } + else + { + //is this TCY? + var line:ITextFlowLine = tLine.userData as ITextFlowLine; + var elemIdx:int = element.getAbsoluteStart() - line.absoluteStart; + + //elemIdx can sometimes be negative if the text is being wrapped due to a + //resize gesture - in which case the tLine has not necessarily been updated. + //If the elemIdx is invalid, just treat it like it's normal ttb text - gak 07.08.08 + if (elemIdx < 0 || tLine.atomCount <= elemIdx || tLine.getAtomTextRotation(elemIdx) != TextRotation.ROTATE_0) + { + addBackgroundRect (element, tLine, metrics, spanBounds, false); + + if (element.computedFormat.textDecoration == TextDecoration.UNDERLINE) + { + shape.stroke.setLineStyle(metrics.underlineThickness, element.computedFormat.color as uint); + builder.moveTo(ulOffset, spanBounds.topLeft.y); + builder.lineTo(ulOffset, spanBounds.topLeft.y + spanBounds.height); + shape.drawPathCommands(builder); + builder.clear(); + +// g.lineStyle(metrics.underlineThickness, _computedFormat.color as uint); +// g.moveTo(ulOffset, spanBounds.topLeft.y); +// g.lineTo(ulOffset, spanBounds.topLeft.y + spanBounds.height); + } + + if (element.computedFormat.lineThrough == true) + { + shape.stroke.setLineStyle(metrics.strikethroughThickness, element.computedFormat.color as uint); + builder.moveTo(-stOffset, spanBounds.topLeft.y); + builder.lineTo(-stOffset, spanBounds.topLeft.y + spanBounds.height); + shape.drawPathCommands(builder); + builder.clear(); + +// g.lineStyle(metrics.strikethroughThickness, _computedFormat.color as uint); +// g.moveTo(-stOffset, spanBounds.topLeft.y); +// g.lineTo(-stOffset, spanBounds.topLeft.y + spanBounds.height); + } + } + else + { + addBackgroundRect (element, tLine, metrics, spanBounds, true, true); + + if (!backgroundOnly) + { + //it is TCY! + var tcyParent:ITCYElement = element.getParentByType("TCYElement") as ITCYElement; + CONFIG::debug{ assert(tcyParent != null, "What kind of object is this that is ROTATE_0, but not TCY?");} + + //if the locale of the paragraph is Chinese, we need to adorn along the left and not right side. + var tcyPara:IParagraphElement = element.getParentByType("ParagraphElement") as IParagraphElement; + var lowerLocale:String = tcyPara.computedFormat.locale.toLowerCase(); + var adornRight:Boolean = (lowerLocale.indexOf("zh") != 0); + + + //only perform calculations for TCY adornments when we are on the last leaf. ONLY the last leaf matters + if((element.getAbsoluteStart() + element.textLength) == (tcyParent.getAbsoluteStart() + tcyParent.textLength)) + { + var tcyAdornBounds:Rectangle = new Rectangle(); + calculateAdornmentBounds(tcyParent, tLine, blockProgression, tcyAdornBounds); + + if (element.computedFormat.textDecoration == TextDecoration.UNDERLINE) + { + shape.stroke.setLineStyle(metrics.underlineThickness, element.computedFormat.color as uint); +// g.lineStyle(metrics.underlineThickness, _computedFormat.color as uint); + var baseULAdjustment:Number = metrics.underlineOffset + (metrics.underlineThickness/2); + var xCoor:Number = adornRight ? spanBounds.right : spanBounds.left; + if(!adornRight) + baseULAdjustment = -baseULAdjustment; + + builder.moveTo(xCoor + baseULAdjustment, tcyAdornBounds.top); + builder.lineTo(xCoor + baseULAdjustment, tcyAdornBounds.bottom); + shape.drawPathCommands(builder); + builder.clear(); + +// g.moveTo(xCoor + baseULAdjustment, tcyAdornBounds.top); +// g.lineTo(xCoor + baseULAdjustment, tcyAdornBounds.bottom); + } + + if (element.computedFormat.lineThrough == true) + { + var tcyMid:Number = spanBounds.bottomRight.x - tcyAdornBounds.x; + tcyMid /= 2; + tcyMid += tcyAdornBounds.x; + + shape.stroke.setLineStyle(metrics.strikethroughThickness, element.computedFormat.color as uint); + builder.moveTo(tcyMid, tcyAdornBounds.top); + builder.lineTo(tcyMid, tcyAdornBounds.bottom); + shape.drawPathCommands(builder); + builder.clear(); + +// g.lineStyle(metrics.strikethroughThickness, _computedFormat.color as uint); +// g.moveTo(tcyMid, tcyAdornBounds.top); +// g.lineTo(tcyMid, tcyAdornBounds.bottom); + } + } + } + } + } + + // Add the shape as a child of the ITextLine. In some cases, the textLine we passed through may not be the same one that's + // in the TextFlowLine textLineCache. This can happen if the TextFlowLine's textLine is invalid and a child of the + // container. In that case, we generated a valid ITextLine and passed it in as tLine so that we have correct metrics + // for generating the adornment shapes. + if (shape) + { + var peekLine:ITextLine = (tLine.userData as ITextFlowLine).peekTextLine(); + CONFIG::debug{ assert(peekLine == null || peekLine == tLine || peekLine.validity == "invalid", "Valid/invalid mismatch"); } + // CONFIG::debug{ assert(peekLine == null || peekLine == TextFlowLine(tLine.userData).getTextLine(false), "Valid/invalid mismatch"); } + if (peekLine && tLine != peekLine) + { + // belief is that this line of code is never hit + CONFIG::debug { assert(false,"updateAdornmentsOnBounds: peekLine doesn't match textLine"); } + tLine = peekLine; + } + tLine.addElement(shape); + } + } + + /** + * @flexjsignorecoercion org.apache.flex.textLayout.compose.ITextFlowLine + */ + public static function updateIMEAdornments(element:IFlowLeafElement,tLine:ITextLine, blockProgression:String, imeStatus:String):void + { + // Don't underline for floats + if(element.className == "InlineGraphicElement" && Object(element).effectiveFloat != Float.NONE) + return; + + if(element.className == "TableLeafElement") + return ; + + var metrics:FontMetrics = element.getComputedFontMetrics(); + var spanBoundsArray:Array = getSpanBoundsOnLine(element,tLine, blockProgression); + //this is pretty much always going to have a length of 1, but just to be sure... + for (var i:int = 0; i < spanBoundsArray.length; i++) + { + //setup ime variables + var imeLineThickness:int = 1; + var imeLineColor:uint = 0x000000; + var imeLineStartX:Number = 0; + var imeLineStartY:Number = 0; + var imeLineEndX:Number = 0; + var imeLineEndY:Number = 0; + + //selected text draws with 2 px + if(imeStatus == IMEStatus.SELECTED_CONVERTED || imeStatus == IMEStatus.SELECTED_RAW) + { + imeLineThickness = 2; + } + //Raw or deadkey text draws with grey + if(imeStatus == IMEStatus.SELECTED_RAW || imeStatus == IMEStatus.NOT_SELECTED_RAW + || imeStatus == IMEStatus.DEAD_KEY_INPUT_STATE) + { + imeLineColor = 0xA6A6A6; + } + + var spanBounds:Rectangle = spanBoundsArray[i] as Rectangle; + var stOffset:Number = calculateStrikeThrough(element, tLine, blockProgression, metrics); + var ulOffset:Number = calculateUnderlineOffset(element, stOffset, blockProgression, metrics, tLine); + + if (blockProgression != BlockProgression.RL) + { + imeLineStartX = spanBounds.topLeft.x + 1; + imeLineEndX = spanBounds.topLeft.x + spanBounds.width - 1; + imeLineStartY = ulOffset; + imeLineEndY = ulOffset; + } + else + { + //is this TCY? + var line:ITextFlowLine = tLine.userData as ITextFlowLine; + var elemIdx:int = element.getAbsoluteStart() - line.absoluteStart; + imeLineStartY = spanBounds.topLeft.y + 1; + imeLineEndY = spanBounds.topLeft.y + spanBounds.height - 1; + + //elemIdx can sometimes be negative if the text is being wrapped due to a + //resize gesture - in which case the tLine has not necessarily been updated. + //If the elemIdx is invalid, just treat it like it's normal ttb text - gak 07.08.08 + if(elemIdx < 0 || tLine.atomCount <= elemIdx || tLine.getAtomTextRotation(elemIdx) != TextRotation.ROTATE_0) + { + imeLineStartX = ulOffset; + imeLineEndX = ulOffset; + } + else + { + //it is TCY! + var tcyParent:ITCYElement = element.getParentByType("TCYElement") as ITCYElement; + CONFIG::debug{ assert(tcyParent != null, "What kind of object is this that is ROTATE_0, but not TCY?");} + + //only perform calculations for TCY adornments when we are on the last leaf. ONLY the last leaf matters + if((element.getAbsoluteStart() + element.textLength) == (tcyParent.getAbsoluteStart() + tcyParent.textLength)) + { + var tcyAdornBounds:Rectangle = new Rectangle(); // NO PMD + calculateAdornmentBounds(tcyParent, tLine, blockProgression, tcyAdornBounds); + var baseULAdjustment:Number = metrics.underlineOffset + (metrics.underlineThickness/2); + + imeLineStartY = tcyAdornBounds.top + 1; + imeLineEndY = tcyAdornBounds.bottom - 1; + imeLineStartX = spanBounds.bottomRight.x + baseULAdjustment; + imeLineEndX = spanBounds.bottomRight.x + baseULAdjustment; + } + } + } + + //Build the shape + var selObj:ICompoundGraphic = element.getTextFlow().tlfFactory.getCompoundGraphic(); // NO PMD + //TODO - this is probably going to need to be overridable in the full implementation + selObj.alpha = 1; + selObj.fill = new SolidColor(imeLineColor); +// selObj.graphics.beginFill(imeLineColor); + + selObj.stroke = new SolidColorStroke(imeLineColor,imeLineThickness,selObj.alpha); +// selObj.graphics.lineStyle(imeLineThickness, imeLineColor, selObj.alpha); +// selObj.graphics.moveTo(imeLineStartX, imeLineStartY); +// selObj.graphics.lineTo(imeLineEndX, imeLineEndY); + var builder:PathBuilder = new PathBuilder(true); + builder.moveTo(imeLineStartX, imeLineStartY); + builder.lineTo(imeLineEndX, imeLineEndY); + selObj.drawPathCommands(builder); +// selObj.graphics.endFill(); + tLine.addElement(selObj); + } + } + + static public function calculateUnderlineOffset(element:IFlowLeafElement, stOffset:Number, blockProgression:String, metrics:FontMetrics, textLine:ITextLine):Number + { + if(element.className == "InlineGraphicElement" && IInlineGraphicElement(element).graphic && IInlineGraphicElement(element).status == InlineGraphicElementStatus.READY) + return calculateGraphicUnderlineOffset(IInlineGraphicElement(element), stOffset, blockProgression, metrics, textLine); + else + return calculateLeafUnderlineOffset(element, stOffset, blockProgression, metrics, textLine); + + } + + static private function calculateLeafUnderlineOffset(element:IFlowLeafElement, stOffset:Number, blockProgression:String, metrics:FontMetrics, textLine:ITextLine):Number + { + var ulOffset:Number = metrics.underlineOffset + metrics.underlineThickness; + var baseSTAdjustment:Number = metrics.strikethroughOffset; + + //based on the stOffset - which really represents the middle of the glyph, set the ulOffset + //which will always be relative. Note that simply using the alignDomBaselineAdjustment is not enough + if(blockProgression != BlockProgression.RL) + ulOffset += (stOffset - baseSTAdjustment) + metrics.underlineThickness/2; + else + { + var para:IParagraphElement = element.getParagraph(); + + if (para.computedFormat.locale.toLowerCase().indexOf("zh") == 0) + { + ulOffset = -ulOffset; + ulOffset -= (stOffset - baseSTAdjustment + (metrics.underlineThickness*2)); + } + else + ulOffset -= (-ulOffset + stOffset + baseSTAdjustment + (metrics.underlineThickness/2)); + } + + return ulOffset; + } + + /** + * @private + * @flexjsignorecoercion org.apache.flex.core.IParentIUIBase + */ + static private function calculateGraphicUnderlineOffset(element:IInlineGraphicElement, stOffset:Number, blockProgression:String, metrics:FontMetrics, tLine:ITextLine):Number + { + var para:IParagraphElement = element.getParagraph(); + var ulOffset:Number = 0; + var inlineHolder:IParentIUIBase = element.placeholderGraphic.parent as IParentIUIBase; + if (inlineHolder) + { + if(blockProgression == BlockProgression.TB) + ulOffset = inlineHolder.y + element.elementHeightWithMarginsAndPadding(); + else + { + if (para.computedFormat.locale.toLowerCase().indexOf("zh") == 0) + { + ulOffset = inlineHolder.x - element.elementHeightWithMarginsAndPadding(); + ulOffset -= metrics.underlineOffset + (metrics.underlineThickness/2); + return ulOffset; + } + else + ulOffset = inlineHolder.x - element.getEffectivePaddingLeft(); + } + } + ulOffset += metrics.underlineOffset + (metrics.underlineThickness/2); + + var justRule:String = para.getEffectiveJustificationRule(); + if(justRule == JustificationRule.EAST_ASIAN) + ulOffset += 1; + + return ulOffset; + } + + /** @private + * Adds the background rectangle (if needed), making adjustments for glyph shifting as appropriate + */ + static private function addBackgroundRect(element:IFlowLeafElement, tLine:ITextLine, metrics:FontMetrics, spanBounds:Rectangle, horizontalText:Boolean, isTCY:Boolean=false):void + { + if(element.computedFormat.backgroundAlpha == 0 || element.computedFormat.backgroundColor == BackgroundColor.TRANSPARENT) + return; + + var tf:ITextFlow = element.getTextFlow(); + // ensure the TextFlow has a background manager - but its only supported with the StandardFlowComposer at this time + if (!tf.getBackgroundManager()) + return; + + // The background rectangle usually needs to coincide with the passsed-in span bounds. + var r:Rectangle = spanBounds.clone(); + + // With constrained glyph shifting (such as when superscript/subscript are in use), we'd like the + // background rectangle to follow the glyphs. Not so for arbitrary glyph shifting (such as when + // baseline shift or baseline alignment are in use) + // TODO-06/12/2009: Need to figure out adjustment for TCY background rect. No adjustment for now. + if (!isTCY && (element.computedFormat.baselineShift == BaselineShift.SUPERSCRIPT || element.computedFormat.baselineShift == BaselineShift.SUBSCRIPT)) + { + // The atom bounds returned by FTE do not reflect the effect of glyph shifting. + // We approximate this effect by making the following assumptions (strikethrough/underline code does the same) + // - The strike-through adornment runs through the center of the glyph + // - The Roman baseline is halfway between the center and bottom (descent) + // Effectively, the glyph's descent equals the strike-through offset, and its ascent is three times that + + var desiredExtent:Number; // The desired extent of the rectangle in the block progression direction + var baselineShift:Number; + var fontSize:Number = element.getEffectiveFontSize(); + var baseStrikethroughOffset:Number = metrics.strikethroughOffset + metrics.strikethroughThickness/2; + + if (element.computedFormat.baselineShift == BaselineShift.SUPERSCRIPT) + { + // The rectangle needs to sit on the line's descent and must extend far enough to accommodate the + // ascender of the glyph (that has moved up because of superscript) + + var glyphAscent:Number = -3 * baseStrikethroughOffset; // see assumptions above + baselineShift = -metrics.superscriptOffset * fontSize; + var lineDescent:Number = tLine.getBaselinePosition(TextBaseline.DESCENT) - tLine.getBaselinePosition(TextBaseline.ROMAN); + + desiredExtent = glyphAscent + baselineShift + lineDescent; + if (horizontalText) + { + if (desiredExtent > r.height) + { + r.y -= desiredExtent - r.height; + r.height = desiredExtent; + } + } + else + { + if (desiredExtent > r.width) + r.width = desiredExtent; + } + } + else + { + // The rectangle needs to hang from the line's ascent and must extend far enough to accommodate the + // descender of the glyph (that has moved down because of superscript) + + var glyphDescent:Number = -baseStrikethroughOffset; // see assumptions above + baselineShift = metrics.subscriptOffset * fontSize; + var lineAscent:Number = tLine.getBaselinePosition(TextBaseline.ROMAN) - tLine.getBaselinePosition(TextBaseline.ASCENT); + + desiredExtent = lineAscent + baselineShift + glyphDescent; + if (horizontalText) + { + if (desiredExtent > r.height) + r.height = desiredExtent; + } + else + { + if (desiredExtent > r.width) + { + r.x -= desiredExtent - r.width; + r.width = desiredExtent; + } + } + } + } + + tf.backgroundManager.addRect(tLine, element, r, element.computedFormat.backgroundColor, element.computedFormat.backgroundAlpha); + } + + /** + * @private + * @flexjsignorecoercion org.apache.flex.core.IUIBase + * @flexjsignorecoercion org.apache.flex.textLayout.elements.IFlowLeafElement + */ + static public function calculateAdornmentBounds(spg:ISubParagraphGroupElementBase, tLine:ITextLine, blockProgression:String, spgRect:Rectangle):void + { + var childCount:int = 0; + while(childCount < spg.numChildren) + { + var curChild:IFlowElement = spg.getChildAt(childCount) as IFlowElement; + var curFlowLeaf:IFlowLeafElement = curChild as IFlowLeafElement; + if(!curFlowLeaf && curChild is ISubParagraphGroupElementBase) + { + calculateAdornmentBounds(curChild as ISubParagraphGroupElementBase, tLine, blockProgression, spgRect); + ++childCount; + continue; + } + + CONFIG::debug{ assert(curFlowLeaf != null, "The TCY contains a non-FlowLeafElement! Cannot calculate mirror!");} + var curBounds:Rectangle = null; + if(!(curFlowLeaf is IInlineGraphicElement)) + curBounds = getSpanBoundsOnLine(curFlowLeaf, tLine, blockProgression)[0]; + else + { + curBounds = BoundsUtil.getBounds(curFlowLeaf as IUIBase, tLine);// (curFlowLeaf as InlineGraphicElement).graphic.getBounds(tLine); + } + + if(childCount != 0) + { + if(curBounds.top < spgRect.top) + spgRect.top = curBounds.top; + + if(curBounds.bottom > spgRect.bottom) + spgRect.bottom = curBounds.bottom; + + if(spgRect.x > curBounds.x) + spgRect.x = curBounds.x; + } + else + { + spgRect.top = curBounds.top; + spgRect.bottom = curBounds.bottom; + spgRect.x = curBounds.x; + } + ++childCount; + } + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/ContextUtil.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/ContextUtil.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/ContextUtil.as new file mode 100644 index 0000000..5feb5b1 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/ContextUtil.as @@ -0,0 +1,31 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.compose.ISWFContext; + + public class ContextUtil + { + /** @private - helper function for finding a base swf context from a swf context */ + public static function computeBaseSWFContext(context:ISWFContext):ISWFContext + { + return context && Object(context).hasOwnProperty("getBaseSWFContext") ? context["getBaseSWFContext"]() : context; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/FactoryHelper.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/FactoryHelper.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/FactoryHelper.as new file mode 100644 index 0000000..4bb96b4 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/FactoryHelper.as @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.compose.IFactoryComposer; + import org.apache.flex.textLayout.compose.ISimpleCompose; + import org.apache.flex.textLayout.utils.FactoryUtil; + public class FactoryHelper + { + static public function getComposer():IFactoryComposer + { + if(!composerClass) + composerClass = FactoryUtil.getDefaultFlowComposerClass(); + + return new composerClass(); + } + static public var composerClass:Class; + static public var staticComposer:ISimpleCompose; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberLineUserData.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberLineUserData.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberLineUserData.as new file mode 100644 index 0000000..831c753 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberLineUserData.as @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.elements.IBackgroundManager; + import org.apache.flex.textLayout.formats.ITextLayoutFormat; + + public class NumberLineUserData + { + public function NumberLineUserData(listStylePosition:String, insideLineWidth:Number, spanFormat:ITextLayoutFormat, paraDirection:String) + { + this.listStylePosition = listStylePosition; + // added by yong + this.insideLineWidth = insideLineWidth; + this.spanFormat = spanFormat; + this.paragraphDirection = paraDirection; + } + + public var listStylePosition:String; + public var insideLineWidth:Number; + public var spanFormat:ITextLayoutFormat; + public var paragraphDirection:String; + public var listEndIndent:Number; + public var backgroundManager:IBackgroundManager; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberlineUtil.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberlineUtil.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberlineUtil.as new file mode 100644 index 0000000..d82bca3 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/NumberlineUtil.as @@ -0,0 +1,160 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.utils.NumberFactoryUtil; + import org.apache.flex.core.UIBase; + import org.apache.flex.geom.Rectangle; + import org.apache.flex.text.engine.ITextLine; + import org.apache.flex.textLayout.compose.ISWFContext; + import org.apache.flex.textLayout.compose.SWFContext; + import org.apache.flex.textLayout.debug.assert; + import org.apache.flex.textLayout.elements.IFlowLeafElement; + import org.apache.flex.textLayout.elements.ILinkElement; + import org.apache.flex.textLayout.elements.IListElement; + import org.apache.flex.textLayout.elements.IListItemElement; + import org.apache.flex.textLayout.elements.IParagraphElement; + import org.apache.flex.textLayout.elements.LinkState; + import org.apache.flex.textLayout.factory.INumberLineFactory; + import org.apache.flex.textLayout.formats.Direction; + import org.apache.flex.textLayout.formats.FormatValue; + import org.apache.flex.textLayout.formats.IListMarkerFormat; + import org.apache.flex.textLayout.formats.ListStylePosition; + import org.apache.flex.textLayout.formats.TextLayoutFormat; + + public class NumberlineUtil + { + static private var numberLineFactory:INumberLineFactory; + + /** + * + * @private Logic to generate and position the ITextLine containing the numbering for a listElement's first line + * @flexjsignorecoercion org.apache.flex.textLayout.elements.ILinkElement + * @flexjsignorecoercion org.apache.flex.textLayout.elements.IListElement + */ + static public function createNumberLine(listItemElement:IListItemElement, curParaElement:IParagraphElement, swfContext:ISWFContext, totalStartIndent:Number):ITextLine + { + CONFIG::debug + { + assert(swfContext != SWFContext.globalSWFContext, "TextFlowLine.createNumberLine: don't pass globalswfcontext"); } + if (numberLineFactory == null) + { + numberLineFactory = NumberFactoryUtil.getNumberFactory(); + numberLineFactory.compositionBounds = new Rectangle(0, 0, NaN, NaN); + } + numberLineFactory.swfContext = swfContext; + + var listMarkerFormat:IListMarkerFormat = listItemElement.computedListMarkerFormat(); + + // use the listStylePosition on the ListItem (not the list) + numberLineFactory.listStylePosition = listItemElement.computedFormat.listStylePosition; + + var listElement:IListElement = listItemElement.parent as IListElement; + var paragraphFormat:TextLayoutFormat = new TextLayoutFormat(curParaElement.computedFormat); + var boxStartIndent:Number = paragraphFormat.direction == Direction.LTR ? listElement.getEffectivePaddingLeft() + listElement.getEffectiveBorderLeftWidth() + listElement.getEffectiveMarginLeft() : listElement.getEffectivePaddingRight() + listElement.getEffectiveBorderRightWidth() + listElement.getEffectiveMarginRight(); + // this just gets the first line but that's the only one we use. could have used paragraphStartIndent or padding/margins. + // do it this way so that negative indents are supported. TODO revisit when box model work is complete + paragraphFormat.apply(listMarkerFormat); + // Fix bug 2800975 ListMarkerFormat.paragraphStartIndent not applied properly in Inside lists. + paragraphFormat.textIndent += totalStartIndent; + if (numberLineFactory.listStylePosition == ListStylePosition.OUTSIDE) + paragraphFormat.textIndent -= boxStartIndent; + numberLineFactory.paragraphFormat = paragraphFormat; // curParaElement.computedFormat; + numberLineFactory.textFlowFormat = curParaElement.getTextFlow().computedFormat; + + // suppress the formatting of any links + var firstLeaf:IFlowLeafElement = curParaElement.getFirstLeaf(); + var parentLink:ILinkElement = firstLeaf.getParentByType("LinkElement") as ILinkElement; + // record the topmost parent link + var highestParentLinkLinkElement:ILinkElement; + var linkStateArray:Array = []; + while (parentLink) + { + highestParentLinkLinkElement = parentLink; + linkStateArray.push(parentLink.linkState); + parentLink.chgLinkState(LinkState.SUPPRESSED); + parentLink = parentLink.getParentByType("LinkElement") as ILinkElement; + } + + // spanFormat to use for the markers + var spanFormat:TextLayoutFormat = new TextLayoutFormat(firstLeaf.computedFormat); + + // now restore the formatting of any links + parentLink = firstLeaf.getParentByType("LinkElement") as ILinkElement; + while (parentLink) + { + linkStateArray.push(parentLink.linkState); + parentLink.chgLinkState(linkStateArray.shift()); + parentLink = parentLink.getParentByType("LinkElement") as ILinkElement; + } + + // forces recompute of computedFormat of all leaf nodes of highestParentLinkLinkElement + if (highestParentLinkLinkElement) + { + var leaf:IFlowLeafElement = highestParentLinkLinkElement.getFirstLeaf(); + while (leaf) + { + leaf.calculateComputedFormat(); + leaf = leaf.getNextLeaf(highestParentLinkLinkElement); + } + } + + // finalize the spanFormat for the marker + var markerFormat:TextLayoutFormat = new TextLayoutFormat(spanFormat); + TextLayoutFormat.resetModifiedNoninheritedStyles(markerFormat); + var holderStyles:Object = (listMarkerFormat as TextLayoutFormat).getStyles(); + for (var key:String in holderStyles) + { + // only copy TextLayoutFormat properties + if (TextLayoutFormat.description[key] !== undefined) + { + var val:* = holderStyles[key]; + markerFormat[key] = (val !== FormatValue.INHERIT) ? val : spanFormat[key]; + } + } + numberLineFactory.markerFormat = markerFormat; + numberLineFactory.text = listElement.computeListItemText(listItemElement, listMarkerFormat); + + // expect one or zero lines - technically with beforeContent and afterContent more than one line can be generated. This could be more like a float!! + // also need to expect a backgroundColor + var rslt:Array = []; + numberLineFactory.createTextLines(function(o:UIBase):void + { + rslt.push(o); + }); + + // position it relative to the parent line - later need to take inside/outside into account + var numberLine:ITextLine = rslt[0] as ITextLine; + if (numberLine) + { + CONFIG::debug + { + assert(numberLine.validity == "static", "Invalid validity on numberLine"); } + // TODO deal with mouseEnabled and mouseChildren + // numberLine.mouseEnabled = false; + // numberLine.mouseChildren = false; + TextLineUtil.setNumberLineBackground(numberLine, numberLineFactory.backgroundManager); + } + numberLineFactory.clearBackgroundManager(); + + return numberLine; + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/StandardHelper.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/StandardHelper.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/StandardHelper.as new file mode 100644 index 0000000..c197b22 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/StandardHelper.as @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.textLayout.compose.IFlowComposer; + import org.apache.flex.textLayout.compose.StandardFlowComposer; + + public class StandardHelper + { + static public function getStandardClass():Class + { + return StandardFlowComposer; + } + static public function getNewComposer():IFlowComposer + { + return new StandardFlowComposer(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/fd08d137/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/TextLineUtil.as ---------------------------------------------------------------------- diff --git a/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/TextLineUtil.as b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/TextLineUtil.as new file mode 100644 index 0000000..52a0bd2 --- /dev/null +++ b/frameworks/projects/TLF/src/main/flex/org/apache/flex/textLayout/compose/utils/TextLineUtil.as @@ -0,0 +1,172 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 org.apache.flex.textLayout.compose.utils +{ + import org.apache.flex.text.engine.ITextLine; + import org.apache.flex.textLayout.debug.assert; + import org.apache.flex.textLayout.elements.IBackgroundManager; + import org.apache.flex.textLayout.elements.IFlowLeafElement; + import org.apache.flex.textLayout.elements.IInlineGraphicElement; + import org.apache.flex.textLayout.elements.IListItemElement; + import org.apache.flex.textLayout.elements.IParagraphElement; + import org.apache.flex.textLayout.formats.BlockProgression; + import org.apache.flex.textLayout.formats.Direction; + import org.apache.flex.textLayout.formats.FormatValue; + import org.apache.flex.textLayout.formats.IListMarkerFormat; + import org.apache.flex.textLayout.formats.ITextLayoutFormat; + import org.apache.flex.textLayout.formats.ListStylePosition; + + public class TextLineUtil + { + /** @private */ + static public function findNumberLine(textLine:ITextLine):ITextLine + { + if (textLine == null) + return null; + // not always going to be a numberLine - listStyleType may be "none" + // have to hunt for it because inlinegraphics get pushed at the beginning + // risk here is that clients decorate TextLines with other TextLines. + for (var idx:int = 0; idx < textLine.numElements; idx++) + { + var numberLine:ITextLine = textLine.getElementAt(idx) as ITextLine; + if (numberLine && (numberLine.userData is NumberLineUserData)) + break; + } + return numberLine; + } + + /** @private */ + static public function getNumberLineListStylePosition(numberLine:ITextLine):String + { + return (numberLine.userData as NumberLineUserData).listStylePosition; + } + + /** @private */ + static public function getNumberLineInsideLineWidth(numberLine:ITextLine):Number + { + return (numberLine.userData as NumberLineUserData).insideLineWidth; + } + + /** @private */ + static public function getNumberLineSpanFormat(numberLine:ITextLine):ITextLayoutFormat + { + return (numberLine.userData as NumberLineUserData).spanFormat; + } + + /** @private */ + static public function getNumberLineParagraphDirection(numberLine:ITextLine):String + { + return (numberLine.userData as NumberLineUserData).paragraphDirection; + } + + /** @private */ + static public function setListEndIndent(numberLine:ITextLine, listEndIndent:Number):void + { + (numberLine.userData as NumberLineUserData).listEndIndent = listEndIndent; + } + + /** @private */ + static public function getListEndIndent(numberLine:ITextLine):Number + { + return (numberLine.userData as NumberLineUserData).listEndIndent; + } + + /** @private */ + static public function setNumberLineBackground(numberLine:ITextLine, background:IBackgroundManager):void + { + (numberLine.userData as NumberLineUserData).backgroundManager = background; + } + + /** @private */ + static public function getNumberLineBackground(numberLine:ITextLine):IBackgroundManager + { + return (numberLine.userData as NumberLineUserData).backgroundManager; + } + + /** @private */ + static public function initializeNumberLinePosition(numberLine:ITextLine, listItemElement:IListItemElement, curParaElement:IParagraphElement, totalWidth:Number):void + { + // use the listStylePosition on the ListItem (not the list) + var listMarkerFormat:IListMarkerFormat = listItemElement.computedListMarkerFormat(); + var paragraphFormat:ITextLayoutFormat = curParaElement.computedFormat; + // only applies on outside list markers + var listEndIndent:Number = listMarkerFormat.paragraphEndIndent === undefined || listItemElement.computedFormat.listStylePosition == ListStylePosition.INSIDE ? 0 : (listMarkerFormat.paragraphEndIndent == FormatValue.INHERIT ? paragraphFormat.paragraphEndIndent : listMarkerFormat.paragraphEndIndent); + + TextLineUtil.setListEndIndent(numberLine, listEndIndent); + + // no more work needed for OUTSIDE positioning - its all done in the applyTextAlign code + if (listItemElement.computedFormat.listStylePosition == ListStylePosition.OUTSIDE) + { + numberLine.x = numberLine.y = 0; + return; + } + + var bp:String = curParaElement.getTextFlow().computedFormat.blockProgression; + var numberLineWidth:Number = TextLineUtil.getNumberLineInsideLineWidth(numberLine); + + if (bp == BlockProgression.TB) + { + if (paragraphFormat.direction == Direction.LTR) + numberLine.x = -numberLineWidth; + else + numberLine.x = totalWidth + numberLineWidth - numberLine.textWidth; + numberLine.y = 0; // assumes same baseline as parent!! + } + else + { + if (paragraphFormat.direction == Direction.LTR) + numberLine.y = -numberLineWidth; + else + numberLine.y = totalWidth + numberLineWidth - numberLine.textWidth; + numberLine.x = 0; // assumes same baseline as parent!! + } + } + + /** @private + * Scan through the format runs within the line, and figure out what the typographic ascent (i.e. ascent relative to the + * Roman baseline) for the overall line is. Normally it is the distance between the Roman and Ascent baselines, + * but it may be adjusted upwards by the width/height of the GraphicElement. + */ + static public function getTextLineTypographicAscent(textLine:ITextLine, elem:IFlowLeafElement, elemStart:int, textLineEnd:int):Number + { + CONFIG::debug + { + assert(!elem || elemStart == elem.getAbsoluteStart(), "bad elemStart passed to getTextLineTypographicAscent"); } + var rslt:Number = textLine.getBaselinePosition(org.apache.flex.text.engine.TextBaseline.ROMAN) - textLine.getBaselinePosition(org.apache.flex.text.engine.TextBaseline.ASCENT); + + if (textLine.hasGraphicElement) + { + for (;;) + { + if (elem is IInlineGraphicElement) + rslt = Math.max(rslt, IInlineGraphicElement(elem).getTypographicAscent(textLine)); + elemStart += elem.textLength; + if (elemStart >= textLineEnd) + break; + elem = elem.getNextLeaf(); + CONFIG::debug + { + assert(elem != null, "bad nextLeaf"); } + } + } + return rslt; + } + + } +} \ No newline at end of file