Example #1
0
        internal FormatSettings(
            TextFormatterImp    formatter,
            TextSource          textSource,
            TextRunCacheImp     runCache,
            ParaProp            pap,
            TextLineBreak       previousLineBreak,
            bool                isSingleLineFormatting,
            TextFormattingMode  textFormattingMode,
            bool                isSideways
            )
        {
            _isSideways     = isSideways;
            _textFormattingMode = textFormattingMode;
            _formatter      = formatter;
            _textSource     = textSource;
            _runCache       = runCache;
            _pap            = pap;
            _digitState     = new DigitState();
            _previousLineBreak = previousLineBreak;
            _maxLineWidth      = Constants.IdealInfiniteWidth;

            if (isSingleLineFormatting)
            {
                // Apply text indent on each line in single line mode
                _textIndent = _pap.Indent;
            }
        }
Example #2
0
        // ------------------------------------------------------------------
        // Constructor.
        //
        //      wrappingWidth - wrapping width for the line
        //      length - number or characters in the line
        //      width - width of the line 
        //      height - height of the line 
        //      baseline - baseline of the line 
        //      hasInlineObjects - has inline objects? 
        // ------------------------------------------------------------------
        internal LineMetrics(
#if DEBUG
                    double wrappingWidth, 
#endif
                    int length, 
                    double width, 
                    double height, 
                    double baseline, 
                    bool hasInlineObjects, 
                    TextLineBreak textLineBreak)
        {
#if DEBUG
            _wrappingWidth = wrappingWidth;
#endif
            _start = 0;
            _width  = width;
            _height = height;
            _baseline = baseline;
            _textLineBreak = textLineBreak;

            _packedData = ((uint) length & LengthMask) | (hasInlineObjects ? HasInlineObjectsMask : 0);
        }
Example #3
0
 /// <summary> 
 /// Client to format a text line that fills a paragraph in the document.
 /// </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="paragraphWidth">width of paragraph in which the line fills</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="previousLineBreak">text formatting state at the point where the previous line in the paragraph
 /// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous 
 /// line; this parameter can be null, and will always be null for the first line in a paragraph.</param> 
 /// <param name="textRunCache">an object representing content cache of the client.</param>
 /// <returns>object representing a line of text that client interacts with. </returns> 
 public abstract TextLine FormatLine(
     TextSource                  textSource,
     int                         firstCharIndex,
     double                      paragraphWidth, 
     TextParagraphProperties     paragraphProperties,
     TextLineBreak               previousLineBreak, 
     TextRunCache                textRunCache 
     );
Example #4
0
        internal static IList<TextBreakpoint> CreateMultiple(
            TextParagraphCache          paragraphCache,
            int                         firstCharIndex,
            int                         maxLineWidth,
            TextLineBreak               previousLineBreak,
            IntPtr                      penaltyRestriction,
            out int                     bestFitIndex            
            )
        {
            Invariant.Assert(paragraphCache != null);

            // grab full text state from paragraph cache
            FullTextState fullText = paragraphCache.FullText;
            Invariant.Assert(fullText != null);

            FormatSettings settings = fullText.TextStore.Settings;
            Invariant.Assert(settings != null);

            // update formatting parameters at line start
            settings.UpdateSettingsForCurrentLine(
                maxLineWidth,
                previousLineBreak, 
                (firstCharIndex == fullText.TextStore.CpFirst)
                );

            Invariant.Assert(settings.Formatter != null);

            // acquiring LS context
            TextFormatterContext context = settings.Formatter.AcquireContext(fullText, IntPtr.Zero);

            IntPtr previousBreakRecord = IntPtr.Zero;
            if (settings.PreviousLineBreak != null)
                previousBreakRecord = settings.PreviousLineBreak.BreakRecord.Value;

            // need not consider marker as tab since marker does not affect line metrics and it wasnt drawn.
            fullText.SetTabs(context);

            LsBreaks lsbreaks = new LsBreaks();

            LsErr lserr = context.CreateBreaks(
                fullText.GetBreakpointInternalCp(firstCharIndex),
                previousBreakRecord,
                paragraphCache.Ploparabreak.Value,  // para breaking session
                penaltyRestriction,
                ref lsbreaks, 
                out bestFitIndex
                );

            // get the exception in context before it is released
            Exception callbackException = context.CallbackException;
            
            // release the context
            context.Release();

            if(lserr != LsErr.None)
            {
                if(callbackException != null)
                {                        
                    // rethrow exception thrown in callbacks
                    throw callbackException;
                }
                else
                {
                    // throw with LS error codes
                    TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.CreateBreaksFailure, lserr), lserr);
                }
            }

            // keep context alive at least till here
            GC.KeepAlive(context);

            TextBreakpoint[] breakpoints = new TextBreakpoint[lsbreaks.cBreaks];

            for (int i = 0; i < lsbreaks.cBreaks; i++)
            {
                breakpoints[i] = new FullTextBreakpoint(
                    fullText,
                    firstCharIndex,
                    maxLineWidth,
                    ref lsbreaks,
                    i   // the current break
                    );
            }

            return breakpoints;
        }
