/// <summary> /// This method applies the given culture to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="culture"> This parameter references the culture to apply to the range. </param> public void SetCulture(IndexedRange textRange, CultureInfo culture) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Culture = culture; } }
public static IndexedRange GetRange(NSRange theRange) { IndexedRange result; if (theRange.Location == NSRange.NotFound) { return(null); } if (!ranges.TryGetValue(theRange, out result)) { result = new IndexedRange(); result.Range = new NSRange(theRange.Location, theRange.Length); } return(result); }
public static void Draw(Painter painterSink, ITextMetrics metrics, IndexedRange range) { Contract.Requires(painterSink != null); Contract.Requires(metrics != null); for(int i = range.StartIndex; i <= range.LastIndex; ++i) { if(metrics.IsClusterStart(i)) { if(metrics.IsVisible(i)) { Rectangle region = metrics.Regions[i]; Point baseline = new Point( region.Left + metrics.BaselineOffset.Width, region.Top + metrics.BaselineOffset.Height); if(metrics.IsRightToLeft(i)) { baseline = new Point(region.Right + metrics.BaselineOffset.Width, baseline.Y); } painterSink.SaveState(); painterSink.Translate(baseline.X, baseline.Y); Outline outline = metrics.Outlines[i]; painterSink.Scale(outline.EmSize, outline.EmSize); if (outline.NormalizedOutline != null) { painterSink.Fill(outline.NormalizedOutline); } painterSink.RestoreState(); } } } }
/// <summary> /// This method applies the given font family to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="family"> This parameter references the font family to apply to the range. </param> public void SetFamily(IndexedRange textRange, string family) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Family = family; } }
/// <summary> /// This method applies the given font style to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="style"> This parameter indicates the font style to apply to the range. </param> public void SetStyle(IndexedRange textRange, FontStyle style) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Style = style; } }
/// <summary> /// This method applies the results of script analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="scriptAnalysis"> This parameter contains the results to apply to the range. </param> void TextAnalysisSink.SetScriptAnalysis( int textPosition, int textLength, ScriptAnalysis scriptAnalysis) { IndexedRange range = new IndexedRange(textPosition, textLength); foreach(int index in range) { _OutputSink.Characters[index].ScriptAnalysis = scriptAnalysis; } }
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); }
internal void Reset() { _Runs.Clear(); _States.Clear(); _Alignment = Alignment.Stretch; _Indentation = DefaultIndentation; _Leading = DefaultLeading; _Spacing = DefaultSpacing; _Tracking = DefaultTracking; _Text.Clear(); _ActiveCulture = DefaultCulture; _ActiveFamily = DefaultFamily; _ActivePointSize = DefaultPointSize; _ActiveHAlignment = Alignment.Stretch; _ActiveVAlignment = Alignment.Stretch; _ActiveInline = Size.Empty; _ActiveTextRange = IndexedRange.Empty; _ActiveStretch = FontStretch.Regular; _ActiveStyle = FontStyle.Regular; _ActiveWeight = FontWeight.Regular; _ActiveFeatures = null; }
/// <summary> /// This method converts a cluster range to a text range. /// </summary> /// <param name="clusters"> This parameter contains the cluster range to convert. </param> /// <returns> This method returns the converted text range. </returns> private IndexedRange ToTextRange(IndexedRange clusters) { int textLength = 0; foreach(int index in clusters) { textLength += _Clusters[index].Characters.Length; } int startIndex = _Clusters[clusters.StartIndex].Characters.StartIndex; return new IndexedRange(startIndex, textLength); }
/// <summary> /// This method retrieves cohesive runs of text having identical locales. /// </summary> /// <param name="textPosition"> This parameter indicates the text position. </param> /// <param name="textLength"> This output parameter indicates the length of text remaining for processing. </param> /// <returns> This method returns the run of text having a consistent locale at the given position. </returns> string TextAnalysisSource.GetLocaleName(int textPosition, out int textLength) { IndexedRange range = new IndexedRange(textPosition, _FullText.Length); foreach(int index in range) { if(_Characters[index].Culture != _Characters[textPosition].Culture) { textLength = index - textPosition; return _Characters[textPosition].Culture.Name; } } textLength = _FullText.Length - textPosition; return _Characters[textPosition].Culture.Name; }
public Builder ResetState() { Contract.Ensures(Contract.Result<Builder>() != null); _ActiveTextRange = IndexedRange.Empty; _ActiveCulture = DefaultCulture; _ActiveFamily = DefaultFamily; _ActiveFeatures = null; _ActivePointSize = DefaultPointSize; _ActiveStretch = FontStretch.Regular; _ActiveStyle = FontStyle.Regular; _ActiveWeight = FontWeight.Regular; _ActiveInline = Size.Empty; _ActiveHAlignment = Alignment.Stretch; _ActiveVAlignment = Alignment.Stretch; return this; }
/// <summary> /// This method applies the given font point size to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="pointSize"> This parameter contains the font size to apply to the range. </param> public void SetPointSize(IndexedRange textRange, float pointSize) { Contract.Requires(Check.IsPositive(pointSize)); Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].PointSize = pointSize; } }
public void ComputeRegion(IndexedRange textRange, out Rectangle result) { Contract.Requires(textRange.StartIndex < Regions.Count); Contract.Requires(textRange.LastIndex < Regions.Count); throw new NotSupportedException(); }
/// <summary> /// This method transforms the characters of the given text range to inline objects. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="inline"> This parameter indicates the size of the inline object. </param> /// <param name="hAlignment"> This parameter indicates the horizontal alignment of the inline object. </param> /// <param name="vAlignment"> This parameter indicates the vertical alignment of the inline object. </param> public void SetInline( IndexedRange textRange, Size inline, Alignment hAlignment, Alignment vAlignment) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Inline = inline; _OutputSink.Characters[index].HAlignment = hAlignment; _OutputSink.Characters[index].VAlignment = vAlignment; } }
/// <summary> /// This method applies the given font features to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="features"> This parameter references the collection of font features to apply to the range. </param> public void SetFeatures(IndexedRange textRange, FontFeatureCollection features) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Features = features; } }
/// <summary> /// This method applies the results of breakpoint analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="lineBreakpoints"> This parameter contains the results to apply to the range. </param> void TextAnalysisSink.SetLineBreakpoints( int textPosition, int textLength, DxLineBreakpoint[] lineBreakpoints) { IndexedRange range = new IndexedRange(textPosition, textLength); foreach(int index in range) { var breakpoint = lineBreakpoints[index - textPosition]; LineBreakCondition beforeCondition = LineBreakCondition.Neutral; switch(breakpoint.BreakConditionBefore) { case DxBreakCondition.CanBreak: beforeCondition = LineBreakCondition.CanBreak; break; case DxBreakCondition.MayNotBreak: beforeCondition = LineBreakCondition.MayNotBreak; break; case DxBreakCondition.MustBreak: beforeCondition = LineBreakCondition.MustBreak; break; case DxBreakCondition.Neutral: beforeCondition = LineBreakCondition.Neutral; break; } LineBreakCondition afterCondition = LineBreakCondition.Neutral; switch(breakpoint.BreakConditionAfter) { case DxBreakCondition.CanBreak: afterCondition = LineBreakCondition.CanBreak; break; case DxBreakCondition.MayNotBreak: afterCondition = LineBreakCondition.MayNotBreak; break; case DxBreakCondition.MustBreak: afterCondition = LineBreakCondition.MustBreak; break; case DxBreakCondition.Neutral: afterCondition = LineBreakCondition.Neutral; break; } _TextShaper.Characters[index].Breakpoint = new LineBreakpoint( beforeCondition, afterCondition, breakpoint.IsWhitespace, breakpoint.IsSoftHyphen); } }
/// <summary> /// This method applies the results of bidi-text analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="explicitLevel"> This parameter indicates the explicit bidi level for the range. </param> /// <param name="resolvedLevel"> This parameter indicates the resolved bidi level for the range. </param> void TextAnalysisSink.SetBidiLevel( int textPosition, int textLength, byte explicitLevel, byte resolvedLevel) { IndexedRange range = new IndexedRange(textPosition, textLength); _TextShaper.SetBidiLevel(range, resolvedLevel); }
/// <summary> /// This method retrieves the geometry for a formatted cluster. /// </summary> /// <param name="clusterIndex"> This parameter indicates the formatted cluster index. </param> /// <param name="bidiLevel"> This parameter indicates the bidi level of the cluster. </param> /// <param name="font"> This parameter references the font for the cluster. </param> /// <param name="input"> This parameter references the formatted text output. </param> /// <returns> This method returns the geometry for the formatted cluster if available; otherwise, this method returns <c>null</c> . </returns> public Shape Retrieve( IndexedRange glyphRange, bool isVertical, bool isRightToLeft, FontHandle font, List<Formatting.TextShaper.Glyph> glyphs) { ResizeInternalBuffers(glyphRange.Length); int index = 0; foreach(int itemIndex in glyphRange) { _GlyphAdvances[index] = glyphs[itemIndex].Advance; _GlyphIndices[index] = glyphs[itemIndex].Index; _GlyphOffsets[index] = new GlyphOffset { AdvanceOffset = glyphs[itemIndex].Offset.Width, AscenderOffset = glyphs[itemIndex].Offset.Height }; ++index; } TextGeometryKey key; key.Advances = _GlyphAdvances; key.Indices = _GlyphIndices; key.Offsets = _GlyphOffsets; Dictionary<TextGeometryKey, Shape> cacheForFont; if(_Cache.TryGetValue(font, out cacheForFont)) { Shape result; if(cacheForFont.TryGetValue(key, out result)) { return result; } } else { cacheForFont = new Dictionary<TextGeometryKey, Shape>(); _Cache.Add(font, cacheForFont); } Shape geometry = _Sink.CreateGeometry( key, isRightToLeft, isVertical, font); TextGeometryKey newKey; newKey.Advances = (float[])key.Advances.Clone(); newKey.Indices = (short[])key.Indices.Clone(); newKey.Offsets = (GlyphOffset[])key.Offsets.Clone(); cacheForFont.Add(newKey, geometry); return geometry; }
/// <summary> /// This method applies the given number substition to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="numberSubstitution"> This parameter references the number substitution to apply to the range. </param> public void SetNumberSubstitution(IndexedRange textRange, NumberSubstitution numberSubstitution) { Contract.Assert(textRange.IsWithin(_FullText)); foreach(int index in textRange) { _Characters[index].NumberSubstitution = numberSubstitution; } }
/// <summary> /// This method applies the given font weight to a range of characters. /// </summary> /// <param name="textRange"> This parameter indicates the range of characters to modify. </param> /// <param name="weight"> This parameter indicates the font weight to apply to the range. </param> public void SetWeight(IndexedRange textRange, FontWeight weight) { Contract.Assert(textRange.IsWithin(_OutputSink.FullText)); foreach(int index in textRange) { _OutputSink.Characters[index].Weight = weight; } }
/// <summary> /// This method retrieves cohesive runs of text having identical number substitutions. /// </summary> /// <param name="textPosition"> This parameter indicates the text position. </param> /// <param name="textLength"> This output parameter indicates the length of text remaining for processing. </param> /// <returns> This method returns the run of text having a consistent number substition at the given position. </returns> NumberSubstitution TextAnalysisSource.GetNumberSubstitution(int textPosition, out int textLength) { IndexedRange range = new IndexedRange(textPosition, _FullText.Length); foreach(int index in range) { if(_Characters[index].NumberSubstitution != _Characters[textPosition].NumberSubstitution) { textLength = index - textPosition; return _Characters[textPosition].NumberSubstitution; } } textLength = _FullText.Length - textPosition; return _Characters[textPosition].NumberSubstitution; }
/// <summary> /// This method applies the results of bidi-text analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="explicitLevel"> This parameter indicates the explicit bidi level for the range. </param> /// <param name="resolvedLevel"> This parameter indicates the resolved bidi level for the range. </param> void TextAnalysisSink.SetBidiLevel( int textPosition, int textLength, byte explicitLevel, byte resolvedLevel) { IndexedRange range = new IndexedRange(textPosition, textLength); foreach(int index in range) { _OutputSink.Characters[index].BidiLevel = resolvedLevel; } }
public Builder RestoreState() { Contract.Ensures(Contract.Result<Builder>() != null); TextRun activeState = _States.Pop(); _ActiveTextRange = activeState.TextRange; _ActiveCulture = activeState.Culture; _ActiveFamily = activeState.Family; _ActiveFeatures = activeState.Features; _ActivePointSize = activeState.PointSize; _ActiveStretch = activeState.Stretch; _ActiveStyle = activeState.Style; _ActiveWeight = activeState.Weight; _ActiveInline = activeState.Inline; _ActiveHAlignment = activeState.HAlignment; _ActiveVAlignment = activeState.VAlignment; return this; }
/// <summary> /// This method applies the results of breakpoint analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="lineBreakpoints"> This parameter contains the results to apply to the range. </param> void TextAnalysisSink.SetLineBreakpoints( int textPosition, int textLength, DxLineBreakpoint[] lineBreakpoints) { IndexedRange range = new IndexedRange(textPosition, textLength); foreach(int index in range) { _OutputSink.Characters[index].Breakpoint = new LineBreakpoint(lineBreakpoints[index - textPosition]); } }
/// <summary> /// This method applies the results of number substition analysis to a range of characters. /// </summary> /// <param name="textPosition"> This parameter indicates the starting index of the range. </param> /// <param name="textLength"> This parameter indicates the length of the range. </param> /// <param name="numberSubstitution"> This parameter references the number substition to apply to the range. </param> void TextAnalysisSink.SetNumberSubstitution( int textPosition, int textLength, NumberSubstitution numberSubstitution) { IndexedRange range = new IndexedRange(textPosition, textLength); foreach(int index in range) { _OutputSink.Characters[index].NumberSubstitution = numberSubstitution; } }
public void ComputeRegion(IndexedRange range, out Rectangle region) { float left = float.MaxValue; float top = float.MaxValue; float right = float.MinValue; float bottom = float.MinValue; foreach(int index in range) { // exclude invisible clusters from consideration if(IsVisible(index)) { // get the cluster index from the text index int cluster = _TextToCluster[index]; left = Math.Min(left, _Clusters[cluster].Region.Left); top = Math.Min(top, _Clusters[cluster].Region.Top); right = Math.Max(right, _Clusters[cluster].Region.Right); bottom = Math.Max(bottom, _Clusters[cluster].Region.Bottom); } } region = Rectangle.FromEdges(left, top, right, bottom); }