Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Documents / FixedTextBuilder.cs / 2 / FixedTextBuilder.cs
//---------------------------------------------------------------------------- //// Copyright (C) 2004 by Microsoft Corporation. All rights reserved. // // // Description: // FixedTextBuilder contains heuristics to map fixed document elements // into stream of flow text // // History: // 02/10/2004 - [....] ([....]) - Created. // //--------------------------------------------------------------------------- namespace System.Windows.Documents { using MS.Internal.Documents; using System.Windows.Controls; // UIElementCollection using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Markup; using System.Windows.Shapes; // Glyphs using System.Windows.Automation; using System.Windows.Documents.DocumentStructures; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Text; using System.IO; using System.Xml; using Path=System.Windows.Shapes.Path; using MS.Utility; //===================================================================== ////// FixedTextBuilder contains heuristics to map fixed document elements /// into stream of flow text. /// internal sealed class FixedTextBuilder { //------------------------------------------------------------------- // // Consts // //---------------------------------------------------------------------- #region Const internal const char FLOWORDER_SEPARATOR = ' '; #endregion Const //------------------------------------------------------------------- // // Statics // //---------------------------------------------------------------------- #region Statics // A list of CultureInfo that are always adjacent internal static CultureInfo[] AdjacentLanguage = { new CultureInfo("zh-CHS"), // Chinese Simplified new CultureInfo("zh-CHT"), // Chinese Traditional new CultureInfo("zh-HK"), // Chinese Hong Kong SAR new CultureInfo("zh-MO"), // Chinese Macau SAR new CultureInfo("zh-CN"), // Chinese China new CultureInfo("zh-SG"), // Chinese Singapore new CultureInfo("zh-TW"), // Chinese `Taiwan new CultureInfo("ja-JP"), // Japanese new CultureInfo("ko-KR"), // Korean new CultureInfo("th-TH") // Thai }; internal static bool AlwaysAdjacent(CultureInfo ci) { foreach (CultureInfo cultureInfo in AdjacentLanguage) { if (ci.Equals(cultureInfo)) { return true; } } return false; } // obtained via Unicode 3.0 book: C0 Controls and Basic Latin. // 0x002D/0x00AD and their related characters. // // NOTE it is okay to not getting accurate list as long as // we deal with common cases since this is used in heuristic // algorithm! internal static char[] HyphenSet = { '\x002D', // Hyphen-Minus '\x2010', // Hyphen '\x2011', // Non-breaking Hyphen '\x2012', // Figure-dash '\x2013', // En-dash '\x2212', // Minus Sign '\x00AD' // Soft-Hyphen }; internal static bool IsHyphen(char target) { foreach (char hyphen in HyphenSet) { if (hyphen == target) { return true; } } return false; } // Space that was used in the heuristic algorithm. internal static bool IsSpace(char target) { // Only the regular space character is considered // space. return (target == '\x0020'); } #endregion Statics //-------------------------------------------------------------------- // // Connstructors // //--------------------------------------------------------------------- #region Constructors internal FixedTextBuilder(FixedTextContainer container) { _container = container; _Init(); } #endregion Constructors //-------------------------------------------------------------------- // // Public Methods // //--------------------------------------------------------------------- //------------------------------------------------------------------- // // Public Properties // //--------------------------------------------------------------------- //-------------------------------------------------------------------- // // Public Events // //--------------------------------------------------------------------- //-------------------------------------------------------------------- // // Internal Methods // //---------------------------------------------------------------------- #region Internal Methods //------------------------------------------------------------------- // Virtualization //---------------------------------------------------------------------- // Add virtual FlowNode to represent the page internal void AddVirtualPage() { #if DEBUG DocumentsTrace.FixedTextOM.Builder.Trace(string.Format("AppendVirtualPage {0}", _pageStructures.Count)); #endif FixedPageStructure pageStructure = new FixedPageStructure(_pageStructures.Count); #if DEBUG pageStructure.FixedTextBuilder = this; #endif _pageStructures.Add(pageStructure); // Insert the virtural FlowNode into the Flow Order. _fixedFlowMap.FlowOrderInsertBefore(_fixedFlowMap.FlowEndEdge, pageStructure.FlowStart); } //------------------------------------------------------------------- // Devirtualizing flow structure //--------------------------------------------------------------------- // Making sure a page is devirtualized // All function that takes FixedNode as parameter and asks for FlowPosition // related content should call this functions first!!! internal bool EnsureTextOMForPage(int pageIndex) { Debug.Assert(!_IsBoundaryPage(pageIndex)); FixedPageStructure pageStructure = _pageStructures[pageIndex]; if (!pageStructure.Loaded) { EventTrace.NormalTraceEvent(EventTraceGuidId.DRXENSUREOMGUID, EventType.StartEvent); FixedPage page = _container.FixedDocument.SyncGetPage(pageIndex, false); if (page == null) return false; Size pageSize = _container.FixedDocument.ComputePageSize(page); page.Measure(pageSize); page.Arrange(new Rect(new Point(0, 0), pageSize)); Debug.Assert(page != null); Debug.Assert(page.IsInitialized); bool constructSOM = true; StoryFragments sf = page.GetPageStructure(); if (sf != null) { constructSOM = false; FixedDSBuilder fb = new FixedDSBuilder(page, sf); pageStructure.FixedDSBuilder = fb; } if (constructSOM) { FixedSOMPageConstructor pageConstructor = new FixedSOMPageConstructor(page, pageIndex); pageStructure.PageConstructor = pageConstructor; pageStructure.FixedSOMPage = pageConstructor.FixedSOMPage; } DocumentsTrace.FixedTextOM.Builder.Trace(string.Format("_EnsureTextOMForPage Loading...")); _CreateFixedMappingAndElementForPage(pageStructure, page, constructSOM); #if DEBUG // // Note: this debug verification is expensive. I have moved this code from FixedFlowMap.cs // to reduce the rate is is called. Now it is called after each page is constructed and might // still have effect on long documents and scrolling in page per stream case. // //FixedFlowMap.DebugVerifyMapping(true); #endif EventTrace.NormalTraceEvent(EventTraceGuidId.DRXENSUREOMGUID, EventType.EndEvent); return true; } #if DEBUG FixedPage fixedPage = _container.FixedDocument.SyncGetPage(pageIndex, false); fixedPage.FixedPageStructure = pageStructure; #endif return false; } //------------------------------------------------------------------- // Fixed Document //---------------------------------------------------------------------- // This could return null if FixedNode is an artificial boundary node internal FixedPage GetFixedPage(FixedNode node) { FixedDocument doc = _container.FixedDocument; return doc.SyncGetPageWithCheck(node.Page); } // This could return null if FixedNode is an artificial boundary node internal Glyphs GetGlyphsElement(FixedNode node) { FixedPage page = GetFixedPage(node); if (page != null) { return page.GetGlyphsElement(node); } return null; } //------------------------------------------------------------------- // Hit Testing / Keyboard Navigation //---------------------------------------------------------------------- // Given a fixed node, find its next/previous line // count: // in # of lines desired // out # of lines remaining // Return null if no next line internal FixedNode[] GetNextLine(FixedNode currentNode, bool forward, ref int count) { if (_IsBoundaryPage(currentNode.Page)) { return null; } EnsureTextOMForPage(currentNode.Page); FixedPageStructure ps = _pageStructures[currentNode.Page]; if (_IsStartVisual(currentNode[1])) { FixedNode[] firstLine = ps.FirstLine; if (firstLine == null) { return null; } currentNode = firstLine[0]; count--; } else if (_IsEndVisual(currentNode[1])) { FixedNode[] lastLine = ps.LastLine; if (lastLine == null) { return null; } currentNode = lastLine[0]; count--; } FixedSOMTextRun run = _fixedFlowMap.MappingGetFixedSOMElement(currentNode, 0) as FixedSOMTextRun; if (run == null) { return null; } int lineIndex = run.LineIndex; return ps.GetNextLine(lineIndex, forward, ref count); } // Given a fixed node // Return null is cannot get line internal FixedNode[] GetLine(int pageIndex, Point pt) { EnsureTextOMForPage(pageIndex); return _pageStructures[pageIndex].FindSnapToLine(pt); } // Find first line on page internal FixedNode[] GetFirstLine(int pageIndex) { EnsureTextOMForPage(pageIndex); return _pageStructures[pageIndex].FirstLine; } //----------------------------------------------- // Fixed nodes ==> FlowPosition //----------------------------------------------- // Find out flow offset given fixed position internal FlowPosition CreateFlowPosition(FixedPosition fixedPosition) { // make sure page has been loaded EnsureTextOMForPage(fixedPosition.Page); FixedSOMElement element = _fixedFlowMap.MappingGetFixedSOMElement(fixedPosition.Node, fixedPosition.Offset); if (element != null) { FlowNode flow = element.FlowNode; int fixedOffset = fixedPosition.Offset; FixedSOMTextRun run = element as FixedSOMTextRun; if (run != null && run.IsReversed) { fixedOffset = run.EndIndex - run.StartIndex - fixedOffset; } int offset = element.OffsetInFlowNode + fixedOffset - element.StartIndex; return new FlowPosition(_container, flow, offset); } return null; } internal FlowPosition GetPageStartFlowPosition(int pageIndex) { EnsureTextOMForPage(pageIndex); FlowNode fn = _pageStructures[pageIndex].FlowStart; // Remove this assert once we start supporting element across page bounary Debug.Assert(fn.Type == FlowNodeType.Start); return new FlowPosition(_container, fn, 0); } internal FlowPosition GetPageEndFlowPosition(int pageIndex) { EnsureTextOMForPage(pageIndex); // Remove this assert once we start supporting element across page bounary FlowNode fn = _pageStructures[pageIndex].FlowEnd; return new FlowPosition(_container, fn, 1); } //----------------------------------------------- // FlowPosition ==> Fixed Nodes //----------------------------------------------- // This function can handle flow nodes that are mapped to fixed nodes (Object or Run type) and start and end nodes internal bool GetFixedPosition(FlowPosition position, LogicalDirection textdir, out FixedPosition fixedp) { // Currently broken on empty page and on start/end flow nodes! // Init out parameter fixedp = new FixedPosition(FixedFlowMap.FixedStartEdge, 0); int flowOffset; FlowNode flow; position.GetFlowNode(textdir, out flow, out flowOffset); FixedSOMElement[] fixes = flow.FixedSOMElements; if (fixes == null) { return false; } int loIndex = 0, hiIndex = fixes.Length - 1; while (hiIndex > loIndex) { int index = (hiIndex + loIndex + 1) >> 1; // middle, round up -- guarantee hiIndex >= index > loIndex if (fixes[index].OffsetInFlowNode > flowOffset) { hiIndex = index - 1; } else { loIndex = index; } } FixedSOMElement element = fixes[loIndex]; FixedSOMTextRun run; if (loIndex > 0 && textdir == LogicalDirection.Backward && element.OffsetInFlowNode == flowOffset) { //check if we should really be in the prior element FixedSOMElement last = fixes[loIndex - 1]; int offsetInLast = flowOffset - last.OffsetInFlowNode + last.StartIndex; if (offsetInLast == last.EndIndex) { run = last as FixedSOMTextRun; if (run != null && run.IsReversed) { offsetInLast = run.EndIndex - run.StartIndex - offsetInLast; } fixedp = new FixedPosition(last.FixedNode, offsetInLast); return true; } } run = element as FixedSOMTextRun; int fixedOffset = flowOffset - element.OffsetInFlowNode + element.StartIndex; if (run != null && run.IsReversed) { fixedOffset = run.EndIndex - run.StartIndex - fixedOffset; } fixedp = new FixedPosition(element.FixedNode, fixedOffset); return true; } // Find out fixed node given flow positions internal bool GetFixedNodesForFlowRange(FlowPosition pStart, FlowPosition pEnd, out FixedSOMElement[] somElements, out int firstElementStart, out int lastElementEnd) { Debug.Assert(pStart.CompareTo(pEnd) < 0); somElements = null; firstElementStart = 0; lastElementEnd = 0; FlowNode[] flowNodes; int charStart = 0; int charEnd = -1; int offsetStart; int offsetEnd; pStart.GetFlowNodes(pEnd, out flowNodes, out offsetStart, out offsetEnd); if (flowNodes.Length <= 0) { return false; } ArrayList ar = new ArrayList(); FlowNode flowStart = flowNodes[0]; FlowNode flowEnd = flowNodes[flowNodes.Length - 1]; foreach (FlowNode flowScan in flowNodes) { int skipBefore = 0; int stopAt = Int32.MaxValue; if (flowScan == flowStart) { skipBefore = offsetStart; } if (flowScan == flowEnd) { stopAt = offsetEnd; } if (flowScan.Type == FlowNodeType.Object) { FixedSOMElement[] fixes = flowScan.FixedSOMElements; Debug.Assert(fixes.Length == 1); ar.Add(fixes[0]); } if (flowScan.Type == FlowNodeType.Run) { FixedSOMElement[] fixes = flowScan.FixedSOMElements; foreach (FixedSOMElement element in fixes) { int startIndex = element.OffsetInFlowNode; if (startIndex >= stopAt) { break; } int endIndex = startIndex + element.EndIndex - element.StartIndex; if (endIndex <= skipBefore) { continue; } ar.Add(element); if (skipBefore >= startIndex && flowScan == flowStart) { charStart = element.StartIndex + skipBefore - startIndex; } if (stopAt <= endIndex && flowScan == flowEnd) { charEnd = element.StartIndex + stopAt - startIndex; break; } else if (stopAt == endIndex + 1) { charEnd = element.EndIndex; //in case this ends at beginning of next node } } }//endofifrun }//endofforeach FlowNode // This array could be empty! (Maybe...) Broken if it is. somElements = (FixedSOMElement[])ar.ToArray(typeof(FixedSOMElement)); if (somElements.Length == 0) { return false; } if (flowStart.Type == FlowNodeType.Object) { // Image firstElementStart = offsetStart; } else { firstElementStart = charStart; } if (flowEnd.Type == FlowNodeType.Object) { lastElementEnd = offsetEnd; } else { lastElementEnd = charEnd; } return true; } //----------------------------------------------- // FlowPosition ==> Flow Content //----------------------------------------------- // Helper function to retrieve text from FixedNodes that are mapped // to a flow run represented by a FlowPosition. internal string GetFlowText(FlowNode flowNode) { Debug.Assert(flowNode.Type == FlowNodeType.Run); StringBuilder sb = new StringBuilder(); FixedSOMElement[] fixes = flowNode.FixedSOMElements; Debug.Assert(flowNode.Type == FlowNodeType.Run); Debug.Assert(fixes != null); foreach (FixedSOMTextRun element in fixes) { sb.Append(element.Text); } return sb.ToString(); } internal static bool MostlyRTL(string s) { int RTL = 0; int LTR = 0; foreach (char c in s) { if (_IsRTL(c)) { RTL++; } else if (c != ' ') { LTR++; } } return (RTL > 0) && (LTR == 0 || (RTL / LTR >= 2)); } //Decides whether two lines specified by line heights and a vertical distance between them is considered on the same line //verticalDistance needs to be passed as top of line2 - top of line 1 internal static bool IsSameLine(double verticalDistance, double fontSize1, double fontSize2) { // According to spec for rubber band selection, to adjacent Glyphs are on same line if they have 50% overlap double smallSize = (fontSize1 < fontSize2) ? fontSize1 : fontSize2; double overlap = (verticalDistance > 0) ? (fontSize1 - verticalDistance) : (fontSize2 + verticalDistance); return overlap / smallSize > .5; } //------------------------------------------------------------------------------ // Design Note ([....] - 2004/11/15) - Heuristic to test if two FixedSOMTextRun adjacent // in geometry for the purpose of adding additional separator into non-adjacent runs. // This algorithm bias toward NOT adding separator. The reason is artifically breaking // a word is more annoying than missing a space between words. // // The following steps are applied in order: // 1. If the two TextRun belong to two different languages, they are not // adjacent. (A separator is needed) // 2. If the TextRun belongs to a language that does not use space as separator, // they are always adjacent. (Need additional input about Bidi and complext // script here. Currently NOT adjacent). // 3. If the two TextRuns belong to two different lines, they are NOT adjacent // unless the end of the previous GlyphRun is HYPHEN. // 3. For TextRuns on the same line: // a. If the last character of the previous run is SPACE, they are adjacent. // b. If they are in different Bidi embedding level, they are NOT adjacent. // c. If the distance between their InkBoundingBox is greater than 1/4 of // the BoundingBox of the preceeding GlyphRun, they are NOT adjacent. // (This can be tweaked to use step function in the future!). // All others are adjacent Glyphs! // //----------------------------------------------------------------------------- internal static bool IsNonContiguous(CultureInfo ciPrev, CultureInfo ciCurrent, bool isSidewaysPrev, bool isSidewaysCurrent, string strPrev, string strCurrent, GlyphComparison comparison) { if (ciPrev != ciCurrent) { return true; } if (AlwaysAdjacent(ciPrev)) { return false; } if (isSidewaysPrev != isSidewaysCurrent) { return true; // not adjacent } if (strPrev.Length == 0 || strCurrent.Length == 0) { return false; // adjacent } if (!isSidewaysPrev) { // Horizontal Lines int textLength = strPrev.Length; char lastChar = strPrev[textLength - 1]; if (IsSpace(lastChar)) { return false; // adjacent } if (comparison == GlyphComparison.DifferentLine || comparison == GlyphComparison.Unknown) { // Different Line if (!IsHyphen(lastChar)) { return true; // non adjacent } } else { return comparison != GlyphComparison.Adjacent; } } return false; // Default is adjacent } #endregion Internal Methods //-------------------------------------------------------------------- // // Internal Properties // //--------------------------------------------------------------------- #region Internal Properties internal FixedFlowMap FixedFlowMap { get { return _fixedFlowMap; } } #if DEBUG internal FixedTextContainer FixedTextContainer { get { return _container; } } #endif #endregion Internal Propeties //------------------------------------------------------------------- // // Private Methods // //--------------------------------------------------------------------- #region Private Methods //-------------------------------------------------------------------- // Initilization //--------------------------------------------------------------------- private void _Init() { // Initialize Id _nextScopeId = FixedFlowMap.FlowOrderScopeIdStart; // Create empty mapping _fixedFlowMap = new FixedFlowMap(); // _pageStructures = new List(); } //-------------------------------------------------------------------- // Heuristics // // Design Note ([....]): // Page boundary is artificially represented by a pair // of FixedNodes. Start of Page uses int.MinValue as // its glyphs index, while End of Page uses int.MaxValue // as its glyphs index. All users of FixedNode needs // to be aware of such articifical index and special case // so that the "fake" glyphs indice are not used to access // children. One should always use FixedPage.GetGlyphs // instead of using FixedPage's logical children collection // directly, and should always check for possible null return. // // The page boundaries, however, are mapped to a FlowNodeType.Run // instead of any other FlowNodeType. This is to be // consistent with the general principal that non-run type // FlowNode has no corresponding FixedNode. // // Each FlowNode, if it is of type FlowNodeType.Run, contains // a cookie that is the run length. //---------------------------------------------------------------------- // Helper function for efficient creation of FixedNode used during pre-order walking. // current index is @ childIndex // depending on nesting level, the prefix can be hold at // 1. no prefix (level1) // 2. level1Index // 3. pathPrefix. // FixedNode _NewFixedNode(int pageIndex, int nestingLevel, int level1Index, int[] pathPrefix, int childIndex) { if (nestingLevel == 1) { return FixedNode.Create(pageIndex, nestingLevel, childIndex, -1, null); } else if (nestingLevel == 2) { return FixedNode.Create(pageIndex, nestingLevel, level1Index, childIndex, null); } else { // For deeply nested path, we need to append current childIndex to a pathPrefix // to form the entire childPath. Debug.Assert(pathPrefix != null); int[] newPath = new int[pathPrefix.Length + 1]; pathPrefix.CopyTo(newPath, 0); newPath[newPath.Length - 1] = childIndex; return FixedNode.Create(pageIndex, nestingLevel, -1, -1, newPath); } } // Helper function to get Paths with ImageBrushes private bool _IsImage(object o) { System.Windows.Shapes.Path p = o as System.Windows.Shapes.Path; if (p != null) { return p.Fill is ImageBrush && p.Data != null; } return o is Image; } private bool _IsNonContiguous(FixedSOMTextRun prevRun, FixedSOMTextRun currentRun, GlyphComparison comparison) { Debug.Assert(prevRun != null); Debug.Assert(currentRun != null); if (prevRun.FixedNode == currentRun.FixedNode) { return currentRun.StartIndex != prevRun.EndIndex; } return IsNonContiguous(prevRun.CultureInfo, currentRun.CultureInfo, prevRun.IsSideways, currentRun.IsSideways, prevRun.Text, currentRun.Text, comparison); } private GlyphComparison _CompareGlyphs(Glyphs glyph1, Glyphs glyph2) { GlyphComparison comparison = GlyphComparison.DifferentLine; if (glyph1 == glyph2) { comparison = GlyphComparison.SameLine; } else if (glyph1 != null && glyph2 != null) { GlyphRun run1 = glyph1.ToGlyphRun(); GlyphRun run2 = glyph2.ToGlyphRun(); if (run1 != null && run2 != null) { Rect box1 = run1.ComputeAlignmentBox(); box1.Offset(glyph1.OriginX, glyph1.OriginY); Rect box2 = run2.ComputeAlignmentBox(); box2.Offset(glyph2.OriginX, glyph2.OriginY); bool LTR1 = ((glyph1.BidiLevel & 1) == 0); bool LTR2 = ((glyph2.BidiLevel & 1) == 0); GeneralTransform transform = glyph2.TransformToVisual(glyph1); Point prevPt = LTR1 ? box1.TopRight : box1.TopLeft; Point currentPt = LTR2 ? box2.TopLeft : box2.TopRight; if (transform != null) { transform.TryTransform(currentPt, out currentPt); } if (IsSameLine(currentPt.Y - prevPt.Y, box1.Height, box2.Height)) { comparison = GlyphComparison.SameLine; if (LTR1 == LTR2) { double xDistance = Math.Abs(currentPt.X - prevPt.X); double maxHeight = Math.Max(box1.Height, box2.Height); if (xDistance / maxHeight < .05) { comparison = GlyphComparison.Adjacent; } } } } } return comparison; } // Apply heuristics // Create FlowNode structure // Create Fixed to Flow mapping // Create FixedElement private void _CreateFixedMappingAndElementForPage(FixedPageStructure pageStructure, FixedPage page, bool constructSOM) { List fixedNodes = new List (); _GetFixedNodes(pageStructure, page.Children, 1, -1, null, constructSOM, fixedNodes, Matrix.Identity); FlowModelBuilder flowBuilder = new FlowModelBuilder(this, pageStructure, page); flowBuilder.FindHyperlinkPaths(page); if (constructSOM) { pageStructure.FixedSOMPage.MarkupOrder = fixedNodes; pageStructure.ConstructFixedSOMPage(fixedNodes); _CreateFlowNodes(pageStructure.FixedSOMPage, flowBuilder); pageStructure.PageConstructor = null; } else { pageStructure.FixedDSBuilder.ConstructFlowNodes(flowBuilder, fixedNodes); } flowBuilder.FinishMapping(); #if DEBUG pageStructure.FixedNodes = fixedNodes; //flowBuilder.DumpToFile("FlowDump_Page_" + pageStructure.PageIndex.ToString() + ".xml"); #endif } private void _GetFixedNodes( FixedPageStructure pageStructure, IEnumerable oneLevel, int nestingLevel, // the level of nesting int level1Index, // if nesting level == 2, this is leve1 1 index int[] pathPrefix, // if nesting level > 2, this is used to represent prefix, otherwise it is null bool constructLines, List fixedNodes, // start empty, nodes will be added to this list Matrix transform ) { int pageIndex = pageStructure.PageIndex; DocumentsTrace.FixedTextOM.Builder.Trace(string.Format("_FlowOrderAnalysis P{0}-L[{0}]", pageIndex, nestingLevel)); int currentScopeId = _NewScopeId(); // Create per run fixed nodes IFrameworkInputElement namedNode; int childIndex = 0; IEnumerator elements = oneLevel.GetEnumerator(); while (elements.MoveNext()) { if (!constructLines) { namedNode = elements.Current as IFrameworkInputElement; if (namedNode != null && namedNode.Name != null && namedNode.Name.Length != 0) { pageStructure.FixedDSBuilder.BuildNameHashTable(namedNode.Name, elements.Current as UIElement, fixedNodes.Count); } } if (_IsImage(elements.Current) || (elements.Current is Glyphs && (elements.Current as Glyphs).MeasurementGlyphRun != null)) { fixedNodes.Add( _NewFixedNode(pageIndex, nestingLevel, level1Index, pathPrefix, childIndex) ); // GlyphRuns are non contiguous due to Image } else if (constructLines && elements.Current is Path) { pageStructure.PageConstructor.ProcessPath(elements.Current as Path, transform); } else if (elements.Current is Canvas) { Transform localTransform = Transform.Identity; // Drill down to next level IEnumerable children; Canvas canvas = elements.Current as Canvas; children = canvas.Children; localTransform = canvas.RenderTransform; if (localTransform == null) { localTransform = Transform.Identity; } if (children != null) { int[] newPathPrefix = null; if (nestingLevel >= 2) { // anything more than two level deep, we need to use path array if (nestingLevel == 2) { Debug.Assert(pathPrefix == null); Debug.Assert(level1Index >= 0); newPathPrefix = new int[2]; newPathPrefix[0] = level1Index; } else { newPathPrefix = new int[pathPrefix.Length + 1]; pathPrefix.CopyTo(newPathPrefix, 0); } // Append the childIndex to newPathPrefix. Debug.Assert(newPathPrefix != null); newPathPrefix[newPathPrefix.Length - 1] = childIndex; } #if DEBUG else { Debug.Assert(pathPrefix == null && newPathPrefix == null); } #endif _GetFixedNodes( pageStructure, children, (nestingLevel + 1), // go to next nesting level (nestingLevel == 1 ? childIndex : -1), // use this index if we are going from 1 to 2 newPathPrefix, // otherwise use this path prefix constructLines, fixedNodes, transform * localTransform.Value ); }//endofElementIsCanvas } childIndex++; } } private void _CreateFlowNodes(FixedSOMPage somPage, FlowModelBuilder flowBuilder) { flowBuilder.AddStartNode(FixedElement.ElementType.Section); somPage.SetRTFProperties(flowBuilder.FixedElement); foreach (FixedSOMContainer container in somPage.SemanticBoxes) { _CreateFlowNodes(container, flowBuilder); } //Add the remaining hyperlinks at the end of the page flowBuilder.AddLeftoverHyperlinks(); flowBuilder.AddEndNode(); } //We will need to have a special case for an empty page private void _CreateFlowNodes(FixedSOMContainer node, FlowModelBuilder flowBuilder) { FixedElement.ElementType[] elementsForNode = node.ElementTypes; foreach (FixedElement.ElementType type in elementsForNode) { flowBuilder.AddStartNode(type); node.SetRTFProperties(flowBuilder.FixedElement); } List children = node.SemanticBoxes; foreach (FixedSOMSemanticBox box in children) { if (box is FixedSOMElement) { flowBuilder.AddElement((FixedSOMElement)box); } else if (box is FixedSOMContainer) { _CreateFlowNodes((FixedSOMContainer)box, flowBuilder); } else { Debug.Assert(false); } } foreach (FixedElement.ElementType type in elementsForNode) { flowBuilder.AddEndNode(); } } //------------------------------------------------------------------- // Fixed Document //---------------------------------------------------------------------- private bool _IsStartVisual(int visualIndex) { return visualIndex == FixedFlowMap.FixedOrderStartVisual; } private bool _IsEndVisual(int visualIndex) { return visualIndex == FixedFlowMap.FixedOrderEndVisual; } private bool _IsBoundaryPage(int pageIndex) { return ( pageIndex == FixedFlowMap.FixedOrderStartPage || pageIndex == FixedFlowMap.FixedOrderEndPage ); } // Advance the scope ID -- called when a new flow scope is needed. // the scope ID is used to identify the flow scope in flow order. // // For instance: // // All Id =1 consists of one scope while Id=2 opens a new scope (in this case a nested scope). // private int _NewScopeId() { return _nextScopeId++; } private static bool _IsRTL(char c) { /*return (c > 0x590 && c < 0x780) || (c >= 0xFB1D && c <= 0xFDFD) || (c >= 0xFE70 && c <= 0xFEFC);*/ return (c >= 0x5D0 && c <= 0x60B) || (c == 0x60D) || (c >= 0x61B && c <= 0x64A) || (c >= 0x66D && c <= 0x6D5 && c != 0x670) || (c == 0x6DD) || (c == 0x6E5) || (c == 0x6E6) || (c == 0x6EE) || (c == 0x6EF) || (c >= 0x6FA && c <= 0x70D) || (c == 0x710) || (c >= 0x712 && c <= 0x72F) || (c >= 0x74D && c <= 0x7A5) || (c == 0x7B1) || (c == 0xFB1D) || (c >= 0xFB1F && c <= 0xFD3D && c != 0xFB29) || (c >= 0xFD50 && c <= 0xFDFC) || (c >= 0xFE70 && c <= 0xFEFC); } #if DEBUG private static bool _IsCombiningMark(char c) { return (c > 0x590 && c < 0x5BE) || (c > 0x5BE && c < 0x5C8 && _cTable[c - 0x5BF]) || (c >= 0x610 && c <= 0x615) || (c >= 0x64B && c <= 0x65E) || c == 0x670 || (c >= 0x6D6 && c <= 0x6ED && _cTable[c - 0x6CE]) || c == 0x711 || (c >= 0x730 && c <= 0x74A) || c == 0xFB1D; } /*private static Brush _ChooseDebugColor(Glyphs g) { foreach (char c in g.UnicodeString) { if (c >= 0xFB1D) { return Brushes.Red; } else if (_IsCombiningMark(c)) { return Brushes.Blue; } } return Brushes.Green; }*/ #endif #endregion Private Methods //------------------------------------------------------------------- // // Private Properties // //--------------------------------------------------------------------- #region Private Properties #endregion Private Properties //------------------------------------------------------------------- // // Private Fields // //---------------------------------------------------------------------- #region Private Fields private readonly FixedTextContainer _container; // page container private List _pageStructures; // contain all FixedPageStructure for each page. private int _nextScopeId; // Next FlowNode ScopeId private FixedFlowMap _fixedFlowMap; private static bool[] _cTable = new bool[] { true, //0x5BF //Combining marks table false, true, true, false, // 0x5C0 - 3 true, true, false, true, //0x5C4 true, true, //0x6D6 - 7 true, true, true, true, //0x6D8 - B true, false, false, true, //C - F true, true, true, true, //0x6E0 - 3 true, false, false, true, //0x6E4 - 7 true, false, true, true, //0x6E8 - B true, true //C, D }; #endregion Private Fields //------------------------------------------------------------------- // // Private Class // //-------------------------------------------------------------------- #region Private Class internal sealed class FlowModelBuilder { private sealed class LogicalHyperlink { public LogicalHyperlink(Uri uri, Geometry geom, UIElement uiElement) { _uiElement = uiElement; _uri = uri; _geometry = geom; _boundingRect = geom.Bounds; //Get bounding rect _used = false; } public Uri Uri { get { return _uri; } } public Geometry Geometry { get { return _geometry; } } public Rect BoundingRect { get { return _boundingRect; } } public UIElement UIElement { get { return _uiElement; } } public bool Used { get { return _used; } set { _used = value; } } private UIElement _uiElement; private Uri _uri; private Geometry _geometry; private Rect _boundingRect; private bool _used; } private sealed class LogicalHyperlinkContainer : IEnumerable { public LogicalHyperlinkContainer() { _hyperlinks = new List (); } IEnumerator IEnumerable .GetEnumerator() { return _hyperlinks.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _hyperlinks.GetEnumerator(); } public void AddLogicalHyperlink(Uri uri, Geometry geometry, UIElement uiElement) { LogicalHyperlink hyperlink = new LogicalHyperlink(uri, geometry, uiElement); _hyperlinks.Add(hyperlink); } //Returns a Uri that is associated with a SOMElement if there is one //Also returns the actual UIElement as an output variable if a Path with NavigateUri //is used to make this SOMElement look like an actual hyperlink public Uri GetUri(FixedSOMElement element, FixedPage p, out UIElement shadowElement) { shadowElement = null; UIElement e = p.GetElement(element.FixedNode) as UIElement; if (e == null) { Debug.Assert(false); return null; } LogicalHyperlink logicalHyperlink = null; Uri relUri = FixedPage.GetNavigateUri(e); if (relUri == null && _hyperlinks.Count > 0) { Transform t = e.TransformToAncestor(p) as Transform; Geometry g; if (e is Glyphs) { GlyphRun run = ((Glyphs)e).ToGlyphRun(); Rect designRect = run.ComputeAlignmentBox(); designRect.Offset(run.BaselineOrigin.X, run.BaselineOrigin.Y); g = new RectangleGeometry(designRect); } else if (e is Path) { g = ((Path)e).Data; } else { Debug.Assert(e is Image); Image im = (Image)e; g = new RectangleGeometry(new Rect(0, 0, im.Width, im.Height)); } logicalHyperlink = _GetHyperlinkFromGeometry(g, t); if (logicalHyperlink != null) { relUri = logicalHyperlink.Uri; shadowElement = logicalHyperlink.UIElement; } } if (relUri == null) { return null; } return FixedPage.GetLinkUri(p, relUri); } //Marks the hyperlink associated with a specific UIElement as "used" public void MarkAsUsed(UIElement uiElement) { for (int i=0; i<_hyperlinks.Count; i++) { LogicalHyperlink hyperlink = _hyperlinks[i]; if (hyperlink.UIElement == uiElement) { hyperlink.Used = true; break; } } } private LogicalHyperlink _GetHyperlinkFromGeometry(Geometry geom, Transform t) { Geometry g = geom; if (t != null && !t.Value.IsIdentity) { g = PathGeometry.CreateFromGeometry(geom); g.Transform = t; } double minArea = g.GetArea() * .99; Rect r = g.Bounds; for (int i = 0; i < _hyperlinks.Count; i++) { // do fast rect overlap before doing more expensive geometric comparison if (r.IntersectsWith(_hyperlinks[i].BoundingRect)) { Geometry combined = Geometry.Combine(g, _hyperlinks[i].Geometry, GeometryCombineMode.Intersect, Transform.Identity); if (combined.GetArea() > minArea) { return _hyperlinks[i]; } } } return null; } private List _hyperlinks; } public FlowModelBuilder(FixedTextBuilder builder, FixedPageStructure pageStructure, FixedPage page) { _builder = builder; _container = builder._container; _pageIndex = pageStructure.PageIndex; _textRuns = new List (); _flowNodes = new List (); _fixedNodes = new List (); _nodesInLine = new List (); _lineResults = new List (); _endNodes = new Stack(); _fixedElements = new Stack(); _mapping = builder._fixedFlowMap; _pageStructure = pageStructure; _currentFixedElement = _container.ContainerElement; _lineLayoutBox = Rect.Empty; _logicalHyperlinkContainer = new LogicalHyperlinkContainer(); _fixedPage = page; #if DEBUG _dumpDoc = new XmlDocument(); _currentDumpNode = _dumpDoc.CreateElement("FlowModel"); _dumpDoc.AppendChild(_currentDumpNode); #endif } public void FindHyperlinkPaths(FrameworkElement elem) { //we are only interested in hyperlinks created by putting Path on top of a Gyphs element Debug.Assert(elem is FixedPage || elem is Canvas); IEnumerable children = LogicalTreeHelper.GetChildren(elem); foreach (UIElement child in children) { Canvas canvas = child as Canvas; if (canvas != null) { FindHyperlinkPaths(canvas); } if (!(child is Path) || ((Path)child).Fill is ImageBrush) { // ignore these, these are content continue; } Uri navUri = FixedPage.GetNavigateUri(child); if (navUri != null && ((Path)child).Data != null) { Transform trans = child.TransformToAncestor(_fixedPage) as Transform; Geometry geom = ((Path)child).Data; if (trans != null && !trans.Value.IsIdentity) { geom = PathGeometry.CreateFromGeometry(geom); geom.Transform = trans; } _logicalHyperlinkContainer.AddLogicalHyperlink(navUri, geom, child); } } } public void AddLeftoverHyperlinks() { foreach (LogicalHyperlink hyperlink in _logicalHyperlinkContainer) { if (!hyperlink.Used) { _AddStartNode(FixedElement.ElementType.Paragraph); _AddStartNode(FixedElement.ElementType.Hyperlink); _currentFixedElement.SetValue(Hyperlink.NavigateUriProperty, hyperlink.Uri); _currentFixedElement.SetValue(FixedElement.HelpTextProperty, (String) (hyperlink.UIElement.GetValue(AutomationProperties.HelpTextProperty))); _currentFixedElement.SetValue(FixedElement.NameProperty, (String) (hyperlink.UIElement.GetValue(AutomationProperties.NameProperty))); _AddEndNode(); _AddEndNode(); } } } //Use this for start tags public void AddStartNode(FixedElement.ElementType type) { _FinishTextRun(true); _FinishHyperlink(); _AddStartNode(type); } public void AddEndNode() { _FinishTextRun(false); _FinishHyperlink(); _AddEndNode(); } //Use this for images and text runs -- generates necessary flow nodes public void AddElement(FixedSOMElement element) { FixedPage page = _builder.GetFixedPage(element.FixedNode); UIElement shadowHyperlink; Uri navUri = _logicalHyperlinkContainer.GetUri(element, page, out shadowHyperlink); if (element is FixedSOMTextRun) { // Will add code to get font info for rich copy here FixedSOMTextRun run = element as FixedSOMTextRun; bool createNewRun = (_currentRun == null) || (!run.HasSameRichProperties(_currentRun)) || navUri != _currentNavUri || (navUri != null && navUri.ToString() != _currentNavUri.ToString()); if (createNewRun) { if (_currentRun != null) { //Close existing inline tag FixedSOMFixedBlock parent = run.FixedBlock; FixedSOMTextRun lastRun = _textRuns[_textRuns.Count - 1]; Glyphs currentRunGlyph = _builder.GetGlyphsElement(lastRun.FixedNode); Glyphs glyphs = _builder.GetGlyphsElement(run.FixedNode); GlyphComparison comparison = _builder._CompareGlyphs(currentRunGlyph, glyphs); bool addSpace = false; if (_builder._IsNonContiguous(lastRun, run, comparison)) { addSpace = true; } _FinishTextRun(addSpace); } _SetHyperlink(navUri, run.FixedNode, shadowHyperlink); //Open new Run tag and set RTF props _AddStartNode(FixedElement.ElementType.Run); run.SetRTFProperties(_currentFixedElement); _currentRun = run; } _textRuns.Add((FixedSOMTextRun)element); if (_fixedNodes.Count == 0 || _fixedNodes[_fixedNodes.Count - 1] != element.FixedNode) { _fixedNodes.Add(element.FixedNode); } } else if (element is FixedSOMImage) { FixedSOMImage image = (FixedSOMImage)element; _FinishTextRun(true); _SetHyperlink(navUri, image.FixedNode, shadowHyperlink); _AddStartNode(FixedElement.ElementType.InlineUIContainer); FlowNode flowImageNode = new FlowNode(_NewScopeId(), FlowNodeType.Object, null); // Create a new FixedElement to represent this new node. _container.OnNewFlowElement(_currentFixedElement, FixedElement.ElementType.Object, new FlowPosition(_container, flowImageNode, 0), new FlowPosition(_container, flowImageNode, 1), image.Source, _pageIndex ); _flowNodes.Add(flowImageNode); // Do fixed/flow mapping for image element.FlowNode = flowImageNode; flowImageNode.FixedSOMElements = new FixedSOMElement[] { element }; _mapping.AddFixedElement(element); // Do we need this? _fixedNodes.Add(element.FixedNode); //copy automation properties FixedElement fElement = (FixedElement)flowImageNode.Cookie; fElement.SetValue(FixedElement.NameProperty, image.Name); fElement.SetValue(FixedElement.HelpTextProperty, image.HelpText); _AddEndNode(); } else { Debug.Assert(false); } } public void FinishMapping() { _FinishLine(); _mapping.MappingReplace(_pageStructure.FlowStart, _flowNodes); _pageStructure.SetFlowBoundary(_flowNodes[0], _flowNodes[_flowNodes.Count-1]); _pageStructure.SetupLineResults(_lineResults.ToArray()); } #if DEBUG public void DumpToFile(string file) { //_dumpDoc.Save(file); StringWriter writer = new StringWriter(); _dumpDoc.Save(writer); } private void DumpFlowNode(FlowNode node) { FixedElement element = node.Cookie as FixedElement; if (element != null) { XmlElement newDumpNode = _dumpDoc.CreateElement(element.Type.Name); newDumpNode.SetAttribute("id", node.ScopeId.ToString()); _currentDumpNode.AppendChild(newDumpNode); _currentDumpNode = newDumpNode; } else { //Run int nodeLength = (int) node.Cookie; _currentDumpNode.SetAttribute("Cookie", nodeLength.ToString()); FixedSOMElement[] somElems = node.FixedSOMElements; if (somElems!=null) { StringBuilder strBuilder = new StringBuilder(); foreach (FixedSOMElement somElem in somElems) { FixedSOMTextRun run = somElem as FixedSOMTextRun; if (run != null) { strBuilder.Append(run.Text); } } _currentDumpNode.InnerText = strBuilder.ToString(); } } } #endif private void _AddStartNode(FixedElement.ElementType type) { FlowNode startNode = new FlowNode(_NewScopeId(), FlowNodeType.Start, _pageIndex); FlowNode endNode = new FlowNode(_NewScopeId(), FlowNodeType.End, _pageIndex); // add fixed element _container.OnNewFlowElement(_currentFixedElement, //_container.ContainerElement, type, new FlowPosition(_container, (FlowNode)startNode, 1), new FlowPosition(_container, (FlowNode)endNode, 0), null, _pageIndex ); // Create fixed element _fixedElements.Push(_currentFixedElement); _currentFixedElement = (FixedElement)startNode.Cookie; _flowNodes.Add(startNode); _endNodes.Push(endNode); #if DEBUG DumpFlowNode(startNode); #endif } private void _AddEndNode() { _flowNodes.Add((FlowNode)_endNodes.Pop()); _currentFixedElement = (FixedElement)_fixedElements.Pop(); #if DEBUG _currentDumpNode = (XmlElement) _currentDumpNode.ParentNode; #endif } private void _FinishTextRun(bool addSpace) { if (_textRuns.Count > 0) { int textRunLength = 0; FixedSOMTextRun run = null; for (int i=0; i<_textRuns.Count; i++) { run = _textRuns[i]; Glyphs glyphs = _builder.GetGlyphsElement(run.FixedNode); GlyphComparison comparison = _builder._CompareGlyphs(_lastGlyphs, glyphs); if (comparison == GlyphComparison.DifferentLine) { _FinishLine(); } _lastGlyphs = glyphs; _lineLayoutBox.Union(run.BoundingRect); run.LineIndex = _lineResults.Count; if (_nodesInLine.Count == 0 || _nodesInLine[_nodesInLine.Count - 1] != run.FixedNode) { _nodesInLine.Add(run.FixedNode); } textRunLength += run.EndIndex - run.StartIndex; Debug.Assert(run.EndIndex - run.StartIndex == run.Text.Length); if (i>0 && _builder._IsNonContiguous(_textRuns[i-1], run, comparison)) { _textRuns[i-1].Text = _textRuns[i-1].Text + " "; textRunLength++; } } if (addSpace && run.Text.Length>0 && !run.Text.EndsWith(" ", StringComparison.Ordinal) && !IsHyphen(run.Text[run.Text.Length - 1])) { run.Text = run.Text + " "; textRunLength ++; } if (textRunLength != 0) { FlowNode flowNodeRun = new FlowNode(_NewScopeId(), FlowNodeType.Run, textRunLength); // Add list of text runs to flow node flowNodeRun.FixedSOMElements = _textRuns.ToArray(); int offset = 0; foreach (FixedSOMTextRun textRun in _textRuns) { textRun.FlowNode = flowNodeRun; textRun.OffsetInFlowNode = offset; _mapping.AddFixedElement(textRun); offset += textRun.Text.Length; } //Debug.Assert(offset == textRunLength); _flowNodes.Add(flowNodeRun); #if DEBUG DumpFlowNode(flowNodeRun); #endif // clear the list _textRuns.Clear(); } } //Close the inline tag if any if (_currentRun != null) { _AddEndNode(); _currentRun = null; } } private void _FinishHyperlink() { if (_currentNavUri != null) { _AddEndNode(); // _currentNavUri = null; } } private void _SetHyperlink(Uri navUri, FixedNode node, UIElement shadowHyperlink) { if (navUri != _currentNavUri || (navUri != null && navUri.ToString() != _currentNavUri.ToString())) { if (_currentNavUri != null) { _AddEndNode(); // } if (navUri != null) { _AddStartNode(FixedElement.ElementType.Hyperlink); _currentFixedElement.SetValue(Hyperlink.NavigateUriProperty, navUri); UIElement uiElement = _fixedPage.GetElement(node) as UIElement; Debug.Assert(uiElement != null); if (uiElement != null) { _currentFixedElement.SetValue(FixedElement.HelpTextProperty, (String) (uiElement.GetValue(AutomationProperties.HelpTextProperty))); _currentFixedElement.SetValue(FixedElement.NameProperty, (String) (uiElement.GetValue(AutomationProperties.NameProperty))); if (shadowHyperlink != null) { _logicalHyperlinkContainer.MarkAsUsed(shadowHyperlink); } } } _currentNavUri = navUri; } } private void _FinishLine() { if (_nodesInLine.Count > 0) { FixedLineResult newLineResult = new FixedLineResult(_nodesInLine.ToArray(), _lineLayoutBox); Debug.Assert(newLineResult != null); _lineResults.Add(newLineResult); _nodesInLine.Clear(); _lineLayoutBox = Rect.Empty; } } private int _NewScopeId() { return _builder._nextScopeId++; } public FixedElement FixedElement { get { return _currentFixedElement; } } private int _pageIndex; private FixedTextContainer _container; private FixedTextBuilder _builder; private List _textRuns; private List _flowNodes; private List _fixedNodes; private List _nodesInLine; private List _lineResults; private Rect _lineLayoutBox; private Stack _endNodes; private Stack _fixedElements; private FixedElement _currentFixedElement; private FixedFlowMap _mapping; private FixedPageStructure _pageStructure; private Glyphs _lastGlyphs; private FixedSOMTextRun _currentRun; private LogicalHyperlinkContainer _logicalHyperlinkContainer; private FixedPage _fixedPage; private Uri _currentNavUri; #if DEBUG private XmlDocument _dumpDoc; private XmlElement _currentDumpNode; #endif } internal enum GlyphComparison { DifferentLine, SameLine, Adjacent, //also on same line Unknown } #endregion } } // 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
- StringSorter.cs
- LOSFormatter.cs
- TheQuery.cs
- MenuTracker.cs
- SRGSCompiler.cs
- CheckableControlBaseAdapter.cs
- LinkButton.cs
- SafeThreadHandle.cs
- XPathBinder.cs
- AnnotationObservableCollection.cs
- BindUriHelper.cs
- SamlSecurityToken.cs
- MULTI_QI.cs
- SamlAssertionKeyIdentifierClause.cs
- TextUtf8RawTextWriter.cs
- PageSettings.cs
- BooleanSwitch.cs
- InputMethodStateChangeEventArgs.cs
- CompiledIdentityConstraint.cs
- ClientSession.cs
- KeysConverter.cs
- HtmlFormParameterWriter.cs
- GridPattern.cs
- ContentPlaceHolder.cs
- XamlTreeBuilderBamlRecordWriter.cs
- InvokeBinder.cs
- XsltQilFactory.cs
- DescendentsWalkerBase.cs
- XmlUnspecifiedAttribute.cs
- TextEditorSelection.cs
- ToolStripSplitStackLayout.cs
- MethodToken.cs
- AttachedAnnotation.cs
- IConvertible.cs
- VisualBrush.cs
- ToolStripContentPanel.cs
- FilterElement.cs
- CounterCreationDataCollection.cs
- SqlLiftWhereClauses.cs
- DataGridRowAutomationPeer.cs
- SafeFileMappingHandle.cs
- XPathScanner.cs
- SvcMapFile.cs
- CodeArrayCreateExpression.cs
- PageCache.cs
- HttpWebResponse.cs
- StructuralComparisons.cs
- TranslateTransform.cs
- RectangleGeometry.cs
- FillRuleValidation.cs
- ColorContextHelper.cs
- SmtpFailedRecipientsException.cs
- precedingsibling.cs
- _HeaderInfoTable.cs
- WebPartVerb.cs
- XmlILStorageConverter.cs
- ImmutableObjectAttribute.cs
- CodeCommentStatement.cs
- ProtectedConfiguration.cs
- cookie.cs
- CombinedGeometry.cs
- PartitionedDataSource.cs
- RelationshipEndMember.cs
- ConstantProjectedSlot.cs
- TextPointerBase.cs
- TimersDescriptionAttribute.cs
- KeyInterop.cs
- DocumentManager.cs
- CmsInterop.cs
- TextSegment.cs
- DoubleUtil.cs
- ValidationRuleCollection.cs
- LocalServiceSecuritySettings.cs
- CmsUtils.cs
- EditorBrowsableAttribute.cs
- ReflectionUtil.cs
- ADRole.cs
- Imaging.cs
- ServiceErrorHandler.cs
- LicenseManager.cs
- MessageOperationFormatter.cs
- Conditional.cs
- LocalValueEnumerator.cs
- Pointer.cs
- DynamicObject.cs
- WeakReferenceEnumerator.cs
- SiteMap.cs
- DayRenderEvent.cs
- CodeDomDesignerLoader.cs
- ThicknessAnimationBase.cs
- NativeMethods.cs
- TTSEngineProxy.cs
- ResourceDescriptionAttribute.cs
- CheckedPointers.cs
- SingleStorage.cs
- DocobjHost.cs
- SoapTypeAttribute.cs
- WebEvents.cs
- PropertyTab.cs
- RegexFCD.cs