Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Documents / TextTreeText.cs / 1 / 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
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridViewCellConverter.cs
- TextServicesHost.cs
- Thread.cs
- XamlSerializationHelper.cs
- BrowserCapabilitiesFactory.cs
- ResourceReferenceExpression.cs
- PropertyRecord.cs
- GregorianCalendar.cs
- TdsParserHelperClasses.cs
- BooleanKeyFrameCollection.cs
- TemplateField.cs
- InstanceKeyCompleteException.cs
- InputProcessorProfiles.cs
- Application.cs
- ColumnBinding.cs
- RuntimeEnvironment.cs
- MetadataArtifactLoader.cs
- SerializationInfo.cs
- Timer.cs
- Rules.cs
- DrawItemEvent.cs
- Error.cs
- XmlnsCache.cs
- SQLMoney.cs
- MenuCommands.cs
- CompleteWizardStep.cs
- FunctionMappingTranslator.cs
- StrongNamePublicKeyBlob.cs
- TableHeaderCell.cs
- ParsedAttributeCollection.cs
- UriTemplateTableMatchCandidate.cs
- InstallerTypeAttribute.cs
- TypeBuilder.cs
- QilReference.cs
- NullableLongMinMaxAggregationOperator.cs
- FilteredDataSetHelper.cs
- KeyGestureConverter.cs
- RawStylusSystemGestureInputReport.cs
- PlainXmlWriter.cs
- DataGridViewAddColumnDialog.cs
- TextTrailingCharacterEllipsis.cs
- SqlCommand.cs
- SmiContextFactory.cs
- ComponentChangingEvent.cs
- ColumnProvider.cs
- SchemaConstraints.cs
- BindingBase.cs
- BuilderInfo.cs
- MediaEntryAttribute.cs
- OdbcDataReader.cs
- safemediahandle.cs
- CompilationRelaxations.cs
- XPathParser.cs
- HttpStreams.cs
- MdImport.cs
- WebPartCloseVerb.cs
- CharacterMetrics.cs
- XmlNode.cs
- DictionaryEntry.cs
- ObjectPersistData.cs
- HtmlTextArea.cs
- ComponentConverter.cs
- mongolianshape.cs
- Path.cs
- InputScope.cs
- FileNameEditor.cs
- JoinGraph.cs
- securestring.cs
- StylusShape.cs
- ApplicationServicesHostFactory.cs
- TailPinnedEventArgs.cs
- SoapInteropTypes.cs
- SmiConnection.cs
- MediaPlayer.cs
- ContentTextAutomationPeer.cs
- FontConverter.cs
- RefreshPropertiesAttribute.cs
- RequestQueue.cs
- DataControlFieldCell.cs
- CircleEase.cs
- DoubleAnimationClockResource.cs
- RegisteredArrayDeclaration.cs
- IndentedWriter.cs
- WinEventQueueItem.cs
- CompositionAdorner.cs
- HorizontalAlignConverter.cs
- DataRelationPropertyDescriptor.cs
- cryptoapiTransform.cs
- RuntimeVariablesExpression.cs
- VariantWrapper.cs
- Codec.cs
- MbpInfo.cs
- IPPacketInformation.cs
- ToolStripStatusLabel.cs
- RawTextInputReport.cs
- ActivityStatusChangeEventArgs.cs
- FunctionImportMapping.cs
- StandardCommands.cs
- ContentAlignmentEditor.cs
- ReadOnlyNameValueCollection.cs