Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / FixedFindEngine.cs / 1305600 / FixedFindEngine.cs
//---------------------------------------------------------------------------- //// Copyright (C) 2004 by Microsoft Corporation. All rights reserved. // // // Description: // Implements fast, paginated search functionality for Fixed documents // // // History: // 03/13/2006 AGurcan - Created // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using System; using System.IO; using System.Xml; using System.Text; using System.Globalization; using System.Diagnostics; using System.Windows.Markup; internal sealed class FixedFindEngine { //Searches for the specified pattern and updates start *or* end pointers depending on search direction //At the end of the operation, start or end should be pointing to the beginning/end of the page //of occurance of pattern respectively internal static TextRange Find ( ITextPointer start, ITextPointer end, string findPattern, CultureInfo cultureInfo, bool matchCase, bool matchWholeWord, bool matchLast, bool matchDiacritics, bool matchKashida, bool matchAlefHamza) { Debug.Assert(start != null); Debug.Assert(end != null); Debug.Assert( ((start is DocumentSequenceTextPointer) && (end is DocumentSequenceTextPointer)) || ((start is FixedTextPointer) && (end is FixedTextPointer)) ); Debug.Assert(findPattern != null); if (findPattern.Length == 0) { return null; } IDocumentPaginatorSource paginatorSource = start.TextContainer.Parent as IDocumentPaginatorSource; DynamicDocumentPaginator paginator = paginatorSource.DocumentPaginator as DynamicDocumentPaginator; Debug.Assert(paginator != null); int pageNumber = -1; int endPageNumber = -1; if (matchLast) { endPageNumber = paginator.GetPageNumber( (ContentPosition) start); pageNumber = paginator.GetPageNumber( (ContentPosition) end); } else { endPageNumber = paginator.GetPageNumber( (ContentPosition) end); pageNumber = paginator.GetPageNumber( (ContentPosition) start); } TextRange result = null; CompareInfo compareInfo = cultureInfo.CompareInfo; bool replaceAlefWithAlefHamza = false; CompareOptions compareOptions = _InitializeSearch(cultureInfo, matchCase, matchAlefHamza, matchDiacritics, ref findPattern, out replaceAlefWithAlefHamza); //Translate the page number int translatedPageNumber = pageNumber; //If this is a DocumentSequence, we need to pass translated page number to the below call FixedDocumentSequence documentSequence = paginatorSource as FixedDocumentSequence; DynamicDocumentPaginator childPaginator = null; if (documentSequence != null) { documentSequence.TranslatePageNumber(pageNumber, out childPaginator, out translatedPageNumber); } if (pageNumber - endPageNumber != 0) { ITextPointer firstSearchPageStart = null; ITextPointer firstSearchPageEnd = null; _GetFirstPageSearchPointers(start, end, translatedPageNumber, matchLast, out firstSearchPageStart, out firstSearchPageEnd); Debug.Assert(firstSearchPageStart != null); Debug.Assert(firstSearchPageEnd != null); //Need to search the first page using TextFindEngine to start exactly from the requested search location to avoid false positives result = TextFindEngine.InternalFind( firstSearchPageStart, firstSearchPageEnd, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); if (result == null) { //Start from the next page and check all pages until the end pageNumber = matchLast ? pageNumber-1 : pageNumber+1; int increment = matchLast ? -1 : 1; for (; matchLast ? pageNumber >= endPageNumber : pageNumber <= endPageNumber; pageNumber+=increment) { FixedDocument fixedDoc = null; translatedPageNumber = pageNumber; childPaginator = null; if (documentSequence != null) { documentSequence.TranslatePageNumber(pageNumber, out childPaginator, out translatedPageNumber); fixedDoc = (FixedDocument) childPaginator.Source; } else { fixedDoc = paginatorSource as FixedDocument; } Debug.Assert(fixedDoc != null); String pageString = _GetPageString(fixedDoc, translatedPageNumber, replaceAlefWithAlefHamza); if (pageString == null) { //This is not a page-per-stream //Default back to slow search return TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); } if ( _FoundOnPage(pageString, findPattern, cultureInfo, compareOptions) ) { //Update end or start pointer depending on search direction if (documentSequence != null) { ChildDocumentBlock childBlock = documentSequence.TextContainer.FindChildBlock(fixedDoc.DocumentReference); if (matchLast) { end = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Backward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageEndFlowPosition(translatedPageNumber))); start = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Forward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageStartFlowPosition(translatedPageNumber))); } else { start = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Forward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageStartFlowPosition(translatedPageNumber))); end = new DocumentSequenceTextPointer(childBlock, new FixedTextPointer(false, LogicalDirection.Backward, fixedDoc.FixedContainer.FixedTextBuilder.GetPageEndFlowPosition(translatedPageNumber))); } } else { //We are working on a FixedDocument FixedTextBuilder textBuilder = ((FixedDocument)(paginatorSource)).FixedContainer.FixedTextBuilder; if (matchLast) { end = new FixedTextPointer(false, LogicalDirection.Backward, textBuilder.GetPageEndFlowPosition(pageNumber)); start = new FixedTextPointer(false, LogicalDirection.Forward, textBuilder.GetPageStartFlowPosition(pageNumber)); } else { start = new FixedTextPointer(false, LogicalDirection.Forward, textBuilder.GetPageStartFlowPosition(pageNumber)); end = new FixedTextPointer(false, LogicalDirection.Backward, textBuilder.GetPageEndFlowPosition(pageNumber)); } } result = TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); //If the result is null, this means we had a false positive if (result != null) { return result; } } } } } else { //Make sure fast search result and slow search result are consistent FixedDocument fixedDoc = childPaginator != null ? childPaginator.Source as FixedDocument : paginatorSource as FixedDocument; String pageString = _GetPageString(fixedDoc, translatedPageNumber, replaceAlefWithAlefHamza); if (pageString == null || _FoundOnPage(pageString, findPattern, cultureInfo, compareOptions)) { //The search is only limited to the current page result = TextFindEngine.InternalFind( start, end, findPattern, cultureInfo, matchCase, matchWholeWord, matchLast, matchDiacritics, matchKashida, matchAlefHamza); } } return result; } private static bool _FoundOnPage(string pageString, string findPattern, CultureInfo cultureInfo, CompareOptions compareOptions) { CompareInfo compareInfo = cultureInfo.CompareInfo; //We don't need to use LastIndexOf in this function even if mathcLast is true because //we are only trying to determine whether the pattern exists on a specific page or not. //Exact location will be determined in TextFindEngine.InternalFind string[] tokens = findPattern.Split(null); if (tokens != null) { foreach (string token in tokens) { if (!String.IsNullOrEmpty(token) && compareInfo.IndexOf(pageString, token, compareOptions) == -1) { return false; } } } return true; } private static CompareOptions _InitializeSearch (CultureInfo cultureInfo, bool matchCase, bool matchAlefHamza, bool matchDiacritics, ref string findPattern, out bool replaceAlefWithAlefHamza) { CompareOptions compareOptions = CompareOptions.None; replaceAlefWithAlefHamza = false; if (!matchCase) { compareOptions |= CompareOptions.IgnoreCase; } bool stringContainedBidiCharacter; bool stringContainedAlefCharacter; // Initialize Bidi flags whether the string contains the bidi characters // or alef character. TextFindEngine.InitializeBidiFlags( findPattern, out stringContainedBidiCharacter, out stringContainedAlefCharacter); if (stringContainedAlefCharacter && !matchAlefHamza) { // Replace the alef-hamza with the alef. findPattern = TextFindEngine.ReplaceAlefHamzaWithAlef(findPattern); replaceAlefWithAlefHamza = true; } // Ignore Bidi diacritics that use for only Bidi language. if (!matchDiacritics && stringContainedBidiCharacter) { // Ignore Bidi diacritics with checking non-space character. compareOptions |= CompareOptions.IgnoreNonSpace; } return compareOptions; } private static void _GetFirstPageSearchPointers ( ITextPointer start, ITextPointer end, int pageNumber, bool matchLast, out ITextPointer firstSearchPageStart, out ITextPointer firstSearchPageEnd) { if (matchLast) { //The page in question is the last page //Need to search between the start of the last page and the end pointer DocumentSequenceTextPointer endAsDSTP = end as DocumentSequenceTextPointer; if (endAsDSTP != null) { FlowPosition pageStartFlowPosition = ((FixedTextContainer)(endAsDSTP.ChildBlock.ChildContainer)).FixedTextBuilder.GetPageStartFlowPosition(pageNumber); firstSearchPageStart = new DocumentSequenceTextPointer(endAsDSTP.ChildBlock, new FixedTextPointer(false, LogicalDirection.Forward,pageStartFlowPosition)); } else { FixedTextPointer endAsFTP = end as FixedTextPointer; Debug.Assert(endAsFTP != null); firstSearchPageStart = new FixedTextPointer(false, LogicalDirection.Forward, endAsFTP.FixedTextContainer.FixedTextBuilder.GetPageStartFlowPosition(pageNumber)); } firstSearchPageEnd = end; } else { //The page in question is the first page //Need to search between the start pointer and the end of the first page DocumentSequenceTextPointer startAsDSTP = start as DocumentSequenceTextPointer; if (startAsDSTP != null) { FlowPosition pageEndFlowPosition = ((FixedTextContainer)startAsDSTP.ChildBlock.ChildContainer).FixedTextBuilder.GetPageEndFlowPosition(pageNumber); firstSearchPageEnd = new DocumentSequenceTextPointer( startAsDSTP.ChildBlock, new FixedTextPointer(false, LogicalDirection.Backward, pageEndFlowPosition)); } else { FixedTextPointer startAsFTP = start as FixedTextPointer; Debug.Assert(startAsFTP != null); firstSearchPageEnd = new FixedTextPointer(false, LogicalDirection.Backward, startAsFTP.FixedTextContainer.FixedTextBuilder.GetPageEndFlowPosition(pageNumber)); } firstSearchPageStart = start; } } private static String _GetPageString(FixedDocument doc, int translatedPageNo, bool replaceAlefWithAlefHamza) { String pageString = null; Debug.Assert(doc != null); Debug.Assert(translatedPageNo >= 0 && translatedPageNo < doc.PageCount); PageContent pageContent = doc.Pages[translatedPageNo]; Stream pageStream = pageContent.GetPageStream(); bool reverseRTL = true; if (doc.HasExplicitStructure) { reverseRTL = false; } if (pageStream != null) { pageString = _ConstructPageString(pageStream, reverseRTL); if (replaceAlefWithAlefHamza) { // Replace the alef-hamza with the alef. pageString = TextFindEngine.ReplaceAlefHamzaWithAlef(pageString); } } return pageString; } private static String _ConstructPageString(Stream pageStream, bool reverseRTL) { Debug.Assert(pageStream != null); XmlTextReader xmlTextReader = new XmlTextReader(pageStream); //Wrap around a compatibility reader XmlReader xmlReader = new XmlCompatibilityReader(xmlTextReader, _predefinedNamespaces); XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreWhitespace = true; settings.IgnoreComments = true; settings.ProhibitDtd = true; xmlReader = XmlReader.Create(xmlReader, settings); xmlReader.MoveToContent(); StringBuilder pageString = new StringBuilder(); bool isSideways = false; string unicodeStr = null; while (xmlReader.Read()) { switch (xmlReader.NodeType) { case XmlNodeType.Element: { if (xmlReader.Name == "Glyphs") { unicodeStr = xmlReader.GetAttribute("UnicodeString"); if (!String.IsNullOrEmpty(unicodeStr)) { string sidewaysString = xmlReader.GetAttribute("IsSideways"); isSideways = false; if (sidewaysString != null && String.Compare(sidewaysString, Boolean.TrueString, StringComparison.OrdinalIgnoreCase) == 0) { isSideways = true; } if (reverseRTL) { //This is to cover for MXDW generation //RTL Glyphs are saved LTR and bidi level is not set //In this case we need to reverse the UnicodeString string bidiLevelAsString = xmlReader.GetAttribute("BidiLevel"); int bidiLevel = 0; if (!String.IsNullOrEmpty(bidiLevelAsString)) { try { bidiLevel = Convert.ToInt32(bidiLevelAsString, CultureInfo.InvariantCulture); } catch (Exception) { } } string caretStops = xmlReader.GetAttribute("CaretStops"); if (bidiLevel == 0 && !isSideways && String.IsNullOrEmpty(caretStops) && FixedTextBuilder.MostlyRTL(unicodeStr)) { char[] chars = unicodeStr.ToCharArray(); Array.Reverse(chars); unicodeStr = new String(chars); } } pageString.Append(unicodeStr); } } } break; } } return pageString.ToString(); } //Private constructor to prevent the compiler from generating a default constructor (fxcop) private FixedFindEngine() { } static private string [] _predefinedNamespaces = new string [2] { "http://schemas.microsoft.com/xps/2005/06", XamlReaderHelper.DefinitionMetroNamespaceURI }; } } // 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
- AttributeQuery.cs
- ClientConfigurationSystem.cs
- ProfileSection.cs
- TextSpanModifier.cs
- ipaddressinformationcollection.cs
- TextHidden.cs
- Vector3DAnimationBase.cs
- XmlDocumentFieldSchema.cs
- PrtCap_Public_Simple.cs
- InputBindingCollection.cs
- RuntimeConfig.cs
- _DisconnectOverlappedAsyncResult.cs
- WorkerRequest.cs
- DocumentPageViewAutomationPeer.cs
- XDeferredAxisSource.cs
- XmlArrayItemAttribute.cs
- GridItemCollection.cs
- PeerApplicationLaunchInfo.cs
- SafeArrayTypeMismatchException.cs
- OperationContractAttribute.cs
- BitmapEffectGeneralTransform.cs
- QilInvoke.cs
- HijriCalendar.cs
- StylusCaptureWithinProperty.cs
- FileUpload.cs
- InkSerializer.cs
- OleDbConnectionPoolGroupProviderInfo.cs
- ContentOperations.cs
- IndexOutOfRangeException.cs
- AnnotationComponentChooser.cs
- NetMsmqBindingCollectionElement.cs
- ItemsControlAutomationPeer.cs
- OperationCanceledException.cs
- QueryRelOp.cs
- SoundPlayerAction.cs
- FreezableOperations.cs
- FrameworkContentElementAutomationPeer.cs
- Script.cs
- FontWeight.cs
- OleDbStruct.cs
- CodeCatchClauseCollection.cs
- TransactionState.cs
- MatcherBuilder.cs
- FacetEnabledSchemaElement.cs
- PlainXmlDeserializer.cs
- MruCache.cs
- UnitControl.cs
- ErrorLog.cs
- EventRouteFactory.cs
- ValueUnavailableException.cs
- _Connection.cs
- Bezier.cs
- DocumentApplicationJournalEntry.cs
- TemplatedEditableDesignerRegion.cs
- __Filters.cs
- sqlcontext.cs
- UncommonField.cs
- PreviewPrintController.cs
- EventlogProvider.cs
- Item.cs
- CheckBoxBaseAdapter.cs
- DependencyObjectPropertyDescriptor.cs
- ExtensionDataObject.cs
- BufferedMessageData.cs
- PartialCachingAttribute.cs
- ClientUtils.cs
- SqlClientWrapperSmiStreamChars.cs
- HtmlEncodedRawTextWriter.cs
- Compiler.cs
- WmlListAdapter.cs
- DataRecordInternal.cs
- BezierSegment.cs
- TextProperties.cs
- Int64AnimationBase.cs
- SQLDecimalStorage.cs
- Matrix3DValueSerializer.cs
- WebPartManager.cs
- TableColumn.cs
- DataGridViewControlCollection.cs
- KoreanCalendar.cs
- Regex.cs
- FlowNode.cs
- ReadWriteObjectLock.cs
- SqlNodeAnnotations.cs
- FormatterConverter.cs
- _LocalDataStoreMgr.cs
- BufferAllocator.cs
- TrustManagerPromptUI.cs
- BuilderElements.cs
- ConfigXmlText.cs
- ByteStream.cs
- Comparer.cs
- GeneratedContractType.cs
- SqlProvider.cs
- ProfileEventArgs.cs
- WebException.cs
- CachedFontFamily.cs
- Help.cs
- ContractsBCL.cs
- XamlTreeBuilder.cs