Example #5
0
        /// <summary>
        /// Update formatting parameters at line start
        /// </summary>
        internal void UpdateSettingsForCurrentLine(
            int             maxLineWidth,
            TextLineBreak   previousLineBreak,
            bool            isFirstLineInPara
            )
        {
            _previousLineBreak = previousLineBreak;
            _digitState = new DigitState(); // reset digit state
            _maxLineWidth = Math.Max(maxLineWidth, 0);

            if (isFirstLineInPara)
            {
                _textIndent = _pap.Indent;
            }
            else
            {
                // Do not apply text indentation to all but the first line in para
                _textIndent = 0;
            }
        }
Example #6
0
		public TextLine FormatLine(TextSource textSource, int firstCharIndex, double paragraphWidth,
			TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak) {
			return formatter.FormatLine(textSource, firstCharIndex, paragraphWidth, paragraphProperties, previousLineBreak);
		}
Example #7
0
        // ------------------------------------------------------------------
        // Create and format text line.
        //
        //      lineStartIndex - index of the first character in the line
        //      width - wrapping width of the line
        //      lineProperties - properties of the line
        //      textRunCache - run cache used by text formatter
        //      showParagraphEllipsis - true if paragraph ellipsis is shown 
        //                              at the end of the line
        // ------------------------------------------------------------------
        internal void Format(int dcp, double width, TextParagraphProperties lineProperties, TextLineBreak textLineBreak, TextRunCache textRunCache, bool showParagraphEllipsis)
        {
#if TEXTPANELLAYOUTDEBUG
            TextPanelDebug.IncrementCounter("Line.Format", TextPanelDebug.Category.TextView);
#endif
            _mirror = (lineProperties.FlowDirection == FlowDirection.RightToLeft);
            _dcp = dcp;
            _showParagraphEllipsis = showParagraphEllipsis;
            _wrappingWidth = width;
            _line = _owner.TextFormatter.FormatLine(this, dcp, width, lineProperties, textLineBreak, textRunCache);
        }
Example #8
0
            internal LineEnumerator(FormattedText text)
            {
                _previousHeight = 0;
                _previousLength = 0;
                _previousLineBreak = null;

                _textStorePosition = 0;
                _lineCount = 0;
                _totalHeight = 0;
                _currentLine = null;
                _nextLine = null;
                _formatter = TextFormatter.FromCurrentDispatcher(text._textFormattingMode);
                _that = text;
                if (_that._textSourceImpl == null)
                    _that._textSourceImpl = new TextSourceImplementation(_that);
            }
Example #9
0
        internal override TextParagraphCache CreateParagraphCache(
#endif
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache
            )
        {
            // prepare formatting settings
            FormatSettings settings = PrepareFormatSettings(
                textSource,
                firstCharIndex,
                paragraphWidth,
                paragraphProperties,
                previousLineBreak,
                textRunCache,
                true,   // optimalBreak
                false,  // !isSingleLineFormatting
                _textFormattingMode
                );

            //
            // Optimal paragraph formatting session specific check
            //
            if (!settings.Pap.Wrap && settings.Pap.OptimalBreak)
            {
                // Optimal paragraph must wrap.
                throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap));
            }

            // create paragraph content cache object
            return new TextParagraphCache(
                settings,
                firstCharIndex,
                RealToIdeal(paragraphWidth)
                );
        }
Example #10
0
        /// <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)
                    ) 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;
        }
