Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Documents / FlowPosition.cs / 1 / FlowPosition.cs
//---------------------------------------------------------------------------- //// Copyright (C) 2003 by Microsoft Corporation. All rights reserved. // // // Description: // FlowPosition represents a navigational position in a document's content flow. // // History: // 02/10/2003 - Zhenbin Xu (ZhenbinX) - Created. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using MS.Internal.Documents; using System; using System.Collections; using System.Diagnostics; using System.Globalization; using System.Windows.Controls; //===================================================================== ////// FlowPosition represents a navigational position in a document's content flow. /// ////// A FlowPosition is represented by a FlowNode in the backing store and offset within /// the flow node (starts with 0, on the left side of the symbol). e.g. /// <P> H A L </P> /// 0 1 0 1 2 3 0 1 /// internal sealed class FlowPosition : IComparable { //------------------------------------------------------------------- // // Connstructors // //---------------------------------------------------------------------- #region Constructors internal FlowPosition(FixedTextContainer container, FlowNode node, int offset) { Debug.Assert(!FlowNode.IsNull(node)); _container = container; _flowNode = node; _offset = offset; } #endregion Constructors //------------------------------------------------------------------- // // Public Methods // //---------------------------------------------------------------------- #region Public Methods ////// Create a shallow copy of this objet /// ///A clone of this FlowPosition public object Clone() { return new FlowPosition(_container, _flowNode, _offset); } // Compare two FixedTextPointer based on their flow order and offset public int CompareTo(object o) { if (o == null) { throw new ArgumentNullException("o"); } FlowPosition flow = o as FlowPosition; if (flow == null) { throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, o.GetType(), typeof(FlowPosition)), "o"); } return _OverlapAwareCompare(flow); } ////// Compute hash code. A flow position is predominantly identified /// by its flow node and the offset. /// ///int - hash code public override int GetHashCode() { return _flowNode.GetHashCode()^_offset.GetHashCode(); } #if DEBUG ////// Create a string representation of this object /// ///string - A string representation of this object public override string ToString() { return String.Format(CultureInfo.InvariantCulture, "FP[{0}+{1}]", _flowNode, _offset); } #endif #endregion Public Methods //-------------------------------------------------------------------- // // Public Properties // //--------------------------------------------------------------------- //-------------------------------------------------------------------- // // Public Events // //--------------------------------------------------------------------- //------------------------------------------------------------------- // // Internal Methods // //--------------------------------------------------------------------- #region Internal Methods //-------------------------------------------------------------------- // Text OM Helper //--------------------------------------------------------------------- #region Text OM Helper // Returns the count of symbols between pos1 and pos2 internal int GetDistance(FlowPosition flow) { Debug.Assert(flow != null); // if both clings to the same flow node, simply // compare the offset if (_flowNode.Equals(flow._flowNode)) { return flow._offset - _offset; } // otherwise scan to find out distance // Make sure scanning from low to high flow order int np = _OverlapAwareCompare(flow); FlowPosition flowScan, flowEnd; if (np == -1) { // scan forward flowScan = (FlowPosition)this.Clone(); flowEnd = flow; } else { // scan backward flowScan = (FlowPosition)flow.Clone(); flowEnd = this; } // scan from low to high and accumulate counts // devirtualize the node as it scans int distance = 0; while (!flowScan._IsSamePosition(flowEnd)) { if (flowScan._flowNode.Equals(flowEnd._flowNode)) { distance += (flowEnd._offset - flowScan._offset); break; } int scan = flowScan._vScan(LogicalDirection.Forward, -1); distance += scan; } return np * (-1) * distance; } // Returns TextPointerContext.None if query is Backward at TextContainer.Start or Forward at TetContainer.End internal TextPointerContext GetPointerContext(LogicalDirection dir) { Debug.Assert(dir == LogicalDirection.Forward || dir == LogicalDirection.Backward); return _vGetSymbolType(dir); } // returns remaining text length on dir internal int GetTextRunLength(LogicalDirection dir) { Debug.Assert(GetPointerContext(dir) == TextPointerContext.Text); FlowPosition flow = GetClingPosition(dir); if (dir == LogicalDirection.Forward) { return flow._NodeLength - flow._offset; } else { return flow._offset; } } // Get Text until end-of-run or maxLength/limit is hit. internal int GetTextInRun(LogicalDirection dir, int maxLength, char[] chars, int startIndex) { Debug.Assert(GetPointerContext(dir) == TextPointerContext.Text); // make sure the position is clinged to text run FlowPosition flow = GetClingPosition(dir); int runLength = flow._NodeLength; int remainingLength; if (dir == LogicalDirection.Forward) { remainingLength = runLength - flow._offset; } else { remainingLength = flow._offset; } maxLength = Math.Min(maxLength, remainingLength); // // string text = _container.FixedTextBuilder.GetFlowText(flow._flowNode); if (dir == LogicalDirection.Forward) { Array.Copy(text.ToCharArray(flow._offset, maxLength), 0, chars, startIndex, maxLength); } else { Array.Copy(text.ToCharArray(flow._offset - maxLength, maxLength), 0, chars, startIndex, maxLength); } return maxLength; } // Get Embedeed Object instance internal object GetAdjacentElement(LogicalDirection dir) { FlowPosition flow = GetClingPosition(dir); FlowNodeType type = flow._flowNode.Type; Debug.Assert(type == FlowNodeType.Object || type == FlowNodeType.Noop || type == FlowNodeType.Start || type == FlowNodeType.End); if (type == FlowNodeType.Noop) { return String.Empty; } else { Object obj = ((FixedElement)flow._flowNode.Cookie).GetObject(); Image image = obj as Image; if (type == FlowNodeType.Object && image != null) { //Set width and height properties by looking at corresponding SOMImage FixedSOMElement[] elements = flow._flowNode.FixedSOMElements; if (elements != null && elements.Length > 0) { FixedSOMImage somImage = elements[0] as FixedSOMImage; if (somImage != null) { image.Width = somImage.BoundingRect.Width; image.Height = somImage.BoundingRect.Height; } } } return obj; } } // return FixedElement on the direction internal FixedElement GetElement(LogicalDirection dir) { FlowPosition flow = GetClingPosition(dir); return (FixedElement)flow._flowNode.Cookie; } // Immediate scoping element. If no element scops the position, // returns the container element. internal FixedElement GetScopingElement() { FlowPosition flowScan = (FlowPosition)this.Clone(); int nestedElement = 0; TextPointerContext tst; while (flowScan.FlowNode.Fp > 0 && !IsVirtual(_FixedFlowMap[flowScan.FlowNode.Fp - 1]) && // do not de-virtualize nodes (tst = flowScan.GetPointerContext(LogicalDirection.Backward))!= TextPointerContext.None) { if (tst == TextPointerContext.ElementStart) { if (nestedElement == 0) { FlowPosition flowEnd = flowScan.GetClingPosition(LogicalDirection.Backward); return (FixedElement)flowEnd._flowNode.Cookie; } nestedElement--; } else if (tst == TextPointerContext.ElementEnd) { nestedElement++; } flowScan.Move(LogicalDirection.Backward); } return _container.ContainerElement; } // return false if distance exceeds the size of the document internal bool Move(int distance) { LogicalDirection dir = (distance >= 0 ? LogicalDirection.Forward : LogicalDirection.Backward); distance = Math.Abs(distance); FlowNode startNode = _flowNode; // save state int startOffset = _offset; // keep moving until we hit distance while (distance > 0) { int scan = _vScan(dir, distance); if (scan == 0) { //restore state and return false _flowNode = startNode; _offset = startOffset; return false; } distance -= scan; } return true; } // Skip current symbol or run internal bool Move(LogicalDirection dir) { if (_vScan(dir, -1) > 0) { return true; } return false; } // Move to next FlowPosition internal void MoveTo(FlowPosition flow) { _flowNode = flow._flowNode; _offset = flow._offset; } #endregion Text OM Helper //-------------------------------------------------------------------- // Internal Methods //---------------------------------------------------------------------- internal void AttachElement(FixedElement e) { _flowNode.AttachElement(e); } internal void GetFlowNode(LogicalDirection direction, out FlowNode flowNode, out int offsetStart) { FlowPosition fp = GetClingPosition(direction); offsetStart = fp._offset; flowNode = fp._flowNode; } // return FlowNode within this range internal void GetFlowNodes(FlowPosition pEnd, out FlowNode[] flowNodes, out int offsetStart, out int offsetEnd) { Debug.Assert(this._OverlapAwareCompare(pEnd) < 0); flowNodes = null; offsetStart = 0; offsetEnd = 0; FlowPosition flowScan = GetClingPosition(LogicalDirection.Forward); offsetStart = flowScan._offset; ArrayList ar = new ArrayList(); int distance = GetDistance(pEnd); // keep moving until we hit distance while (distance > 0) { int scan = flowScan._vScan(LogicalDirection.Forward, distance); distance -= scan; if (flowScan.IsRun || flowScan.IsObject) { ar.Add(flowScan._flowNode); offsetEnd = flowScan._offset; } } flowNodes = (FlowNode [])ar.ToArray(typeof(FlowNode)); } // A canonical position is one that clings to a FlowNode internal FlowPosition GetClingPosition(LogicalDirection dir) { FlowPosition flow = (FlowPosition)this.Clone(); FlowNode fn; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength) { // This position is at right side of a FlowNode // look for next run fn = _xGetNextFlowNode(); if (!FlowNode.IsNull(fn)) { flow._flowNode = fn; flow._offset = 0; } #if DEBUG else { DocumentsTrace.FixedTextOM.FlowPosition.Trace("GetClingPosition: Next FlowNode is null"); } #endif } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0) { // This position is at left side of a FlowNode // look for previous run fn = _xGetPreviousFlowNode(); if (!FlowNode.IsNull(fn)) { flow._flowNode = fn; flow._offset = flow._NodeLength; } #if DEBUG else { DocumentsTrace.FixedTextOM.FlowPosition.Trace("GetClingPosition: Next FlowNode is null"); } #endif } } return flow; } internal bool IsVirtual(FlowNode flowNode) { return (flowNode.Type == FlowNodeType.Virtual); } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //---------------------------------------------------------------------- #region Internal Properties internal FixedTextContainer TextContainer { get { return _container; } } internal bool IsBoundary { get { return (_flowNode.Type == FlowNodeType.Boundary); } } internal bool IsStart { get { return (_flowNode.Type == FlowNodeType.Start); } } internal bool IsEnd { get { return (_flowNode.Type == FlowNodeType.End); } } // If th_Is position _Is symbol internal bool IsSymbol { get { FlowNodeType t = _flowNode.Type; return (t == FlowNodeType.Start || t == FlowNodeType.End || t == FlowNodeType.Object); } } // If the FlowNode has run length internal bool IsRun { get { return (_flowNode.Type == FlowNodeType.Run); } } // If the FlowNode has run length internal bool IsObject { get { return (_flowNode.Type == FlowNodeType.Object); } } internal FlowNode FlowNode { get { return this._flowNode; } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //--------------------------------------------------------------------- #region Private Methods //------------------------------------------------------------------- // Helper functions that could result in de-virtualization //---------------------------------------------------------------------- // scan one node forward, return characters/symbols passed // limit < 0 means scan entire node. private int _vScan(LogicalDirection dir, int limit) { if (limit == 0) { return 0; } FlowNode flowNode = _flowNode; int scanned = 0; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength || flowNode.Type == FlowNodeType.Boundary) { // This position is at right side of a FlowNode flowNode = _xGetNextFlowNode(); if (FlowNode.IsNull(flowNode)) { return scanned; } _flowNode = flowNode; scanned = _NodeLength; } else { scanned = _NodeLength - _offset; } _offset = _NodeLength; if (limit > 0 && scanned > limit) { int back = scanned - limit; scanned = limit; _offset -= back; } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0 || flowNode.Type == FlowNodeType.Boundary) { // This position is at left side of a FlowNode // look for previous run flowNode = _xGetPreviousFlowNode(); if (FlowNode.IsNull(flowNode)) { return scanned; } _flowNode = flowNode; scanned = _NodeLength; } else { scanned = _offset; } _offset = 0; if (limit > 0 && scanned > limit) { int back = scanned - limit; scanned = limit; _offset += back; } } return scanned; } private TextPointerContext _vGetSymbolType(LogicalDirection dir) { FlowNode flowNode = _flowNode; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength) { // This position is at right side of a FlowNode // look for next run flowNode = _xGetNextFlowNode(); } if (!FlowNode.IsNull(flowNode)) { return _FlowNodeTypeToTextSymbol(flowNode.Type); } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0) { // This position is at left side of a FlowNode // look for previous run flowNode = _xGetPreviousFlowNode(); } if (!FlowNode.IsNull(flowNode)) { return _FlowNodeTypeToTextSymbol(flowNode.Type); } } return TextPointerContext.None; } //------------------------------------------------------------------- // Helper functions that have raw access to backing store and provided // a non-virtualied view on top of virtualized content. //---------------------------------------------------------------------- // return null if no previous node private FlowNode _xGetPreviousFlowNode() { if (_flowNode.Fp > 1) { FlowNode flow = _FixedFlowMap[_flowNode.Fp - 1]; // devirtualize the backing store if (IsVirtual(flow)) { _FixedTextBuilder.EnsureTextOMForPage((int)flow.Cookie); flow = _FixedFlowMap[_flowNode.Fp - 1]; } // filter out boundary node if (flow.Type != FlowNodeType.Boundary) { return flow; } } return null; } // return null if no next node private FlowNode _xGetNextFlowNode() { if (_flowNode.Fp < _FixedFlowMap.FlowCount - 1) { FlowNode flow = _FixedFlowMap[_flowNode.Fp + 1]; // devirtualize the backing store if (IsVirtual(flow)) { _FixedTextBuilder.EnsureTextOMForPage((int)flow.Cookie); flow = _FixedFlowMap[_flowNode.Fp + 1]; } // filter out boundary node if (flow.Type != FlowNodeType.Boundary) { return flow; } } return null; } //-------------------------------------------------------------------- // Helper functions //--------------------------------------------------------------------- // see if the two FlowPosition are indeed same position private bool _IsSamePosition(FlowPosition flow) { if (flow == null) { return false; } return (_OverlapAwareCompare(flow) == 0); } // intelligent compare routine that understands position overlap private int _OverlapAwareCompare(FlowPosition flow) { Debug.Assert(flow != null); if ((object)this == (object)flow) { return 0; } int comp = this._flowNode.CompareTo(flow._flowNode); if (comp < 0) { // Check overlap positions // Positions are the same if they are at end of previous run or begin of next run if (this._flowNode.Fp == flow._flowNode.Fp - 1 && this._offset == _NodeLength && flow._offset == 0) { return 0; } } else if (comp > 0) { // Check overlap positions // Positions are the same if they are at end of previous run or begin of next run if (flow._flowNode.Fp == this._flowNode.Fp - 1 && flow._offset == flow._NodeLength && this._offset == 0) { return 0; } } else { // compare offset only Debug.Assert(this._flowNode.Equals(flow._flowNode)); comp = this._offset.CompareTo(flow._offset); } return comp; } // Convert Flow Node Type to TextPointerContext private TextPointerContext _FlowNodeTypeToTextSymbol(FlowNodeType t) { switch (t) { case FlowNodeType.Start: return TextPointerContext.ElementStart; case FlowNodeType.End: return TextPointerContext.ElementEnd; case FlowNodeType.Run: return TextPointerContext.Text; case FlowNodeType.Object: case FlowNodeType.Noop: return TextPointerContext.EmbeddedElement; default: return TextPointerContext.None; } } #endregion Private Methods //-------------------------------------------------------------------- // // Private Properties // //--------------------------------------------------------------------- #region Private Properties // Get length of this node structure private int _NodeLength { get { if (IsRun) { return (int)_flowNode.Cookie; } else { return 1; } } } private FixedTextBuilder _FixedTextBuilder { get { return _container.FixedTextBuilder; } } private FixedFlowMap _FixedFlowMap { get { return _container.FixedTextBuilder.FixedFlowMap; } } #endregion Private Properties //------------------------------------------------------------------- // // Private Fields // //--------------------------------------------------------------------- #region Private Fields private FixedTextContainer _container; // the container has the backing store for flow nodes private FlowNode _flowNode; // flow node private int _offset; // offset into flow #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- //// Copyright (C) 2003 by Microsoft Corporation. All rights reserved. // // // Description: // FlowPosition represents a navigational position in a document's content flow. // // History: // 02/10/2003 - Zhenbin Xu (ZhenbinX) - Created. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using MS.Internal.Documents; using System; using System.Collections; using System.Diagnostics; using System.Globalization; using System.Windows.Controls; //===================================================================== ////// FlowPosition represents a navigational position in a document's content flow. /// ////// A FlowPosition is represented by a FlowNode in the backing store and offset within /// the flow node (starts with 0, on the left side of the symbol). e.g. /// <P> H A L </P> /// 0 1 0 1 2 3 0 1 /// internal sealed class FlowPosition : IComparable { //------------------------------------------------------------------- // // Connstructors // //---------------------------------------------------------------------- #region Constructors internal FlowPosition(FixedTextContainer container, FlowNode node, int offset) { Debug.Assert(!FlowNode.IsNull(node)); _container = container; _flowNode = node; _offset = offset; } #endregion Constructors //------------------------------------------------------------------- // // Public Methods // //---------------------------------------------------------------------- #region Public Methods ////// Create a shallow copy of this objet /// ///A clone of this FlowPosition public object Clone() { return new FlowPosition(_container, _flowNode, _offset); } // Compare two FixedTextPointer based on their flow order and offset public int CompareTo(object o) { if (o == null) { throw new ArgumentNullException("o"); } FlowPosition flow = o as FlowPosition; if (flow == null) { throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, o.GetType(), typeof(FlowPosition)), "o"); } return _OverlapAwareCompare(flow); } ////// Compute hash code. A flow position is predominantly identified /// by its flow node and the offset. /// ///int - hash code public override int GetHashCode() { return _flowNode.GetHashCode()^_offset.GetHashCode(); } #if DEBUG ////// Create a string representation of this object /// ///string - A string representation of this object public override string ToString() { return String.Format(CultureInfo.InvariantCulture, "FP[{0}+{1}]", _flowNode, _offset); } #endif #endregion Public Methods //-------------------------------------------------------------------- // // Public Properties // //--------------------------------------------------------------------- //-------------------------------------------------------------------- // // Public Events // //--------------------------------------------------------------------- //------------------------------------------------------------------- // // Internal Methods // //--------------------------------------------------------------------- #region Internal Methods //-------------------------------------------------------------------- // Text OM Helper //--------------------------------------------------------------------- #region Text OM Helper // Returns the count of symbols between pos1 and pos2 internal int GetDistance(FlowPosition flow) { Debug.Assert(flow != null); // if both clings to the same flow node, simply // compare the offset if (_flowNode.Equals(flow._flowNode)) { return flow._offset - _offset; } // otherwise scan to find out distance // Make sure scanning from low to high flow order int np = _OverlapAwareCompare(flow); FlowPosition flowScan, flowEnd; if (np == -1) { // scan forward flowScan = (FlowPosition)this.Clone(); flowEnd = flow; } else { // scan backward flowScan = (FlowPosition)flow.Clone(); flowEnd = this; } // scan from low to high and accumulate counts // devirtualize the node as it scans int distance = 0; while (!flowScan._IsSamePosition(flowEnd)) { if (flowScan._flowNode.Equals(flowEnd._flowNode)) { distance += (flowEnd._offset - flowScan._offset); break; } int scan = flowScan._vScan(LogicalDirection.Forward, -1); distance += scan; } return np * (-1) * distance; } // Returns TextPointerContext.None if query is Backward at TextContainer.Start or Forward at TetContainer.End internal TextPointerContext GetPointerContext(LogicalDirection dir) { Debug.Assert(dir == LogicalDirection.Forward || dir == LogicalDirection.Backward); return _vGetSymbolType(dir); } // returns remaining text length on dir internal int GetTextRunLength(LogicalDirection dir) { Debug.Assert(GetPointerContext(dir) == TextPointerContext.Text); FlowPosition flow = GetClingPosition(dir); if (dir == LogicalDirection.Forward) { return flow._NodeLength - flow._offset; } else { return flow._offset; } } // Get Text until end-of-run or maxLength/limit is hit. internal int GetTextInRun(LogicalDirection dir, int maxLength, char[] chars, int startIndex) { Debug.Assert(GetPointerContext(dir) == TextPointerContext.Text); // make sure the position is clinged to text run FlowPosition flow = GetClingPosition(dir); int runLength = flow._NodeLength; int remainingLength; if (dir == LogicalDirection.Forward) { remainingLength = runLength - flow._offset; } else { remainingLength = flow._offset; } maxLength = Math.Min(maxLength, remainingLength); // // string text = _container.FixedTextBuilder.GetFlowText(flow._flowNode); if (dir == LogicalDirection.Forward) { Array.Copy(text.ToCharArray(flow._offset, maxLength), 0, chars, startIndex, maxLength); } else { Array.Copy(text.ToCharArray(flow._offset - maxLength, maxLength), 0, chars, startIndex, maxLength); } return maxLength; } // Get Embedeed Object instance internal object GetAdjacentElement(LogicalDirection dir) { FlowPosition flow = GetClingPosition(dir); FlowNodeType type = flow._flowNode.Type; Debug.Assert(type == FlowNodeType.Object || type == FlowNodeType.Noop || type == FlowNodeType.Start || type == FlowNodeType.End); if (type == FlowNodeType.Noop) { return String.Empty; } else { Object obj = ((FixedElement)flow._flowNode.Cookie).GetObject(); Image image = obj as Image; if (type == FlowNodeType.Object && image != null) { //Set width and height properties by looking at corresponding SOMImage FixedSOMElement[] elements = flow._flowNode.FixedSOMElements; if (elements != null && elements.Length > 0) { FixedSOMImage somImage = elements[0] as FixedSOMImage; if (somImage != null) { image.Width = somImage.BoundingRect.Width; image.Height = somImage.BoundingRect.Height; } } } return obj; } } // return FixedElement on the direction internal FixedElement GetElement(LogicalDirection dir) { FlowPosition flow = GetClingPosition(dir); return (FixedElement)flow._flowNode.Cookie; } // Immediate scoping element. If no element scops the position, // returns the container element. internal FixedElement GetScopingElement() { FlowPosition flowScan = (FlowPosition)this.Clone(); int nestedElement = 0; TextPointerContext tst; while (flowScan.FlowNode.Fp > 0 && !IsVirtual(_FixedFlowMap[flowScan.FlowNode.Fp - 1]) && // do not de-virtualize nodes (tst = flowScan.GetPointerContext(LogicalDirection.Backward))!= TextPointerContext.None) { if (tst == TextPointerContext.ElementStart) { if (nestedElement == 0) { FlowPosition flowEnd = flowScan.GetClingPosition(LogicalDirection.Backward); return (FixedElement)flowEnd._flowNode.Cookie; } nestedElement--; } else if (tst == TextPointerContext.ElementEnd) { nestedElement++; } flowScan.Move(LogicalDirection.Backward); } return _container.ContainerElement; } // return false if distance exceeds the size of the document internal bool Move(int distance) { LogicalDirection dir = (distance >= 0 ? LogicalDirection.Forward : LogicalDirection.Backward); distance = Math.Abs(distance); FlowNode startNode = _flowNode; // save state int startOffset = _offset; // keep moving until we hit distance while (distance > 0) { int scan = _vScan(dir, distance); if (scan == 0) { //restore state and return false _flowNode = startNode; _offset = startOffset; return false; } distance -= scan; } return true; } // Skip current symbol or run internal bool Move(LogicalDirection dir) { if (_vScan(dir, -1) > 0) { return true; } return false; } // Move to next FlowPosition internal void MoveTo(FlowPosition flow) { _flowNode = flow._flowNode; _offset = flow._offset; } #endregion Text OM Helper //-------------------------------------------------------------------- // Internal Methods //---------------------------------------------------------------------- internal void AttachElement(FixedElement e) { _flowNode.AttachElement(e); } internal void GetFlowNode(LogicalDirection direction, out FlowNode flowNode, out int offsetStart) { FlowPosition fp = GetClingPosition(direction); offsetStart = fp._offset; flowNode = fp._flowNode; } // return FlowNode within this range internal void GetFlowNodes(FlowPosition pEnd, out FlowNode[] flowNodes, out int offsetStart, out int offsetEnd) { Debug.Assert(this._OverlapAwareCompare(pEnd) < 0); flowNodes = null; offsetStart = 0; offsetEnd = 0; FlowPosition flowScan = GetClingPosition(LogicalDirection.Forward); offsetStart = flowScan._offset; ArrayList ar = new ArrayList(); int distance = GetDistance(pEnd); // keep moving until we hit distance while (distance > 0) { int scan = flowScan._vScan(LogicalDirection.Forward, distance); distance -= scan; if (flowScan.IsRun || flowScan.IsObject) { ar.Add(flowScan._flowNode); offsetEnd = flowScan._offset; } } flowNodes = (FlowNode [])ar.ToArray(typeof(FlowNode)); } // A canonical position is one that clings to a FlowNode internal FlowPosition GetClingPosition(LogicalDirection dir) { FlowPosition flow = (FlowPosition)this.Clone(); FlowNode fn; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength) { // This position is at right side of a FlowNode // look for next run fn = _xGetNextFlowNode(); if (!FlowNode.IsNull(fn)) { flow._flowNode = fn; flow._offset = 0; } #if DEBUG else { DocumentsTrace.FixedTextOM.FlowPosition.Trace("GetClingPosition: Next FlowNode is null"); } #endif } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0) { // This position is at left side of a FlowNode // look for previous run fn = _xGetPreviousFlowNode(); if (!FlowNode.IsNull(fn)) { flow._flowNode = fn; flow._offset = flow._NodeLength; } #if DEBUG else { DocumentsTrace.FixedTextOM.FlowPosition.Trace("GetClingPosition: Next FlowNode is null"); } #endif } } return flow; } internal bool IsVirtual(FlowNode flowNode) { return (flowNode.Type == FlowNodeType.Virtual); } #endregion Internal Methods //------------------------------------------------------------------- // // Internal Properties // //---------------------------------------------------------------------- #region Internal Properties internal FixedTextContainer TextContainer { get { return _container; } } internal bool IsBoundary { get { return (_flowNode.Type == FlowNodeType.Boundary); } } internal bool IsStart { get { return (_flowNode.Type == FlowNodeType.Start); } } internal bool IsEnd { get { return (_flowNode.Type == FlowNodeType.End); } } // If th_Is position _Is symbol internal bool IsSymbol { get { FlowNodeType t = _flowNode.Type; return (t == FlowNodeType.Start || t == FlowNodeType.End || t == FlowNodeType.Object); } } // If the FlowNode has run length internal bool IsRun { get { return (_flowNode.Type == FlowNodeType.Run); } } // If the FlowNode has run length internal bool IsObject { get { return (_flowNode.Type == FlowNodeType.Object); } } internal FlowNode FlowNode { get { return this._flowNode; } } #endregion Internal Properties //------------------------------------------------------------------- // // Private Methods // //--------------------------------------------------------------------- #region Private Methods //------------------------------------------------------------------- // Helper functions that could result in de-virtualization //---------------------------------------------------------------------- // scan one node forward, return characters/symbols passed // limit < 0 means scan entire node. private int _vScan(LogicalDirection dir, int limit) { if (limit == 0) { return 0; } FlowNode flowNode = _flowNode; int scanned = 0; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength || flowNode.Type == FlowNodeType.Boundary) { // This position is at right side of a FlowNode flowNode = _xGetNextFlowNode(); if (FlowNode.IsNull(flowNode)) { return scanned; } _flowNode = flowNode; scanned = _NodeLength; } else { scanned = _NodeLength - _offset; } _offset = _NodeLength; if (limit > 0 && scanned > limit) { int back = scanned - limit; scanned = limit; _offset -= back; } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0 || flowNode.Type == FlowNodeType.Boundary) { // This position is at left side of a FlowNode // look for previous run flowNode = _xGetPreviousFlowNode(); if (FlowNode.IsNull(flowNode)) { return scanned; } _flowNode = flowNode; scanned = _NodeLength; } else { scanned = _offset; } _offset = 0; if (limit > 0 && scanned > limit) { int back = scanned - limit; scanned = limit; _offset += back; } } return scanned; } private TextPointerContext _vGetSymbolType(LogicalDirection dir) { FlowNode flowNode = _flowNode; if (dir == LogicalDirection.Forward) { if (_offset == _NodeLength) { // This position is at right side of a FlowNode // look for next run flowNode = _xGetNextFlowNode(); } if (!FlowNode.IsNull(flowNode)) { return _FlowNodeTypeToTextSymbol(flowNode.Type); } } else { Debug.Assert(dir == LogicalDirection.Backward); if (_offset == 0) { // This position is at left side of a FlowNode // look for previous run flowNode = _xGetPreviousFlowNode(); } if (!FlowNode.IsNull(flowNode)) { return _FlowNodeTypeToTextSymbol(flowNode.Type); } } return TextPointerContext.None; } //------------------------------------------------------------------- // Helper functions that have raw access to backing store and provided // a non-virtualied view on top of virtualized content. //---------------------------------------------------------------------- // return null if no previous node private FlowNode _xGetPreviousFlowNode() { if (_flowNode.Fp > 1) { FlowNode flow = _FixedFlowMap[_flowNode.Fp - 1]; // devirtualize the backing store if (IsVirtual(flow)) { _FixedTextBuilder.EnsureTextOMForPage((int)flow.Cookie); flow = _FixedFlowMap[_flowNode.Fp - 1]; } // filter out boundary node if (flow.Type != FlowNodeType.Boundary) { return flow; } } return null; } // return null if no next node private FlowNode _xGetNextFlowNode() { if (_flowNode.Fp < _FixedFlowMap.FlowCount - 1) { FlowNode flow = _FixedFlowMap[_flowNode.Fp + 1]; // devirtualize the backing store if (IsVirtual(flow)) { _FixedTextBuilder.EnsureTextOMForPage((int)flow.Cookie); flow = _FixedFlowMap[_flowNode.Fp + 1]; } // filter out boundary node if (flow.Type != FlowNodeType.Boundary) { return flow; } } return null; } //-------------------------------------------------------------------- // Helper functions //--------------------------------------------------------------------- // see if the two FlowPosition are indeed same position private bool _IsSamePosition(FlowPosition flow) { if (flow == null) { return false; } return (_OverlapAwareCompare(flow) == 0); } // intelligent compare routine that understands position overlap private int _OverlapAwareCompare(FlowPosition flow) { Debug.Assert(flow != null); if ((object)this == (object)flow) { return 0; } int comp = this._flowNode.CompareTo(flow._flowNode); if (comp < 0) { // Check overlap positions // Positions are the same if they are at end of previous run or begin of next run if (this._flowNode.Fp == flow._flowNode.Fp - 1 && this._offset == _NodeLength && flow._offset == 0) { return 0; } } else if (comp > 0) { // Check overlap positions // Positions are the same if they are at end of previous run or begin of next run if (flow._flowNode.Fp == this._flowNode.Fp - 1 && flow._offset == flow._NodeLength && this._offset == 0) { return 0; } } else { // compare offset only Debug.Assert(this._flowNode.Equals(flow._flowNode)); comp = this._offset.CompareTo(flow._offset); } return comp; } // Convert Flow Node Type to TextPointerContext private TextPointerContext _FlowNodeTypeToTextSymbol(FlowNodeType t) { switch (t) { case FlowNodeType.Start: return TextPointerContext.ElementStart; case FlowNodeType.End: return TextPointerContext.ElementEnd; case FlowNodeType.Run: return TextPointerContext.Text; case FlowNodeType.Object: case FlowNodeType.Noop: return TextPointerContext.EmbeddedElement; default: return TextPointerContext.None; } } #endregion Private Methods //-------------------------------------------------------------------- // // Private Properties // //--------------------------------------------------------------------- #region Private Properties // Get length of this node structure private int _NodeLength { get { if (IsRun) { return (int)_flowNode.Cookie; } else { return 1; } } } private FixedTextBuilder _FixedTextBuilder { get { return _container.FixedTextBuilder; } } private FixedFlowMap _FixedFlowMap { get { return _container.FixedTextBuilder.FixedFlowMap; } } #endregion Private Properties //------------------------------------------------------------------- // // Private Fields // //--------------------------------------------------------------------- #region Private Fields private FixedTextContainer _container; // the container has the backing store for flow nodes private FlowNode _flowNode; // flow node private int _offset; // offset into flow #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Constant.cs
- Route.cs
- DetailsViewPagerRow.cs
- SemanticResolver.cs
- HttpListener.cs
- PenLineCapValidation.cs
- DBSchemaTable.cs
- StringUtil.cs
- CookieParameter.cs
- ToolStripControlHost.cs
- TableRow.cs
- GrowingArray.cs
- VectorKeyFrameCollection.cs
- ListViewInsertEventArgs.cs
- TextBoxBase.cs
- FloaterParaClient.cs
- SafePointer.cs
- WebServiceBindingAttribute.cs
- AdjustableArrowCap.cs
- XmlRootAttribute.cs
- BasicExpressionVisitor.cs
- SecurityPolicySection.cs
- AdRotator.cs
- RegexParser.cs
- XpsFilter.cs
- Page.cs
- GlobalItem.cs
- EventMap.cs
- FilterException.cs
- TableLayoutSettings.cs
- WindowsTooltip.cs
- SmiEventSink_Default.cs
- MetaModel.cs
- StringExpressionSet.cs
- ActivationService.cs
- InternalControlCollection.cs
- MethodBuilderInstantiation.cs
- NameSpaceExtractor.cs
- ValueOfAction.cs
- WindowManager.cs
- FixedHighlight.cs
- ReachFixedPageSerializer.cs
- DrawingContextWalker.cs
- XmlNodeReader.cs
- ZoneLinkButton.cs
- ValidationService.cs
- URL.cs
- FixedElement.cs
- DataMemberFieldConverter.cs
- keycontainerpermission.cs
- HtmlTable.cs
- BitmapSource.cs
- ServiceModelReg.cs
- SQLBoolean.cs
- WindowsStatusBar.cs
- CriticalExceptions.cs
- CorrelationManager.cs
- NameValueConfigurationCollection.cs
- NavigatorInput.cs
- ListSortDescriptionCollection.cs
- SiteMapNode.cs
- WinFormsSpinner.cs
- OletxTransactionManager.cs
- NotifyCollectionChangedEventArgs.cs
- EntityCommand.cs
- LogExtentCollection.cs
- CacheOutputQuery.cs
- DataControlExtensions.cs
- PrintDialogException.cs
- SafeMarshalContext.cs
- StringPropertyBuilder.cs
- Literal.cs
- MetadataArtifactLoaderComposite.cs
- VisualTreeUtils.cs
- XPathBuilder.cs
- BamlRecordWriter.cs
- BatchWriter.cs
- ListViewVirtualItemsSelectionRangeChangedEvent.cs
- DialogResultConverter.cs
- SqlConnectionHelper.cs
- SortFieldComparer.cs
- FilterQuery.cs
- PointCollection.cs
- ServiceChannelProxy.cs
- AssemblyLoader.cs
- StrongNameSignatureInformation.cs
- ValueConversionAttribute.cs
- ResourceIDHelper.cs
- DataGridTextBoxColumn.cs
- EventWaitHandle.cs
- CertificateManager.cs
- WindowsScrollBar.cs
- AccessKeyManager.cs
- GeometryValueSerializer.cs
- EnterpriseServicesHelper.cs
- XPathNode.cs
- WpfXamlMember.cs
- EntityStoreSchemaGenerator.cs
- HijriCalendar.cs
- Operators.cs