public TextPipeline(FontDevice fontDevice) { Contract.Requires(fontDevice != null); _FontDevice = fontDevice; _TextAnalyzer = new Analyzer(_FontDevice.Factory); _AggregatorSink = new AggregatorSink(); _Aggregator = new Aggregator(_AggregatorSink); _ShaperSink = new ShaperSink(); _Shaper = new Shaper(_FontDevice, _ShaperSink); _FormatterSink = new FormatterSink(); _Formatter = new Formatter(_FormatterSink); _TypesetterSink = new TypesetterSink(); _Typesetter = new Typesetter(_TypesetterSink); _GeometryCache = new TextGeometryCache(); }
internal ParagraphMetrics( Paragraph paragraph, FormatterSink formattedData, TextGeometryCache geometryCache) { Contract.Requires(paragraph != null); Contract.Requires(formattedData != null); Contract.Requires(geometryCache != null); _Paragraph = paragraph; _Leading = formattedData.Leading; _LayoutRegion = formattedData.LayoutRegion; _BaselineOffset = formattedData.BaselineOffset; _Clusters = formattedData.Clusters.ToArray(); _ClusterBidiLevels = new byte[formattedData.Clusters.Count]; _Outlines = CreateOutlineList(formattedData, geometryCache, out _ClusterBidiLevels); // create the text index to cluster index transformation table _TextToCluster = new int[formattedData.FullText.Length]; for(int i = 0; i < _Clusters.Length; ++i) { foreach(int characterIndex in _Clusters[i].Characters) { _TextToCluster[characterIndex] = i; } } // determine the region that encompasses all formatted clusters float left = float.MaxValue; float top = float.MaxValue; float right = float.MinValue; float bottom = float.MinValue; for(int i = 0; i < _Clusters.Length; ++i) { left = Math.Min(left, _Clusters[i].Region.Left); top = Math.Min(top, _Clusters[i].Region.Top); right = Math.Max(right, _Clusters[i].Region.Right); bottom = Math.Max(bottom, _Clusters[i].Region.Bottom); } _TextRegion = Rectangle.FromEdges(left, top, right, bottom); // determine the ranges of each line _LineListBuilder.Clear(); int lastLine = 0; IndexedRange range = IndexedRange.Empty; for(int i = 0; i < formattedData.Runs.Count; ++i) { if(formattedData.Runs[i].LineNumber > lastLine) { _LineListBuilder.Add(ToTextRange(range)); range = new IndexedRange(formattedData.Runs[i].Clusters.StartIndex, 0); lastLine = formattedData.Runs[i].LineNumber; } range = range.Extend(formattedData.Runs[i].Clusters.Length); } if(range.Length > 0) { _LineListBuilder.Add(ToTextRange(range)); } _Lines = new LineCollection(_LineListBuilder); // build a collection of regions mapping to text indexes _RegionListBuilder.Clear(); for(int i = 0; i < paragraph.Text.Length; ++i) { _RegionListBuilder.Add(_Clusters[_TextToCluster[i]].Region); } _Regions = new RegionCollection(_RegionListBuilder); }
/// <summary> /// This method creates an outline collection. /// </summary> /// <param name="formattedData"> This parameter references the formatted input sink. </param> /// <param name="geometryCache"> This parameter references the text geometry cache. </param> /// <param name="clusterBidiLevels"> This parameter references the cluster bidi levels. </param> /// <returns> This method returns a new outline collection containing an outline for each formatted cluster. </returns> private static OutlineCollection CreateOutlineList( FormatterSink formattedData, TextGeometryCache geometryCache, out byte[] clusterBidiLevels) { _OutlineListBuilder.Clear(); clusterBidiLevels = new byte[formattedData.Clusters.Count]; int geometryClusterIndex = 0; for(int i = 0; i < formattedData.Runs.Count; ++i) { FormattedRun run = formattedData.Runs[i]; FontFace face = run.Font.ResolveFace(); float emSize = face.Metrics.Ascent + face.Metrics.Descent; float baseline = face.Metrics.Ascent / emSize; foreach(int clusterIndex in run.Clusters) { Geometry geometry = geometryCache.Retrieve( clusterIndex, run.BidiLevel, run.Font, formattedData); _OutlineListBuilder.Add(new Outline(geometry, run.EmSize, baseline)); clusterBidiLevels[geometryClusterIndex] = run.BidiLevel; geometryClusterIndex++; } } return new OutlineCollection(_OutlineListBuilder); }