Example #11
0
        internal override TextLine RecreateLine(
#endif
            TextSource                  textSource,
            int                         firstCharIndex,
            int                         lineLength,
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache
            )
        {
            return FormatLineInternal(
                textSource,
                firstCharIndex,
                lineLength,
                paragraphWidth,
                paragraphProperties,
                previousLineBreak,
                textRunCache
                );
        }
Example #12
0
 /// <summary>
 /// Client to format a text line that fills a paragraph in the document.
 /// </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="paragraphWidth">width of paragraph in which the line fills</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="previousLineBreak">LineBreak property of the previous text line, or null if this is the first line in the paragraph</param>
 /// <param name="textRunCache">an object representing content cache of the client.</param>
 /// <returns>object representing a line of text that client interacts with. </returns>
 public override TextLine FormatLine(
     TextSource                  textSource,
     int                         firstCharIndex,
     double                      paragraphWidth,
     TextParagraphProperties     paragraphProperties,
     TextLineBreak               previousLineBreak,
     TextRunCache                textRunCache
     )
 {
     return FormatLineInternal(
         textSource,
         firstCharIndex,
         0,   // lineLength
         paragraphWidth,
         paragraphProperties,
         previousLineBreak,
         textRunCache
         );
 }
Example #13
0
 /// <summary>
 /// Client to format a text line that fills a paragraph in the document.
 /// </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="paragraphWidth">width of paragraph in which the line fills</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="previousLineBreak">LineBreak property of the previous text line, or null if this is the first line in the paragraph</param>
 /// <returns>object representing a line of text that client interacts with. </returns>
 public override TextLine FormatLine(
     TextSource                  textSource,
     int                         firstCharIndex,
     double                      paragraphWidth,
     TextParagraphProperties     paragraphProperties,
     TextLineBreak               previousLineBreak
     )
 {
     return FormatLineInternal(
         textSource,
         firstCharIndex,
         0,   // lineLength
         paragraphWidth,
         paragraphProperties,
         previousLineBreak,
         new TextRunCache()  // local cache, only live within this call
         );
 }
Example #14
0
 /// <summary>
 /// Client to format all feasible breakpoints for a line started at the specified character position. 
 /// The number of breakpoints returned is restricted by penalty restr
 /// </summary> 
 /// <remarks> 
 /// This method is provided for direct access of PTS during optimal paragraph process. The breakpoint
 /// restriction handle is passed as part of the parameter to PTS callback pfnFormatLineVariants. The 
 /// value comes from earlier steps in PTS code to compute the accumulated penalty of the entire paragraph
 /// using 'best-fit' algorithm.
 /// </remarks>
 internal IList<TextBreakpoint> FormatBreakpoints( 
     int                             firstCharIndex,
     TextLineBreak                   previousLineBreak, 
     IntPtr                          breakpointRestrictionHandle, 
     double                          maxLineWidth,
     out int                         bestFitIndex 
     )
 {
     // format all potential breakpoints starting from the specified firstCharIndex.
     // The number of breakpoints returned is restricted by penaltyRestriction. 
     return FullTextBreakpoint.CreateMultiple(
         this, 
         firstCharIndex, 
         VerifyMaxLineWidth(maxLineWidth),
         previousLineBreak, 
         breakpointRestrictionHandle,
         out bestFitIndex
         );
 } 
