/// <summary> /// Create a rectangle of the two specified UV coordinates /// </summary> /// <param name="origin">line drawing origin</param> /// <param name="topLeft">logical top-left point</param> /// <param name="bottomRight">logical bottom-right point</param> /// <param name="line">container line</param> internal static Rect RectUV( Point origin, LSPOINT topLeft, LSPOINT bottomRight, TextMetrics.FullTextLine line ) { int dx = topLeft.x - bottomRight.x; if (dx == 1 || dx == -1) { // in certain situation LS can be off by 1 bottomRight.x = topLeft.x; } Rect rect = new Rect( new Point(line.Formatter.IdealToReal(topLeft.x, line.PixelsPerDip), line.Formatter.IdealToReal(topLeft.y, line.PixelsPerDip)), new Point(line.Formatter.IdealToReal(bottomRight.x, line.PixelsPerDip), line.Formatter.IdealToReal(bottomRight.y, line.PixelsPerDip)) ); if (DoubleUtil.AreClose(rect.TopLeft.X, rect.BottomRight.X)) { rect.Width = 0; } if (DoubleUtil.AreClose(rect.TopLeft.Y, rect.BottomRight.Y)) { rect.Height = 0; } return(rect); }
private double _baseGuidelineY; // the Y guideline of the text line. /// <summary> /// Construct drawing state for full text /// </summary> internal DrawingState( DrawingContext drawingContext, Point lineOrigin, MatrixTransform antiInversion, TextMetrics.FullTextLine currentLine ) { _drawingContext = drawingContext; _antiInversion = antiInversion; _currentLine = currentLine; if (antiInversion == null) { _lineOrigin = lineOrigin; } else { _vectorToLineOrigin = lineOrigin; } if (_drawingContext != null) { // LineServices draws GlyphRun and TextDecorations in multiple // callbacks and GlyphRuns may have different baselines. Pushing guideline // for each DrawGlyphRun are too costly. We optimize for the common case where // GlyphRuns and TextDecorations in the TextLine share the same baseline. _baseGuidelineY = lineOrigin.Y + currentLine.Baseline; _drawingContext.PushGuidelineY1(_baseGuidelineY); } }
/// <summary> /// Format and produce a text line either with or without previously known /// line break point. /// </summary> private TextLine FormatLineInternal( TextSource textSource, int firstCharIndex, int lineLength, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) { EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringBegin, "TextFormatterImp.FormatLineInternal Start"); // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak, textRunCache, (lineLength != 0), // Do optimal break if break is given true, // isSingleLineFormatting _textFormattingMode ); TextLine textLine = null; if (!settings.Pap.AlwaysCollapsible && previousLineBreak == null && lineLength <= 0 ) { // simple text line. textLine = SimpleTextLine.Create( settings, firstCharIndex, RealToIdealFloor(paragraphWidth), textSource.PixelsPerDip ) as TextLine; } if (textLine == null) { // content is complex, creating complex line textLine = new TextMetrics.FullTextLine( settings, firstCharIndex, lineLength, RealToIdealFloor(paragraphWidth), LineFlags.None ) as TextLine; } EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordText, EventTrace.Level.Verbose, EventTrace.Event.WClientStringEnd, "TextFormatterImp.FormatLineInternal End"); return(textLine); }
/// <summary> /// Map a UV ideal coordinate to an XY ideal coordinate /// </summary> /// <param name="origin">line drawing origin</param> /// <param name="vectorToOrigin">vector to line origin UV</param> /// <param name="u">ideal distance in text flow direction</param> /// <param name="v">ideal distance in paragraph flow direction</param> /// <param name="line">container line</param> /// <param name="nominalX">ideal X origin</param> /// <param name="nominalY">ideal Y origin</param> internal static void UVToNominalXY( Point origin, Point vectorToOrigin, int u, int v, TextMetrics.FullTextLine line, out int nominalX, out int nominalY ) { origin.Y += vectorToOrigin.Y; if (line.RightToLeft) { nominalX = line.ParagraphWidth - u + TextFormatterImp.RealToIdeal(-vectorToOrigin.X + origin.X); } else { nominalX = u + TextFormatterImp.RealToIdeal(vectorToOrigin.X + origin.X); } nominalY = v + TextFormatterImp.RealToIdeal(origin.Y); }
/// <summary> /// Map a UV ideal coordinate to an XY real coordinate /// </summary> /// <param name="origin">line drawing origin</param> /// <param name="vectorToOrigin">vector to line origin UV</param> /// <param name="u">ideal distance in text flow direction</param> /// <param name="v">ideal distance in paragraph flow direction</param> /// <param name="line">container line</param> internal static Point UVToXY( Point origin, Point vectorToOrigin, int u, int v, TextMetrics.FullTextLine line ) { Point xy; origin.Y += vectorToOrigin.Y; if (line.RightToLeft) { xy = new Point(line.Formatter.IdealToReal(line.ParagraphWidth - u, line.PixelsPerDip) - vectorToOrigin.X + origin.X, line.Formatter.IdealToReal(v, line.PixelsPerDip) + origin.Y); } else { xy = new Point(line.Formatter.IdealToReal(u, line.PixelsPerDip) + vectorToOrigin.X + origin.X, line.Formatter.IdealToReal(v, line.PixelsPerDip) + origin.Y); } return(xy); }
/// <summary> /// Map a UV real coordinate to an XY real coordinate /// </summary> /// <param name="origin">line drawing origin XY</param> /// <param name="vectorToOrigin">vector to line origin UV</param> /// <param name="u">real distance in text flow direction</param> /// <param name="v">real distance in paragraph flow direction</param> /// <param name="line">container line</param> internal static Point UVToXY( Point origin, Point vectorToOrigin, double u, double v, TextMetrics.FullTextLine line ) { Point xy; origin.Y += vectorToOrigin.Y; if (line.RightToLeft) { xy = new Point(line.Formatter.IdealToReal(line.ParagraphWidth) - vectorToOrigin.X - u + origin.X, v + origin.Y); } else { xy = new Point(u + vectorToOrigin.X + origin.X, v + origin.Y); } return(xy); }
/// <summary> /// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content /// </summary> /// <param name="textSource">an object representing text layout clients text source for TextFormatter.</param> /// <param name="firstCharIndex">character index to specify where in the source text the line starts</param> /// <param name="paragraphProperties">properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.</param> /// <param name="textRunCache">an object representing content cache of the client.</param> /// <returns>min max paragraph width</returns> public override MinMaxParagraphWidth FormatMinMaxParagraphWidth( TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) { // prepare formatting settings FormatSettings settings = PrepareFormatSettings( textSource, firstCharIndex, 0, // infinite paragraphWidth paragraphProperties, null, // always format the whole paragraph - no previousLineBreak textRunCache, false, // optimalBreak true, // isSingleLineFormatting _textFormattingMode ); // create specialized line specifically for min/max calculation TextMetrics.FullTextLine line = new TextMetrics.FullTextLine( settings, firstCharIndex, 0, // lineLength 0, // paragraph width has no significant meaning in min/max calculation (LineFlags.KeepState | LineFlags.MinMax) ); // line width in this case is the width of a line when the entire paragraph is laid out // as a single long line. MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width); line.Dispose(); return(minMax); }