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
- TableLayoutPanelDesigner.cs
- BufferedGraphicsManager.cs
- invalidudtexception.cs
- FunctionQuery.cs
- BaseDataListPage.cs
- AcceleratedTokenAuthenticator.cs
- SqlDataSourceFilteringEventArgs.cs
- FontConverter.cs
- SmtpFailedRecipientException.cs
- ListViewHitTestInfo.cs
- cryptoapiTransform.cs
- SolidColorBrush.cs
- PropertyRef.cs
- TableCellCollection.cs
- GenericTypeParameterConverter.cs
- TypeTypeConverter.cs
- ValueType.cs
- autovalidator.cs
- StorageAssociationTypeMapping.cs
- TextRunTypographyProperties.cs
- AutoCompleteStringCollection.cs
- BinaryObjectWriter.cs
- MethodCallExpression.cs
- ProfilePropertyMetadata.cs
- ScriptRef.cs
- CompositeTypefaceMetrics.cs
- ExpressionConverter.cs
- StrokeFIndices.cs
- ThicknessAnimationBase.cs
- LongValidator.cs
- SafeArchiveContext.cs
- Style.cs
- PersonalizablePropertyEntry.cs
- EntityViewGenerationAttribute.cs
- OciLobLocator.cs
- ObjectContext.cs
- PointLight.cs
- CharEnumerator.cs
- KeyInstance.cs
- ProxyManager.cs
- AbsoluteQuery.cs
- ConvertersCollection.cs
- WindowPatternIdentifiers.cs
- ToolboxItemSnapLineBehavior.cs
- _LoggingObject.cs
- SerializationStore.cs
- FixedPosition.cs
- PrePrepareMethodAttribute.cs
- ContextStack.cs
- ListItemParagraph.cs
- GeometryHitTestParameters.cs
- SerializableAttribute.cs
- UniqueEventHelper.cs
- FontResourceCache.cs
- SqlEnums.cs
- SecurityNegotiationException.cs
- MulticastNotSupportedException.cs
- InstalledFontCollection.cs
- InvariantComparer.cs
- SimpleTypeResolver.cs
- KnownTypesProvider.cs
- TransactionManager.cs
- TimersDescriptionAttribute.cs
- WebPartConnectVerb.cs
- NativeMethodsOther.cs
- UserControlDesigner.cs
- TypeToArgumentTypeConverter.cs
- SamlEvidence.cs
- ProcessProtocolHandler.cs
- UserPreferenceChangedEventArgs.cs
- TextViewElement.cs
- Connection.cs
- ReadOnlyDictionary.cs
- BaseTreeIterator.cs
- CellParagraph.cs
- precedingquery.cs
- BaseValidator.cs
- DrawingContextDrawingContextWalker.cs
- BamlMapTable.cs
- ResourceReferenceKeyNotFoundException.cs
- XmlTextWriter.cs
- sqlser.cs
- DefaultEventAttribute.cs
- Baml2006Reader.cs
- DbConnectionInternal.cs
- PhysicalFontFamily.cs
- MarkupExtensionParser.cs
- StringSource.cs
- AttachmentCollection.cs
- LayoutExceptionEventArgs.cs
- TimerElapsedEvenArgs.cs
- FilterElement.cs
- NativeMethods.cs
- WorkflowHostingEndpoint.cs
- sqlstateclientmanager.cs
- BaseTreeIterator.cs
- ToolStripTemplateNode.cs
- FilterableData.cs
- WebConfigurationHostFileChange.cs
- Enum.cs