Example #15
0
        [FriendAccessAllowed]   // used by Framework
        internal abstract TextParagraphCache CreateParagraphCache(
#endif
            TextSource                  textSource, 
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            );
Example #16
0
            /// <summary>
            /// Wrapper of TextFormatter.FormatLine that auto-collapses the line if needed.
            /// </summary>
            private TextLine FormatLine(TextSource textSource, int textSourcePosition, double maxLineLength, TextParagraphProperties paraProps, TextLineBreak lineBreak)
            {
                TextLine line = _formatter.FormatLine(
                    textSource,
                    textSourcePosition,
                    maxLineLength,
                    paraProps,
                    lineBreak
                    );

                if (_that._trimming != TextTrimming.None && line.HasOverflowed && line.Length > 0)
                {
                    // what I really need here is the last displayed text run of the line
                    // textSourcePosition + line.Length - 1 works except the end of paragraph case,
                    // where line length includes the fake paragraph break run
                    Debug.Assert(_that._text.Length > 0 && textSourcePosition + line.Length <= _that._text.Length + 1);

                    SpanRider thatFormatRider = new SpanRider(
                        _that._formatRuns,
                        _that._latestPosition,
                        Math.Min(textSourcePosition + line.Length - 1, _that._text.Length - 1)
                        );

                    GenericTextRunProperties lastRunProps = thatFormatRider.CurrentElement as GenericTextRunProperties;

                    TextCollapsingProperties trailingEllipsis;

                    if (_that._trimming == TextTrimming.CharacterEllipsis)
                        trailingEllipsis = new TextTrailingCharacterEllipsis(maxLineLength, lastRunProps);
                    else
                    {
                        Debug.Assert(_that._trimming == TextTrimming.WordEllipsis);
                        trailingEllipsis = new TextTrailingWordEllipsis(maxLineLength, lastRunProps);
                    }

                    TextLine collapsedLine = line.Collapse(trailingEllipsis);

                    if (collapsedLine != line)
                    {
                        line.Dispose();
                        line = collapsedLine;
                    }
                }
                return line;
            }
Example #17
0
        /// <summary>
        /// Validate all the relevant text formatting initial settings and package them
        /// </summary>
        private FormatSettings PrepareFormatSettings(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache,
            bool                        useOptimalBreak,
            bool                        isSingleLineFormatting,
            TextFormattingMode              textFormattingMode
            )
        {
            VerifyTextFormattingArguments(
                textSource,
                firstCharIndex,
                paragraphWidth,
                paragraphProperties,
                textRunCache
                );

            if (textRunCache.Imp == null)
            {
                // No run cache object available, create one
                textRunCache.Imp = new TextRunCacheImp();
            }

            // initialize formatting settings
            return new FormatSettings(
                this,
                textSource,
                textRunCache.Imp,
                new ParaProp(this, paragraphProperties, useOptimalBreak),
                previousLineBreak,
                isSingleLineFormatting,
                textFormattingMode,
                false
                );
        }
Example #18
0
            /// <summary>
            /// Advances the enumerator to the next text line of the collection
            /// </summary>
            /// <returns>true if the enumerator was successfully advanced to the next element;
            /// false if the enumerator has passed the end of the collection</returns>
            public bool MoveNext()
            {
                if (_currentLine == null)
                {   // this is the first line

                    if (_that._text.Length == 0)
                        return false;

                    _currentLine = FormatLine(
                        _that._textSourceImpl,
                        _textStorePosition,
                        MaxLineLength(_lineCount),
                        _that._defaultParaProps,
                        null // no previous line break
                        );

                    // check if this line fits the text height
                    if (_totalHeight + _currentLine.Height > _that._maxTextHeight)
                    {
                        _currentLine.Dispose();
                        _currentLine = null;
                        return false;
                    }
                    Debug.Assert(_nextLine == null);
                }
                else
                {
                    // there is no next line or it didn't fit
                    // either way we're finished
                    if (_nextLine == null)
                        return false;

                    _totalHeight += _previousHeight;
                    _textStorePosition += _previousLength;
                    ++_lineCount;

                    _currentLine = _nextLine;
                    _nextLine = null;
                }

                TextLineBreak currentLineBreak = _currentLine.GetTextLineBreak();

                // this line is guaranteed to fit the text height
                Debug.Assert(_totalHeight + _currentLine.Height <= _that._maxTextHeight);

                // now, check if the next line fits, we need to do this on this iteration
                // because we might need to add ellipsis to the current line
                // as a result of the next line measurement

                // maybe there is no next line at all
                if (_textStorePosition + _currentLine.Length < _that._text.Length)
                {
                    bool nextLineFits;

                    if (_lineCount + 1 >= _that._maxLineCount)
                        nextLineFits = false;
                    else
                    {
                        _nextLine = FormatLine(
                            _that._textSourceImpl,
                            _textStorePosition + _currentLine.Length,
                            MaxLineLength(_lineCount + 1),
                            _that._defaultParaProps,
                            currentLineBreak
                            );
                        nextLineFits = (_totalHeight + _currentLine.Height + _nextLine.Height <= _that._maxTextHeight);
                    }                       

                    if (!nextLineFits)
                    {
                        // next line doesn't fit
                        if (_nextLine != null)
                        {
                            _nextLine.Dispose();
                            _nextLine = null;
                        }

                        if (_that._trimming != TextTrimming.None && !_currentLine.HasCollapsed)
                        {
                            // recreate the current line with ellipsis added
                            // Note: Paragraph ellipsis is not supported today. We'll workaround
                            // it here by faking a non-wrap text on finite column width.
                            TextWrapping currentWrap = _that._defaultParaProps.TextWrapping;
                            _that._defaultParaProps.SetTextWrapping(TextWrapping.NoWrap);

                            if (currentLineBreak != null)
                                currentLineBreak.Dispose();

                            _currentLine.Dispose();
                            _currentLine = FormatLine(
                                _that._textSourceImpl,
                                _textStorePosition,
                                MaxLineLength(_lineCount),
                                _that._defaultParaProps,
                                _previousLineBreak
                                );

                            currentLineBreak = _currentLine.GetTextLineBreak();
                            _that._defaultParaProps.SetTextWrapping(currentWrap);
                        }
                    }
                }
                _previousHeight = _currentLine.Height;
                _previousLength = _currentLine.Length;

                if (_previousLineBreak != null)
                    _previousLineBreak.Dispose();

                _previousLineBreak = currentLineBreak;

                return true;
            }
