Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / TextTreeText.cs / 1305600 / TextTreeText.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: A static class that manipulates an array TextTreeTextBlocks. // // History: // 2/18/2004 : [....] - Created // //--------------------------------------------------------------------------- using System; using System.Collections; using MS.Internal; namespace System.Windows.Documents { // Each TextContainer maintains an array of TextTreeTextBlocks that holds all // the raw text in the tree. This class manipulates that array. // // "Raw text" includes not only unicode covered by TextTreeTextNodes, but // also placeholders for element edges and embedded objects. Inserting // placeholders lets us map 1-to-1 with array offsets and symbol offsets. internal static class TextTreeText { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Inserts text into the text block array. The text is either a string // or an array of char. internal static void InsertText(TextTreeRootTextBlock rootTextBlock, int offset, object text) { TextTreeTextBlock block; int localOffset; int insertCount; int textLength; Invariant.Assert(text is string || text is char[], "Bad text parameter!"); // Get the block matching the insertion point. block = FindBlock(rootTextBlock, offset, out localOffset); // Fill this block to capacity. textLength = TextContainer.GetTextLength(text); insertCount = block.InsertText(localOffset, text, 0, textLength); if (insertCount < textLength) { // Put all the text to the smaller side of the gap into the new block. if (block.GapOffset < TextTreeTextBlock.MaxBlockSize / 2) { InsertTextLeft(block, text, insertCount); } else { InsertTextRight(block, text, insertCount); } } } // Removes text from the block array. // internal static void RemoveText(TextTreeRootTextBlock rootTextBlock, int offset, int count) { int firstBlockLocalOffset; TextTreeTextBlock firstBlock; int lastBlockLocalOffset; TextTreeTextBlock lastBlock; SplayTreeNode firstRemoveBlock; SplayTreeNode lastRemoveBlock; int firstCount; if (count == 0) { // Early out on count == 0 so we don't get in trouble at the // very end of the array. return; } // Get the block matching the offset. firstBlock = FindBlock(rootTextBlock, offset, out firstBlockLocalOffset); if (firstBlock.Count == firstBlockLocalOffset) { // FindIndexForOffset always returns the lower block if we ask // for a cp between two blocks. // For a remove, we want to work with the following block, which // actually contains the content. firstBlock = (TextTreeTextBlock)firstBlock.GetNextNode(); Invariant.Assert(firstBlock != null); firstBlockLocalOffset = 0; } // And the block matching the offset + count. lastBlock = FindBlock(rootTextBlock, offset + count, out lastBlockLocalOffset); if (firstBlockLocalOffset > 0 || count < firstBlock.Count) { // Remove text from the first block. firstCount = Math.Min(count, firstBlock.Count - firstBlockLocalOffset); firstBlock.RemoveText(firstBlockLocalOffset, firstCount); // Don't remove the first block, since some text was left behind. firstRemoveBlock = firstBlock.GetNextNode(); } else { // All text in the first block covered -- just remove it entirely. firstCount = 0; firstRemoveBlock = firstBlock; } if (count > firstCount) { int lastCount; if (lastBlockLocalOffset < lastBlock.Count) { lastCount = lastBlockLocalOffset; // Remove some text. lastBlock.RemoveText(0, lastBlockLocalOffset); // There's text left over in the last block, so don't remove // the block. lastRemoveBlock = lastBlock.GetPreviousNode(); } else { lastCount = 0; // All text in the last block covered -- just remove it entirely. lastRemoveBlock = lastBlock; } // If firstRemoveBlock == lastBlock && lastRemoveBlock == firstBlock, // then there are no more blocks to remove -- we removed a portion // from the first and last block and they are direct neighbors. if (firstCount + lastCount < count) { // Remove any blocks in the middle of first, last. Remove((TextTreeTextBlock)firstRemoveBlock, (TextTreeTextBlock)lastRemoveBlock); } } } // Remove text from the block array, and return the removed text in a // char array. internal static char[] CutText(TextTreeRootTextBlock rootTextBlock, int offset, int count) { char[] text; text = new char[count]; ReadText(rootTextBlock, offset, count, text, 0); RemoveText(rootTextBlock, offset, count); return text; } // Read text in the block array. internal static void ReadText(TextTreeRootTextBlock rootTextBlock, int offset, int count, char[] chars, int startIndex) { TextTreeTextBlock block; int localOffset; int blockCount; if (count > 0) { // Get the block matching the offset. block = FindBlock(rootTextBlock, offset, out localOffset); while (true) { Invariant.Assert(block != null, "Caller asked for too much text!"); blockCount = block.ReadText(localOffset, count, chars, startIndex); localOffset = 0; count -= blockCount; if (count == 0) break; startIndex += blockCount; block = (TextTreeTextBlock)block.GetNextNode(); } } } // Inserts a placeholder character for an embedded object. // The actual value stored doesn't really matter, it will never be read. internal static void InsertObject(TextTreeRootTextBlock rootTextBlock, int offset) { InsertText(rootTextBlock, offset, new string((char)0xffff, 1)); } // Insert placeholders for elements edges into the block array. // The actual value stored doesn't really matter, it will never be read. internal static void InsertElementEdges(TextTreeRootTextBlock rootTextBlock, int offset, int childSymbolCount) { if (childSymbolCount == 0) { InsertText(rootTextBlock, offset, new string((char)0xbeef, 2)); } else { InsertText(rootTextBlock, offset, new string((char)0xbeef, 1)); InsertText(rootTextBlock, offset + childSymbolCount + 1, new string((char)0x0, 1)); } } // Remove placeholder element edge characters from the block array. internal static void RemoveElementEdges(TextTreeRootTextBlock rootTextBlock, int offset, int symbolCount) { Invariant.Assert(symbolCount >= 2, "Element must span at least two symbols!"); // 2 element edges == 2 symbols. if (symbolCount == 2) { RemoveText(rootTextBlock, offset, 2); } else { RemoveText(rootTextBlock, offset + symbolCount - 1, 1); RemoveText(rootTextBlock, offset, 1); } } #endregion Internal methods //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods // Finds the TextTreeTextBlock that contains the specified char offset. // Returns the lower block for offsets that border two blocks. private static TextTreeTextBlock FindBlock(TextTreeRootTextBlock rootTextBlock, int offset, out int localOffset) { TextTreeTextBlock node; int nodeOffset; node = (TextTreeTextBlock)rootTextBlock.ContainedNode.GetSiblingAtOffset(offset, out nodeOffset); // If offset is between two blocks, make sure we return the lower of the two. if (node.LeftSymbolCount == offset) { TextTreeTextBlock previousBlock = (TextTreeTextBlock)node.GetPreviousNode(); if (previousBlock != null) { node = previousBlock; nodeOffset -= node.SymbolCount; Invariant.Assert(nodeOffset >= 0); } } localOffset = offset - nodeOffset; Invariant.Assert(localOffset >= 0 && localOffset <= node.Count); return node; } // Helper for InsertText. Inserts text to the left of an existing block. private static void InsertTextLeft(TextTreeTextBlock rightBlock, object text, int textOffset) { int newBlockCount; TextTreeTextBlock leftBlock; TextTreeTextBlock neighborBlock; TextTreeTextBlock newBlock; int count; int textEndOffset = -1; int i; int length; length = TextContainer.GetTextLength(text); if (rightBlock.GapOffset == 0) { // Try to fill neighbor block. neighborBlock = (TextTreeTextBlock)rightBlock.GetPreviousNode(); if (neighborBlock != null) { textOffset += neighborBlock.InsertText(neighborBlock.Count, text, textOffset, length); } } if (textOffset < length) { // Try adding just one block. newBlockCount = 1; leftBlock = rightBlock.SplitBlock(); // Fill up the left block. textOffset += leftBlock.InsertText(leftBlock.Count, text, textOffset, length); if (textOffset < length) { // Fill up the larger block. // We need to copy from the end of the text here. count = Math.Min(rightBlock.FreeCapacity, length - textOffset); textEndOffset = length - count; rightBlock.InsertText(0, text, textEndOffset, length); if (textOffset < textEndOffset) { // We've filled both blocks, and there's still more text to copy. // Prepare to allocate some more blocks. newBlockCount += (textEndOffset - textOffset + TextTreeTextBlock.MaxBlockSize - 1) / TextTreeTextBlock.MaxBlockSize; } } for (i = 1; i < newBlockCount; i++) { newBlock = new TextTreeTextBlock(TextTreeTextBlock.MaxBlockSize); textOffset += newBlock.InsertText(0, text, textOffset, textEndOffset); newBlock.InsertAtNode(leftBlock, false /* insertBefore */); leftBlock = newBlock; } Invariant.Assert(newBlockCount == 1 || textOffset == textEndOffset, "Not all text copied!"); } } // Helper for InsertText. Inserts text to the right of an existing block. private static void InsertTextRight(TextTreeTextBlock leftBlock, object text, int textOffset) { int newBlockCount; TextTreeTextBlock rightBlock; TextTreeTextBlock neighborBlock; TextTreeTextBlock newBlock; int count; int textEndOffset; int i; textEndOffset = TextContainer.GetTextLength(text); if (leftBlock.GapOffset == leftBlock.Count) { // Try to fill neighbor block. neighborBlock = (TextTreeTextBlock)leftBlock.GetNextNode(); if (neighborBlock != null) { count = Math.Min(neighborBlock.FreeCapacity, textEndOffset - textOffset); neighborBlock.InsertText(0, text, textEndOffset - count, textEndOffset); textEndOffset -= count; } } if (textOffset < textEndOffset) { // Try adding just one block. newBlockCount = 1; rightBlock = leftBlock.SplitBlock(); // Fill up the right block. count = Math.Min(rightBlock.FreeCapacity, textEndOffset - textOffset); rightBlock.InsertText(0, text, textEndOffset - count, textEndOffset); textEndOffset -= count; if (textOffset < textEndOffset) { // Fill up the larger block. // We need to copy from the end of the text here. textOffset += leftBlock.InsertText(leftBlock.Count, text, textOffset, textEndOffset); if (textOffset < textEndOffset) { // We've filled both blocks, and there's still more text to copy. // Prepare to allocate some more blocks. newBlockCount += (textEndOffset - textOffset + TextTreeTextBlock.MaxBlockSize - 1) / TextTreeTextBlock.MaxBlockSize; } } for (i=0; i// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: A static class that manipulates an array TextTreeTextBlocks. // // History: // 2/18/2004 : [....] - Created // //--------------------------------------------------------------------------- using System; using System.Collections; using MS.Internal; namespace System.Windows.Documents { // Each TextContainer maintains an array of TextTreeTextBlocks that holds all // the raw text in the tree. This class manipulates that array. // // "Raw text" includes not only unicode covered by TextTreeTextNodes, but // also placeholders for element edges and embedded objects. Inserting // placeholders lets us map 1-to-1 with array offsets and symbol offsets. internal static class TextTreeText { //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods // Inserts text into the text block array. The text is either a string // or an array of char. internal static void InsertText(TextTreeRootTextBlock rootTextBlock, int offset, object text) { TextTreeTextBlock block; int localOffset; int insertCount; int textLength; Invariant.Assert(text is string || text is char[], "Bad text parameter!"); // Get the block matching the insertion point. block = FindBlock(rootTextBlock, offset, out localOffset); // Fill this block to capacity. textLength = TextContainer.GetTextLength(text); insertCount = block.InsertText(localOffset, text, 0, textLength); if (insertCount < textLength) { // Put all the text to the smaller side of the gap into the new block. if (block.GapOffset < TextTreeTextBlock.MaxBlockSize / 2) { InsertTextLeft(block, text, insertCount); } else { InsertTextRight(block, text, insertCount); } } } // Removes text from the block array. // internal static void RemoveText(TextTreeRootTextBlock rootTextBlock, int offset, int count) { int firstBlockLocalOffset; TextTreeTextBlock firstBlock; int lastBlockLocalOffset; TextTreeTextBlock lastBlock; SplayTreeNode firstRemoveBlock; SplayTreeNode lastRemoveBlock; int firstCount; if (count == 0) { // Early out on count == 0 so we don't get in trouble at the // very end of the array. return; } // Get the block matching the offset. firstBlock = FindBlock(rootTextBlock, offset, out firstBlockLocalOffset); if (firstBlock.Count == firstBlockLocalOffset) { // FindIndexForOffset always returns the lower block if we ask // for a cp between two blocks. // For a remove, we want to work with the following block, which // actually contains the content. firstBlock = (TextTreeTextBlock)firstBlock.GetNextNode(); Invariant.Assert(firstBlock != null); firstBlockLocalOffset = 0; } // And the block matching the offset + count. lastBlock = FindBlock(rootTextBlock, offset + count, out lastBlockLocalOffset); if (firstBlockLocalOffset > 0 || count < firstBlock.Count) { // Remove text from the first block. firstCount = Math.Min(count, firstBlock.Count - firstBlockLocalOffset); firstBlock.RemoveText(firstBlockLocalOffset, firstCount); // Don't remove the first block, since some text was left behind. firstRemoveBlock = firstBlock.GetNextNode(); } else { // All text in the first block covered -- just remove it entirely. firstCount = 0; firstRemoveBlock = firstBlock; } if (count > firstCount) { int lastCount; if (lastBlockLocalOffset < lastBlock.Count) { lastCount = lastBlockLocalOffset; // Remove some text. lastBlock.RemoveText(0, lastBlockLocalOffset); // There's text left over in the last block, so don't remove // the block. lastRemoveBlock = lastBlock.GetPreviousNode(); } else { lastCount = 0; // All text in the last block covered -- just remove it entirely. lastRemoveBlock = lastBlock; } // If firstRemoveBlock == lastBlock && lastRemoveBlock == firstBlock, // then there are no more blocks to remove -- we removed a portion // from the first and last block and they are direct neighbors. if (firstCount + lastCount < count) { // Remove any blocks in the middle of first, last. Remove((TextTreeTextBlock)firstRemoveBlock, (TextTreeTextBlock)lastRemoveBlock); } } } // Remove text from the block array, and return the removed text in a // char array. internal static char[] CutText(TextTreeRootTextBlock rootTextBlock, int offset, int count) { char[] text; text = new char[count]; ReadText(rootTextBlock, offset, count, text, 0); RemoveText(rootTextBlock, offset, count); return text; } // Read text in the block array. internal static void ReadText(TextTreeRootTextBlock rootTextBlock, int offset, int count, char[] chars, int startIndex) { TextTreeTextBlock block; int localOffset; int blockCount; if (count > 0) { // Get the block matching the offset. block = FindBlock(rootTextBlock, offset, out localOffset); while (true) { Invariant.Assert(block != null, "Caller asked for too much text!"); blockCount = block.ReadText(localOffset, count, chars, startIndex); localOffset = 0; count -= blockCount; if (count == 0) break; startIndex += blockCount; block = (TextTreeTextBlock)block.GetNextNode(); } } } // Inserts a placeholder character for an embedded object. // The actual value stored doesn't really matter, it will never be read. internal static void InsertObject(TextTreeRootTextBlock rootTextBlock, int offset) { InsertText(rootTextBlock, offset, new string((char)0xffff, 1)); } // Insert placeholders for elements edges into the block array. // The actual value stored doesn't really matter, it will never be read. internal static void InsertElementEdges(TextTreeRootTextBlock rootTextBlock, int offset, int childSymbolCount) { if (childSymbolCount == 0) { InsertText(rootTextBlock, offset, new string((char)0xbeef, 2)); } else { InsertText(rootTextBlock, offset, new string((char)0xbeef, 1)); InsertText(rootTextBlock, offset + childSymbolCount + 1, new string((char)0x0, 1)); } } // Remove placeholder element edge characters from the block array. internal static void RemoveElementEdges(TextTreeRootTextBlock rootTextBlock, int offset, int symbolCount) { Invariant.Assert(symbolCount >= 2, "Element must span at least two symbols!"); // 2 element edges == 2 symbols. if (symbolCount == 2) { RemoveText(rootTextBlock, offset, 2); } else { RemoveText(rootTextBlock, offset + symbolCount - 1, 1); RemoveText(rootTextBlock, offset, 1); } } #endregion Internal methods //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods // Finds the TextTreeTextBlock that contains the specified char offset. // Returns the lower block for offsets that border two blocks. private static TextTreeTextBlock FindBlock(TextTreeRootTextBlock rootTextBlock, int offset, out int localOffset) { TextTreeTextBlock node; int nodeOffset; node = (TextTreeTextBlock)rootTextBlock.ContainedNode.GetSiblingAtOffset(offset, out nodeOffset); // If offset is between two blocks, make sure we return the lower of the two. if (node.LeftSymbolCount == offset) { TextTreeTextBlock previousBlock = (TextTreeTextBlock)node.GetPreviousNode(); if (previousBlock != null) { node = previousBlock; nodeOffset -= node.SymbolCount; Invariant.Assert(nodeOffset >= 0); } } localOffset = offset - nodeOffset; Invariant.Assert(localOffset >= 0 && localOffset <= node.Count); return node; } // Helper for InsertText. Inserts text to the left of an existing block. private static void InsertTextLeft(TextTreeTextBlock rightBlock, object text, int textOffset) { int newBlockCount; TextTreeTextBlock leftBlock; TextTreeTextBlock neighborBlock; TextTreeTextBlock newBlock; int count; int textEndOffset = -1; int i; int length; length = TextContainer.GetTextLength(text); if (rightBlock.GapOffset == 0) { // Try to fill neighbor block. neighborBlock = (TextTreeTextBlock)rightBlock.GetPreviousNode(); if (neighborBlock != null) { textOffset += neighborBlock.InsertText(neighborBlock.Count, text, textOffset, length); } } if (textOffset < length) { // Try adding just one block. newBlockCount = 1; leftBlock = rightBlock.SplitBlock(); // Fill up the left block. textOffset += leftBlock.InsertText(leftBlock.Count, text, textOffset, length); if (textOffset < length) { // Fill up the larger block. // We need to copy from the end of the text here. count = Math.Min(rightBlock.FreeCapacity, length - textOffset); textEndOffset = length - count; rightBlock.InsertText(0, text, textEndOffset, length); if (textOffset < textEndOffset) { // We've filled both blocks, and there's still more text to copy. // Prepare to allocate some more blocks. newBlockCount += (textEndOffset - textOffset + TextTreeTextBlock.MaxBlockSize - 1) / TextTreeTextBlock.MaxBlockSize; } } for (i = 1; i < newBlockCount; i++) { newBlock = new TextTreeTextBlock(TextTreeTextBlock.MaxBlockSize); textOffset += newBlock.InsertText(0, text, textOffset, textEndOffset); newBlock.InsertAtNode(leftBlock, false /* insertBefore */); leftBlock = newBlock; } Invariant.Assert(newBlockCount == 1 || textOffset == textEndOffset, "Not all text copied!"); } } // Helper for InsertText. Inserts text to the right of an existing block. private static void InsertTextRight(TextTreeTextBlock leftBlock, object text, int textOffset) { int newBlockCount; TextTreeTextBlock rightBlock; TextTreeTextBlock neighborBlock; TextTreeTextBlock newBlock; int count; int textEndOffset; int i; textEndOffset = TextContainer.GetTextLength(text); if (leftBlock.GapOffset == leftBlock.Count) { // Try to fill neighbor block. neighborBlock = (TextTreeTextBlock)leftBlock.GetNextNode(); if (neighborBlock != null) { count = Math.Min(neighborBlock.FreeCapacity, textEndOffset - textOffset); neighborBlock.InsertText(0, text, textEndOffset - count, textEndOffset); textEndOffset -= count; } } if (textOffset < textEndOffset) { // Try adding just one block. newBlockCount = 1; rightBlock = leftBlock.SplitBlock(); // Fill up the right block. count = Math.Min(rightBlock.FreeCapacity, textEndOffset - textOffset); rightBlock.InsertText(0, text, textEndOffset - count, textEndOffset); textEndOffset -= count; if (textOffset < textEndOffset) { // Fill up the larger block. // We need to copy from the end of the text here. textOffset += leftBlock.InsertText(leftBlock.Count, text, textOffset, textEndOffset); if (textOffset < textEndOffset) { // We've filled both blocks, and there's still more text to copy. // Prepare to allocate some more blocks. newBlockCount += (textEndOffset - textOffset + TextTreeTextBlock.MaxBlockSize - 1) / TextTreeTextBlock.MaxBlockSize; } } for (i=0; i
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TokenizerHelper.cs
- Transform3D.cs
- ObjectContext.cs
- SiteMapSection.cs
- OutputCacheSettingsSection.cs
- ExecutionProperties.cs
- ThaiBuddhistCalendar.cs
- MimeObjectFactory.cs
- EntityDataSourceContainerNameItem.cs
- IDQuery.cs
- DES.cs
- StaticContext.cs
- VerticalAlignConverter.cs
- ColorDialog.cs
- _NestedMultipleAsyncResult.cs
- DigestTraceRecordHelper.cs
- FixedSOMFixedBlock.cs
- ChildrenQuery.cs
- OpacityConverter.cs
- InfoCardRSAOAEPKeyExchangeFormatter.cs
- DataObject.cs
- ConsumerConnectionPointCollection.cs
- WindowsFormsHostAutomationPeer.cs
- sqlpipe.cs
- XslException.cs
- StyleXamlTreeBuilder.cs
- XslTransformFileEditor.cs
- ReliableSessionBindingElementImporter.cs
- TypeConverter.cs
- CellTreeNode.cs
- PageBreakRecord.cs
- SafeLibraryHandle.cs
- PerformanceCountersElement.cs
- GridToolTip.cs
- RadioButtonBaseAdapter.cs
- LoginUtil.cs
- WebPartEditorApplyVerb.cs
- SafeSystemMetrics.cs
- XmlChildNodes.cs
- XPathMessageFilterElementCollection.cs
- XmlWrappingReader.cs
- RtfFormatStack.cs
- MetadataItemEmitter.cs
- TcpChannelHelper.cs
- ReflectionHelper.cs
- ComponentGlyph.cs
- List.cs
- UITypeEditor.cs
- ParameterCollection.cs
- UnionExpr.cs
- ContourSegment.cs
- Parameter.cs
- UseLicense.cs
- LowerCaseStringConverter.cs
- IntegerValidator.cs
- HtmlInputPassword.cs
- RegexParser.cs
- SignedInfo.cs
- XmlBinaryReaderSession.cs
- CustomTypeDescriptor.cs
- listviewsubitemcollectioneditor.cs
- WindowsAuthenticationEventArgs.cs
- WebPermission.cs
- CharKeyFrameCollection.cs
- DataRelation.cs
- ButtonRenderer.cs
- DataGridView.cs
- TypeDelegator.cs
- CategoryGridEntry.cs
- FacetValueContainer.cs
- LinearKeyFrames.cs
- DataBoundLiteralControl.cs
- GridViewItemAutomationPeer.cs
- TraceInternal.cs
- ButtonBaseAdapter.cs
- DataGridViewCheckBoxColumn.cs
- ThreadAbortException.cs
- TraceContextRecord.cs
- ObfuscateAssemblyAttribute.cs
- PreProcessInputEventArgs.cs
- XmlHierarchicalDataSourceView.cs
- GetPageCompletedEventArgs.cs
- CharacterMetricsDictionary.cs
- CanonicalFormWriter.cs
- DbConvert.cs
- PropertyInformationCollection.cs
- EncryptedReference.cs
- BamlWriter.cs
- StandardRuntimeEnumValidatorAttribute.cs
- LinearKeyFrames.cs
- ExtensionDataObject.cs
- Activator.cs
- Frame.cs
- AffineTransform3D.cs
- DependencyStoreSurrogate.cs
- TiffBitmapDecoder.cs
- Odbc32.cs
- ControlDesignerState.cs
- GroupBoxRenderer.cs
- wgx_exports.cs