Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextTreeTextBlock.cs / 1305600 / TextTreeTextBlock.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: A block of text stored in a TextContainer. // // History: // 2/18/2004 : [....] - Created // //--------------------------------------------------------------------------- using System; using MS.Internal; namespace System.Windows.Documents { // Each TextContainer maintains an array of TextTreeTextBlocks that holds all // the raw text in the tree. // // TextTreeTextBlocks are simple char arrays with some extra state that // tracks current char count vs capacity. Instead of simply storing // text at the head of the array, we use the "buffer gap" algorithm. // Free space in the array always follows the last insertion, so with // sequential writes we don't need to memmove any existing text. internal class TextTreeTextBlock : SplayTreeNode { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Create a new TextTreeTextBlock instance. internal TextTreeTextBlock(int size) { Invariant.Assert(size > 0); Invariant.Assert(size <= MaxBlockSize); _text = new char[size]; _gapSize = size; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #if DEBUG // Debug-only ToString override. public override string ToString() { return ("TextTreeTextBlock Id=" + this.DebugId + " Count=" + this.Count); } #endif // DEBUG #endregion Public Methods //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Inserts text into the block, up to the remaining block capacity. // Returns the number of chars actually inserted. internal int InsertText(int logicalOffset, object text, int textStartIndex, int textEndIndex) { int count; string textString; char[] textChars; char[] newText; int rightOfGapLength; Invariant.Assert(text is string || text is char[], "Bad text parameter!"); Invariant.Assert(textStartIndex <= textEndIndex, "Bad start/end index!"); // Splay this node so we don't invalidate any LeftSymbolCounts. Splay(); count = textEndIndex - textStartIndex; if (_text.Length < MaxBlockSize && count > _gapSize) { // We need to grow this block. // We're very conservative here, allocating no more than the // caller asks for. Once we push past the MaxBlockSize, we'll // be more aggressive with allocations. newText = new char[Math.Min(this.Count + count, MaxBlockSize)]; Array.Copy(_text, 0, newText, 0, _gapOffset); rightOfGapLength = _text.Length - (_gapOffset + _gapSize); Array.Copy(_text, _gapOffset + _gapSize, newText, newText.Length - rightOfGapLength, rightOfGapLength); _gapSize += newText.Length - _text.Length; _text = newText; } // Move the gap to the insert point. if (logicalOffset != _gapOffset) { MoveGap(logicalOffset); } // Truncate the copy. count = Math.Min(count, _gapSize); textString = text as string; if (textString != null) { // Do the work. textString.CopyTo(textStartIndex, _text, logicalOffset, count); } else { textChars = (char[])text; // Do the work. Array.Copy(textChars, textStartIndex, _text, logicalOffset, count); } // Update the gap. _gapOffset += count; _gapSize -= count; return count; } // Splits this block at the current gap offset. // Only called during a text insert, when the block is full. // If GapOffset < TextTreeTextBlock.MaxBlockSize / 2, returns // a new block with the left text, otherwise returns a new // block with the right text. internal TextTreeTextBlock SplitBlock() { TextTreeTextBlock newBlock; bool insertBefore; Invariant.Assert(_gapSize == 0, "Splitting non-full block!"); Invariant.Assert(_text.Length == MaxBlockSize, "Splitting non-max sized block!"); newBlock = new TextTreeTextBlock(MaxBlockSize); if (_gapOffset < MaxBlockSize / 2) { // Copy the left text over to the new block. Array.Copy(_text, 0, newBlock._text, 0, _gapOffset); newBlock._gapOffset = _gapOffset; newBlock._gapSize = MaxBlockSize - _gapOffset; // Remove the left text from this block. _gapSize += _gapOffset; _gapOffset = 0; // New node preceeds this one. insertBefore = true; } else { // Copy the right text over to the new block. Array.Copy(_text, _gapOffset, newBlock._text, _gapOffset, MaxBlockSize - _gapOffset); Invariant.Assert(newBlock._gapOffset == 0); newBlock._gapSize = _gapOffset; // Remove the left text from this block. _gapSize = MaxBlockSize - _gapOffset; // New node follows this one. insertBefore = false; } // Add the new node to the splay tree. newBlock.InsertAtNode(this, insertBefore); return newBlock; } // Removes text at a logical offset (an offset that does not // consider the gap). internal void RemoveText(int logicalOffset, int count) { int precedingTextToRemoveCount; Invariant.Assert(logicalOffset >= 0); Invariant.Assert(count >= 0); Invariant.Assert(logicalOffset + count <= this.Count, "Removing too much text!"); int originalCountToRemove = count; int originalCount = this.Count; // Splay this node so we don't invalidate any LeftSymbolCounts. Splay(); // // Remove text before the gap. if (logicalOffset < _gapOffset) { if (logicalOffset + count < _gapOffset) { // Shift text over. MoveGap(logicalOffset + count); } // Extend the gap to "remove" the text. precedingTextToRemoveCount = (logicalOffset + count == _gapOffset) ? count : _gapOffset - logicalOffset; _gapOffset -= precedingTextToRemoveCount; _gapSize += precedingTextToRemoveCount; // Adjust logicalOffset, count, so that they follow the gap below. logicalOffset = _gapOffset; count -= precedingTextToRemoveCount; } // Make offset relative to text after the gap. logicalOffset += _gapSize; // Remove text after the gap. if (logicalOffset > _gapOffset + _gapSize) { // Shift text over. MoveGap(logicalOffset - _gapSize); } // Extend the gap to "remove" the text. _gapSize += count; Invariant.Assert(_gapOffset + _gapSize <= _text.Length); Invariant.Assert(originalCount == this.Count + originalCountToRemove); } // Copies text into a char array, returns the actual count of chars copied, // which may be smaller than count if the end of block is encountered. internal int ReadText(int logicalOffset, int count, char []chars, int charsStartIndex) { int copyCount; int originalCount; originalCount = count; // Read text before the gap. if (logicalOffset < _gapOffset) { copyCount = Math.Min(count, _gapOffset - logicalOffset); Array.Copy(_text, logicalOffset, chars, charsStartIndex, copyCount); count -= copyCount; charsStartIndex += copyCount; // Adjust logicalOffset, so that it will follow the gap below. logicalOffset = _gapOffset; } if (count > 0) { // Make offset relative to text after the gap. logicalOffset += _gapSize; // Read the text following the gap. copyCount = Math.Min(count, _text.Length - logicalOffset); Array.Copy(_text, logicalOffset, chars, charsStartIndex, copyCount); count -= copyCount; } return (originalCount - count); } #endregion Internal methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties // If this node is a local root, then ParentNode contains it. // Otherwise, this is the node parenting this node within its tree. internal override SplayTreeNode ParentNode { get { return _parentNode; } set { _parentNode = value; } } // TextTreeTextNode never has contained nodes. internal override SplayTreeNode ContainedNode { get { return null; } set { Invariant.Assert(false, "Can't set ContainedNode on a TextTreeTextBlock!"); } } // Count of symbols of all siblings preceding this node. internal override int LeftSymbolCount { get { return _leftSymbolCount; } set { _leftSymbolCount = value; } } // Count of unicode chars of all siblings preceding this node. // This property is only used by TextTreeNodes. internal override int LeftCharCount { get { return 0; } set { Invariant.Assert(value == 0); } } // Left child node in a sibling tree. internal override SplayTreeNode LeftChildNode { get { return _leftChildNode; } set { _leftChildNode = (TextTreeTextBlock)value; } } // Right child node in a sibling tree. internal override SplayTreeNode RightChildNode { get { return _rightChildNode; } set { _rightChildNode = (TextTreeTextBlock)value; } } // Unused by this derived class. internal override uint Generation { get { return 0; } set { Invariant.Assert(false, "TextTreeTextBlock does not track Generation!"); } } // Cached symbol offset. // Unused by this derived class. internal override int SymbolOffsetCache { get { return -1; } set { Invariant.Assert(false, "TextTreeTextBlock does not track SymbolOffsetCache!"); } } // Count of symbols covered by this node. internal override int SymbolCount { get { return this.Count; } set { Invariant.Assert(false, "Can't set SymbolCount on TextTreeTextBlock!"); } } // Count of unicode chars covered by this node and any contained nodes. // This property is only used by TextTreeNodes. internal override int IMECharCount { get { return 0; } set { Invariant.Assert(value == 0); } } // The number of chars stored in this block. internal int Count { get { return (_text.Length - _gapSize); } } // The number of additional chars this Block could accept before running out of space. internal int FreeCapacity { get { return _gapSize; } } // The offset of the gap in this block. internal int GapOffset { get { return _gapOffset; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods // Repositions the gap to a new offset, shifting text as necessary. private void MoveGap(int offset) { int sourceOffset; int destinationOffset; int count; if (offset < _gapOffset) { sourceOffset = offset; destinationOffset = offset + _gapSize; count = _gapOffset - offset; } else { sourceOffset = _gapOffset + _gapSize; destinationOffset = _gapOffset; count = offset - _gapOffset; } Array.Copy(_text, sourceOffset, _text, destinationOffset, count); _gapOffset = offset; } #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // Count of symbols of all siblings preceding this node. private int _leftSymbolCount; // The TextTreeTextBlock parenting this node within its tree, // or the TextTreeRootTextBlock containing this node. private SplayTreeNode _parentNode; // Left child node in a sibling tree. private TextTreeTextBlock _leftChildNode; // Right child node in a sibling tree. private TextTreeTextBlock _rightChildNode; // An array of text in the block. private char []_text; // Position of the buffer gap. private int _gapOffset; // Size of the buffer gap. private int _gapSize; // Max block size, in chars. internal const int MaxBlockSize = 4096; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: A block of text stored in a TextContainer. // // History: // 2/18/2004 : [....] - Created // //--------------------------------------------------------------------------- using System; using MS.Internal; namespace System.Windows.Documents { // Each TextContainer maintains an array of TextTreeTextBlocks that holds all // the raw text in the tree. // // TextTreeTextBlocks are simple char arrays with some extra state that // tracks current char count vs capacity. Instead of simply storing // text at the head of the array, we use the "buffer gap" algorithm. // Free space in the array always follows the last insertion, so with // sequential writes we don't need to memmove any existing text. internal class TextTreeTextBlock : SplayTreeNode { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Create a new TextTreeTextBlock instance. internal TextTreeTextBlock(int size) { Invariant.Assert(size > 0); Invariant.Assert(size <= MaxBlockSize); _text = new char[size]; _gapSize = size; } #endregion Constructors //------------------------------------------------------ // // Public Methods // //----------------------------------------------------- #region Public Methods #if DEBUG // Debug-only ToString override. public override string ToString() { return ("TextTreeTextBlock Id=" + this.DebugId + " Count=" + this.Count); } #endif // DEBUG #endregion Public Methods //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Inserts text into the block, up to the remaining block capacity. // Returns the number of chars actually inserted. internal int InsertText(int logicalOffset, object text, int textStartIndex, int textEndIndex) { int count; string textString; char[] textChars; char[] newText; int rightOfGapLength; Invariant.Assert(text is string || text is char[], "Bad text parameter!"); Invariant.Assert(textStartIndex <= textEndIndex, "Bad start/end index!"); // Splay this node so we don't invalidate any LeftSymbolCounts. Splay(); count = textEndIndex - textStartIndex; if (_text.Length < MaxBlockSize && count > _gapSize) { // We need to grow this block. // We're very conservative here, allocating no more than the // caller asks for. Once we push past the MaxBlockSize, we'll // be more aggressive with allocations. newText = new char[Math.Min(this.Count + count, MaxBlockSize)]; Array.Copy(_text, 0, newText, 0, _gapOffset); rightOfGapLength = _text.Length - (_gapOffset + _gapSize); Array.Copy(_text, _gapOffset + _gapSize, newText, newText.Length - rightOfGapLength, rightOfGapLength); _gapSize += newText.Length - _text.Length; _text = newText; } // Move the gap to the insert point. if (logicalOffset != _gapOffset) { MoveGap(logicalOffset); } // Truncate the copy. count = Math.Min(count, _gapSize); textString = text as string; if (textString != null) { // Do the work. textString.CopyTo(textStartIndex, _text, logicalOffset, count); } else { textChars = (char[])text; // Do the work. Array.Copy(textChars, textStartIndex, _text, logicalOffset, count); } // Update the gap. _gapOffset += count; _gapSize -= count; return count; } // Splits this block at the current gap offset. // Only called during a text insert, when the block is full. // If GapOffset < TextTreeTextBlock.MaxBlockSize / 2, returns // a new block with the left text, otherwise returns a new // block with the right text. internal TextTreeTextBlock SplitBlock() { TextTreeTextBlock newBlock; bool insertBefore; Invariant.Assert(_gapSize == 0, "Splitting non-full block!"); Invariant.Assert(_text.Length == MaxBlockSize, "Splitting non-max sized block!"); newBlock = new TextTreeTextBlock(MaxBlockSize); if (_gapOffset < MaxBlockSize / 2) { // Copy the left text over to the new block. Array.Copy(_text, 0, newBlock._text, 0, _gapOffset); newBlock._gapOffset = _gapOffset; newBlock._gapSize = MaxBlockSize - _gapOffset; // Remove the left text from this block. _gapSize += _gapOffset; _gapOffset = 0; // New node preceeds this one. insertBefore = true; } else { // Copy the right text over to the new block. Array.Copy(_text, _gapOffset, newBlock._text, _gapOffset, MaxBlockSize - _gapOffset); Invariant.Assert(newBlock._gapOffset == 0); newBlock._gapSize = _gapOffset; // Remove the left text from this block. _gapSize = MaxBlockSize - _gapOffset; // New node follows this one. insertBefore = false; } // Add the new node to the splay tree. newBlock.InsertAtNode(this, insertBefore); return newBlock; } // Removes text at a logical offset (an offset that does not // consider the gap). internal void RemoveText(int logicalOffset, int count) { int precedingTextToRemoveCount; Invariant.Assert(logicalOffset >= 0); Invariant.Assert(count >= 0); Invariant.Assert(logicalOffset + count <= this.Count, "Removing too much text!"); int originalCountToRemove = count; int originalCount = this.Count; // Splay this node so we don't invalidate any LeftSymbolCounts. Splay(); // // Remove text before the gap. if (logicalOffset < _gapOffset) { if (logicalOffset + count < _gapOffset) { // Shift text over. MoveGap(logicalOffset + count); } // Extend the gap to "remove" the text. precedingTextToRemoveCount = (logicalOffset + count == _gapOffset) ? count : _gapOffset - logicalOffset; _gapOffset -= precedingTextToRemoveCount; _gapSize += precedingTextToRemoveCount; // Adjust logicalOffset, count, so that they follow the gap below. logicalOffset = _gapOffset; count -= precedingTextToRemoveCount; } // Make offset relative to text after the gap. logicalOffset += _gapSize; // Remove text after the gap. if (logicalOffset > _gapOffset + _gapSize) { // Shift text over. MoveGap(logicalOffset - _gapSize); } // Extend the gap to "remove" the text. _gapSize += count; Invariant.Assert(_gapOffset + _gapSize <= _text.Length); Invariant.Assert(originalCount == this.Count + originalCountToRemove); } // Copies text into a char array, returns the actual count of chars copied, // which may be smaller than count if the end of block is encountered. internal int ReadText(int logicalOffset, int count, char []chars, int charsStartIndex) { int copyCount; int originalCount; originalCount = count; // Read text before the gap. if (logicalOffset < _gapOffset) { copyCount = Math.Min(count, _gapOffset - logicalOffset); Array.Copy(_text, logicalOffset, chars, charsStartIndex, copyCount); count -= copyCount; charsStartIndex += copyCount; // Adjust logicalOffset, so that it will follow the gap below. logicalOffset = _gapOffset; } if (count > 0) { // Make offset relative to text after the gap. logicalOffset += _gapSize; // Read the text following the gap. copyCount = Math.Min(count, _text.Length - logicalOffset); Array.Copy(_text, logicalOffset, chars, charsStartIndex, copyCount); count -= copyCount; } return (originalCount - count); } #endregion Internal methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties // If this node is a local root, then ParentNode contains it. // Otherwise, this is the node parenting this node within its tree. internal override SplayTreeNode ParentNode { get { return _parentNode; } set { _parentNode = value; } } // TextTreeTextNode never has contained nodes. internal override SplayTreeNode ContainedNode { get { return null; } set { Invariant.Assert(false, "Can't set ContainedNode on a TextTreeTextBlock!"); } } // Count of symbols of all siblings preceding this node. internal override int LeftSymbolCount { get { return _leftSymbolCount; } set { _leftSymbolCount = value; } } // Count of unicode chars of all siblings preceding this node. // This property is only used by TextTreeNodes. internal override int LeftCharCount { get { return 0; } set { Invariant.Assert(value == 0); } } // Left child node in a sibling tree. internal override SplayTreeNode LeftChildNode { get { return _leftChildNode; } set { _leftChildNode = (TextTreeTextBlock)value; } } // Right child node in a sibling tree. internal override SplayTreeNode RightChildNode { get { return _rightChildNode; } set { _rightChildNode = (TextTreeTextBlock)value; } } // Unused by this derived class. internal override uint Generation { get { return 0; } set { Invariant.Assert(false, "TextTreeTextBlock does not track Generation!"); } } // Cached symbol offset. // Unused by this derived class. internal override int SymbolOffsetCache { get { return -1; } set { Invariant.Assert(false, "TextTreeTextBlock does not track SymbolOffsetCache!"); } } // Count of symbols covered by this node. internal override int SymbolCount { get { return this.Count; } set { Invariant.Assert(false, "Can't set SymbolCount on TextTreeTextBlock!"); } } // Count of unicode chars covered by this node and any contained nodes. // This property is only used by TextTreeNodes. internal override int IMECharCount { get { return 0; } set { Invariant.Assert(value == 0); } } // The number of chars stored in this block. internal int Count { get { return (_text.Length - _gapSize); } } // The number of additional chars this Block could accept before running out of space. internal int FreeCapacity { get { return _gapSize; } } // The offset of the gap in this block. internal int GapOffset { get { return _gapOffset; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods // Repositions the gap to a new offset, shifting text as necessary. private void MoveGap(int offset) { int sourceOffset; int destinationOffset; int count; if (offset < _gapOffset) { sourceOffset = offset; destinationOffset = offset + _gapSize; count = _gapOffset - offset; } else { sourceOffset = _gapOffset + _gapSize; destinationOffset = _gapOffset; count = offset - _gapOffset; } Array.Copy(_text, sourceOffset, _text, destinationOffset, count); _gapOffset = offset; } #endregion Private methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields // Count of symbols of all siblings preceding this node. private int _leftSymbolCount; // The TextTreeTextBlock parenting this node within its tree, // or the TextTreeRootTextBlock containing this node. private SplayTreeNode _parentNode; // Left child node in a sibling tree. private TextTreeTextBlock _leftChildNode; // Right child node in a sibling tree. private TextTreeTextBlock _rightChildNode; // An array of text in the block. private char []_text; // Position of the buffer gap. private int _gapOffset; // Size of the buffer gap. private int _gapSize; // Max block size, in chars. internal const int MaxBlockSize = 4096; #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
- CallbackValidatorAttribute.cs
- MessageQueue.cs
- Parallel.cs
- ListChunk.cs
- StorageComplexPropertyMapping.cs
- AsyncResult.cs
- RequestUriProcessor.cs
- DocumentViewerConstants.cs
- BitmapPalette.cs
- NamedPipeProcessProtocolHandler.cs
- Semaphore.cs
- Vector3DAnimationBase.cs
- ArrayExtension.cs
- FileDialog_Vista.cs
- ResXResourceWriter.cs
- ObjectReaderCompiler.cs
- PathStreamGeometryContext.cs
- PeerValidationBehavior.cs
- MessageBuilder.cs
- DbSourceParameterCollection.cs
- OperatingSystem.cs
- EntityStoreSchemaFilterEntry.cs
- SmuggledIUnknown.cs
- FormsAuthenticationConfiguration.cs
- NonVisualControlAttribute.cs
- CustomErrorsSection.cs
- RemoteHelper.cs
- PublishLicense.cs
- FlatButtonAppearance.cs
- WhitespaceRuleLookup.cs
- UpdateTranslator.cs
- Comparer.cs
- IApplicationTrustManager.cs
- ToolStripGrip.cs
- FuncCompletionCallbackWrapper.cs
- UnaryOperationBinder.cs
- ResourceCollectionInfo.cs
- UshortList2.cs
- MachineKeySection.cs
- AutomationEventArgs.cs
- DataMemberConverter.cs
- LogEntrySerializationException.cs
- validationstate.cs
- WindowsTitleBar.cs
- DataChangedEventManager.cs
- GenerateHelper.cs
- OleCmdHelper.cs
- DropSource.cs
- HttpModuleAction.cs
- KeyedHashAlgorithm.cs
- ScriptResourceHandler.cs
- FormViewInsertEventArgs.cs
- SwitchDesigner.xaml.cs
- AssemblyCache.cs
- CollectionViewGroup.cs
- XMLUtil.cs
- XmlSchemaSimpleContentExtension.cs
- StackSpiller.Bindings.cs
- ParserOptions.cs
- ThicknessAnimationBase.cs
- PeerInputChannel.cs
- OutOfMemoryException.cs
- CorePropertiesFilter.cs
- UserNamePasswordValidator.cs
- DataGridViewAdvancedBorderStyle.cs
- PipeStream.cs
- XmlSchemaComplexContent.cs
- SyntaxCheck.cs
- Internal.cs
- PartManifestEntry.cs
- EntityDataSourceWizardForm.cs
- TypeConverterAttribute.cs
- EntityDataSourceChangingEventArgs.cs
- UIElement.cs
- LocatorPart.cs
- ResourcesBuildProvider.cs
- MachineKeyConverter.cs
- Transform3DCollection.cs
- XmlDocumentType.cs
- ChangeBlockUndoRecord.cs
- XmlStringTable.cs
- StringValueConverter.cs
- DllHostedComPlusServiceHost.cs
- GACMembershipCondition.cs
- ParserContext.cs
- DSASignatureDeformatter.cs
- SiteMapHierarchicalDataSourceView.cs
- LassoHelper.cs
- ArithmeticException.cs
- ReadingWritingEntityEventArgs.cs
- CompleteWizardStep.cs
- FixedTextContainer.cs
- MergablePropertyAttribute.cs
- UnknownWrapper.cs
- OptimalBreakSession.cs
- D3DImage.cs
- Run.cs
- Graphics.cs
- SystemIPv6InterfaceProperties.cs
- BindingWorker.cs