Example #19
0
        // -----------------------------------------------------------------
        // 
        //  Internal Methods
        // 
        // ------------------------------------------------------------------ 

        #region Internal Methods 

        /// <summary>
        /// Create and format text line.
        /// </summary> 
        /// <param name="ctx">
        /// Line formatting context. 
        /// </param> 
        /// <param name="dcp">
        /// Character position where the line starts. 
        /// </param>
        /// <param name="width">
        /// Requested width of the line.
        /// </param> 
        /// <param name="trackWidth">
        /// Requested width of track. 
        /// </param> 
        /// <param name="lineProps">
        /// Line properties. 
        /// </param>
        /// <param name="textLineBreak">
        /// Line break object.
        /// </param> 
        internal void Format(FormattingContext ctx, int dcp, int width, int trackWidth, TextParagraphProperties lineProps, TextLineBreak textLineBreak)
        { 
            // Set formatting context 
            _formattingContext = ctx;
            _dcp = dcp; 
            _host.Context = this;
            _wrappingWidth = TextDpi.FromTextDpi(width);
            _trackWidth = TextDpi.FromTextDpi(trackWidth);
            _mirror = (lineProps.FlowDirection == FlowDirection.RightToLeft); 
            _indent = lineProps.Indent;
 
            try 
            {
                // Create line object 
                if(ctx.LineFormatLengthTarget == -1)
                {
                    _line = _host.TextFormatter.FormatLine(_host, dcp, _wrappingWidth, lineProps, textLineBreak, ctx.TextRunCache);
                } 
                else
                { 
                    _line = _host.TextFormatter.RecreateLine(_host, dcp, ctx.LineFormatLengthTarget, _wrappingWidth, lineProps, textLineBreak, ctx.TextRunCache); 
                }
                _runs = _line.GetTextRunSpans(); 
                Invariant.Assert(_runs != null, "Cannot retrieve runs collection.");

                // Submit inline objects (only in measure mode)
                if (_formattingContext.MeasureMode) 
                {
                    List<InlineObject> inlineObjects = new List<InlineObject>(1); 
                    int dcpRun = _dcp; 
                    // Enumerate through all runs in the current line and retrieve
                    // all inline objects. 
                    // If there are any figures / floaters, store this information for later use.
                    foreach (TextSpan<TextRun> textSpan in _runs)
                    {
                        TextRun run = (TextRun)textSpan.Value; 
                        if (run is InlineObjectRun)
                        { 
                            inlineObjects.Add(new InlineObject(dcpRun, ((InlineObjectRun)run).UIElementIsland, (TextParagraph)_paraClient.Paragraph)); 
                        }
                        else if (run is FloatingRun) 
                        {
                            if (((FloatingRun)run).Figure)
                            {
                                _hasFigures = true; 
                            }
                            else 
                            { 
                                _hasFloaters = true;
                            } 
                        }

                        // Do not use TextRun.Length, because it gives total length of the run.
                        // So, if the run is broken between lines, it gives incorrect value. 
                        // Use length of the TextSpan instead, which gives the correct length here.
                        dcpRun += textSpan.Length; 
                    } 

                    // Submit inline objects to the paragraph cache 
                    if (inlineObjects.Count == 0)
                    {
                        inlineObjects = null;
                    } 
                    TextParagraph.SubmitInlineObjects(dcp, dcp + ActualLength, inlineObjects);
                } 
            } 
            finally
            { 
                // Clear formatting context
                _host.Context = null;
            }
        } 
 // ------------------------------------------------------------------
 // Constructor.
 //
 //      PtsContext - Context
 //      TextLineBreak - Contained line break
 // ------------------------------------------------------------------
 internal LineBreakRecord(PtsContext ptsContext, TextLineBreak textLineBreak) : base(ptsContext)
 {
     _textLineBreak = textLineBreak;
 }
Example #21
0
		public TextLine FormatLine(TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak) {
			var runs = new List<Tuple<TextRun, GlyphRun, int, double>>();

			int index = firstCharIndex;
			double x = paragraphProperties.Indent, height = 0, baseline = 0;
			double trailWhitespaceWidth = 0;

			while (true) {
				var run = textSource.GetTextRun(index);
				var textProps = run.Properties ?? paragraphProperties.DefaultTextRunProperties;
				var fontSize = textProps.FontRenderingEmSize;
				var len = run.Length;
				if (textProps != null) {
					height = Math.Max(height, (int)(textProps.Typeface.FontFamily.LineSpacing * fontSize));
					baseline = Math.Max(baseline, (int)(textProps.Typeface.FontFamily.Baseline * fontSize));
				}

				if (run is TextEndOfLine || run == null) {
					index += len;
					runs.Add(Tuple.Create(run, (GlyphRun)null, 0, 0.0));
					break;
				}
				else if (run is TextCharacters) {
					var chrs = (TextCharacters)run;
					var charBuf = getCharBuf(chrs.CharacterBufferReference);
					var charOffset = getCharOffset(chrs.CharacterBufferReference);

					GlyphTypeface gl;
					if (!textProps.Typeface.TryGetGlyphTypeface(out gl))
						throw new Exception("GlyphTypeface does not exists for font '" + textProps.Typeface.FontFamily + "'.");

					ushort[] glyphIndexes = new ushort[len];
					double[] advanceWidths = new double[len];

					double totalWidth = 0;
					int trailWhitespace = 0;
					trailWhitespaceWidth = 0;
					for (int n = 0; n < len; n++) {
						var c = charBuf[charOffset + n];

						ushort glyphIndex;
						double width;

						if (c == '\t') {
							glyphIndex = gl.CharacterToGlyphMap[' '];
							width = paragraphProperties.DefaultIncrementalTab - x % paragraphProperties.DefaultIncrementalTab;
						}
						else {
							if (!gl.CharacterToGlyphMap.TryGetValue(c, out glyphIndex))
								glyphIndex = gl.CharacterToGlyphMap['?'];
							width = gl.AdvanceWidths[glyphIndex] * fontSize;
						}

						glyphIndexes[n] = glyphIndex;
						advanceWidths[n] = width;

						if (char.IsWhiteSpace(c)) {
							trailWhitespace++;
							trailWhitespaceWidth += width;
						}
						else {
							totalWidth += trailWhitespaceWidth + width;
							trailWhitespaceWidth = 0;
							trailWhitespace = 0;
						}
					}
					var origin = new Point(x, 0);

					var glyphRun = new GlyphRun(
						gl, 0, false, fontSize, glyphIndexes, origin, advanceWidths,
						null, null, null, null, null, null);
					runs.Add(Tuple.Create(run, glyphRun, trailWhitespace, trailWhitespaceWidth));

					x += totalWidth + trailWhitespaceWidth;

					index += len;
				}
				else if (run is TextEmbeddedObject) {
					var obj = (TextEmbeddedObject)run;
					var metrics = obj.Format(paragraphWidth - x);
					runs.Add(Tuple.Create(run, (GlyphRun)null, 0, metrics.Width));

					height = Math.Max(height, obj.Format(paragraphWidth - x).Height);
					x += metrics.Width;

					index += len;
				}
			}

			return new GlyphRunLine {
				entries = runs.ToArray(),
				baseline = baseline,
				width = x - trailWhitespaceWidth,
				height = height,
				mode = mode
			};
		}