internal TextParagraphCache( 
            FormatSettings      settings,
            int                 firstCharIndex, 
            int                 paragraphWidth
            )
        {
            Invariant.Assert(settings != null); 

            // create full text 
            _finiteFormatWidth = settings.GetFiniteFormatWidth(paragraphWidth); 
            _fullText = FullTextState.Create(settings, firstCharIndex, _finiteFormatWidth);
 
            // acquiring LS context
            TextFormatterContext context = settings.Formatter.AcquireContext(_fullText, IntPtr.Zero);

            _fullText.SetTabs(context); 

            IntPtr ploparabreakValue = IntPtr.Zero; 
 
            LsErr lserr = context.CreateParaBreakingSession(
                firstCharIndex, 
                _finiteFormatWidth,
                // breakrec is not needed before the first cp of para cache
                // since we handle Bidi break ourselves.
                IntPtr.Zero, 
                ref ploparabreakValue,
                ref _penalizedAsJustified 
                ); 

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

            // release the context
            context.Release(); 

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

            _ploparabreak.Value = ploparabreakValue;
 
            // keep context alive till here
            GC.KeepAlive(context); 
        } 
Exemple #2
0
        private FullTextBreakpoint(
            FullTextState fullText,
            int firstCharIndex,
            int maxLineWidth,
            ref LsBreaks lsbreaks,
            int breakIndex
            ) : this()
        {
            // According to antons: PTS only uses the width of a feasible break to avoid
            // clipping in subpage. At the moment, there is no good solution as of how
            // PTS client would be able to compute this width efficiently using LS.
            // The work around - although could be conceived would simply be too slow.
            // The width should therefore be set to the paragraph width for the time being.
            //
            // Client of text formatter would simply pass the value of TextBreakpoint.Width
            // back to PTS pfnFormatLineVariants call.
            LsLineWidths lineWidths = new LsLineWidths();

            lineWidths.upLimLine          = maxLineWidth;
            lineWidths.upStartMainText    = fullText.TextStore.Settings.TextIndent;
            lineWidths.upStartMarker      = lineWidths.upStartMainText;
            lineWidths.upStartTrailing    = lineWidths.upLimLine;
            lineWidths.upMinStartTrailing = lineWidths.upStartTrailing;

            // construct the correspondent text metrics
            unsafe
            {
                _metrics.Compute(
                    fullText,
                    firstCharIndex,
                    maxLineWidth,
                    null,   // collapsingSymbol
                    ref lineWidths,
                    &lsbreaks.plslinfoArray[breakIndex]
                    );

                _ploline = new SecurityCriticalDataForSet <IntPtr>(lsbreaks.pplolineArray[breakIndex]);

                // keep the line penalty handle
                _penaltyResource = new SecurityCriticalDataForSet <IntPtr>(lsbreaks.plinepenaltyArray[breakIndex]);

                if (lsbreaks.plslinfoArray[breakIndex].fForcedBreak != 0)
                {
                    _isLineTruncated = true;
                }
            }
        }
Exemple #3
0
        private double           _pixelsPerDip;                     // PixelsPerDip

        /// <summary>
        /// Construct text metrics from full text info
        /// </summary>
        /// <remarks>
        ///
        /// When the application formats a line of text. It starts from the leading edge of the paragraph - the reference position
        /// called "Paragraph Start". It gives the width of the paragraph or "Paragraph Width" to TextFormatter as one of the main
        /// parameters to TextFormatter.FormatLine method. It may also provide additional info about how it wants the line to look
        /// like. The following are all of such info and how the formatting process is carried on inside TextFormatter.
        ///
        ///
        /// *** Indent/Paragraph Indent ***
        /// The application may specify "Indent" - the distance from the beginning of the line to the beginning of the text in that
        /// line. The value is sent to TextFormatter via [TextParagraphProperties.Indent]. It may also specify "Paragraph Indent"
        /// - the distance from the beginning of the paragraph to the beginning of the line [TextParagraphProperties.ParagraphIndent].
        /// The usage of paragraph indent is to offset the beginning of the line relative to the paragraph starting point, while
        /// indent is to offset the beginning of text realtive to the line starting point. Paragraph indent is not included as part
        /// of the line width while indent is.
        ///
        ///
        /// *** Text Alignment ***
        /// "Text Alignment" [TextParagraphProperties.TextAlignment] may be specified to align the leading, center or trailing edge
        /// of the line to the leading, center or trailing edge of the paragraph excluding paragraph indent.
        ///
        ///
        /// *** Bullet/Auto-numbering ***
        /// The application may also specify "bullet" (or "marker") for the line. Marker does not affect the layout measurement of the
        /// line. Line with marker has the same line width with the line that has not. The presence of marker however affects the
        /// pixel-wise black width of the line. The application specifies the distance from the beginning of the line to the trailing
        /// edge of the marker symbol via the property [TextMarkerProperties.Offset]. The application can create the visual effect of
        /// having marker embedded inside the body of paragraph text (so-called "marker inside") by specifying a positive indent so
        /// that the text starts after the beginning of the line and a positive smaller amount of marker offset to place the marker
        /// symbol at between the beginning of the line and the beginning of the text. The "marker outside" visual effect can
        /// also be achieved in a similar manner by specifying zero or positive indent value with negative marker offset value.
        ///
        ///
        /// *** Formatted Line Properties ***
        /// Once the line formatting process is completed and a line is returned to the application. The application determines the
        /// distance from the paragraph starting point to the actual beginning of the line by looking at the "Line Start" property of
        /// the text line [TextLine.Start]. The "Width" of the line can be determined, naturally, from the property [TextLine.Width].
        /// The property value [TextLine.OverhangLeading] represents the distance from the beginning of the line, or the line's alignment
        /// point, to the first leading pixel of that line so-called the "Black Start". The property [TextLine.OverhangTrailing]
        /// is the distance from the last trailing pixel of the line to the trailing edge alignment point of the line. The application
        /// uses these "overhang" or "overshoot" values to ensure proper positioning of text that avoids pixel clipping of the
        /// glyph image. A less sophisticated application may provide reasonable leading and trailing margin around the text line
        /// and ignores these properties altogether.
        ///
        ///
        /// *** Hit-Testing ***
        /// The application may also perform hit-testing by calling methods on TextLine. All the distances involved in hit-testing
        /// operations are distances from the paragraph start, not from the line start. Marker symbol on its own is not hit-testable.
        ///
        ///
        /// *** Tabs ***
        /// The application may specify tab stops - an array of positions to where text aligns. Each tab stop may have different
        /// "Tab Alignment". The left, center and right tab alignment aligns the tab stop position to the leading, center and the
        /// trailing edge of the text following the tab character. "Tab Leader" may also be specified to fill the distance occupied
        /// by the presence of tab character with the symbol of choice. Tab stops is specified thru the property [TextParagraph.Tabs].
        /// In the absence of tab stops, the application may assume an automatic tab stop - so called "Incremental Tab" specified by
        /// the property [TextParagraphProperties.DefaultIncrementalTab]. The property could be overridden, by default the value
        /// is set by TextFormatter to 4 em of the paragraph's default font.
        ///
        ///
        /// *** Line Services Properties ***
        /// TextFormatter relies on LS to calculate the distance from the beginning of the line to the beginning of text or "Text Start"
        /// and keep it in the private property [this._textStart]. This value is non-zero when 1) the line starts with indentation or
        /// 2) the line starts with marker - either bullet or auto-numbering symbol.
        ///
        /// In case of the line with marker, LS also produces the distance from the beginning of the line to the beginning of the marker
        /// symbol, but TextFormatter does not retain that distance because marker is outside the line. The application is assumed
        /// responsibility to make sure the marker symbol is not going to be clipped out. The application achieves that by manipulating
        /// the indent value along with the marker offset value.
        ///
        /// TextFormatter also retains the total "Text Width" value computed by LS in the private property [this._textWidth]. This
        /// is the distance from the beginning of the text to the end including all trailing whitespaces at the end of the line. The
        /// similar value but with trailing whitespaces excluded is kept in the private property [this._textWidthAtTrailing].
        ///
        /// TextFormatter starts formatting a LS line by assuming the beginning of the line being at an imaginary origin. It then
        /// places the starting point of the content depending on whether the line has either marker symbol or indent. The actual
        /// mechanism for the placement is in FetchLineProps callback where the value [LsLineProps.durLeft] represents the distance
        /// relative to the line's origin where actual content begins. The distances can either be positive or negative. Negative
        /// distance runs in the reverse direction from the direction of text flow. When a negative indent or marker offset is
        /// specified, durLeft is set to negative distance relative to line start.
        ///
        /// TextFormatter however does not rely on LS for the whole line's text alignment. It always formats LS as if the line is
        /// left-aligned. Once the distances of the line are received, it aligns the whole line according to the text alignment setting
        /// specified by the application, outside the LS call. The result of this aligning process is a distance from the beginning of
        /// the paragraph to the beginning of text and is kept in a private property [this._paragraphToText].
        ///
        /// </remarks>
        internal unsafe void Compute(
            FullTextState fullText,
            int firstCharIndex,
            int paragraphWidth,
            FormattedTextSymbols collapsingSymbol,
            ref LsLineWidths lineWidths,
            LsLInfo *plsLineInfo
            )
        {
            _formatter = fullText.Formatter;
            TextStore store = fullText.TextStore;

            _pixelsPerDip = store.Settings.TextSource.PixelsPerDip;
            // obtain position of important distances
            _textStart           = lineWidths.upStartMainText;
            _textWidthAtTrailing = lineWidths.upStartTrailing;
            _textWidth           = lineWidths.upLimLine;

            // append line end collapsing symbol if any
            if (collapsingSymbol != null)
            {
                AppendCollapsingSymbolWidth(TextFormatterImp.RealToIdeal(collapsingSymbol.Width));
            }

            // make all widths relative to text start
            _textWidth           -= _textStart;
            _textWidthAtTrailing -= _textStart;

            // keep the newline character count if any
            _cchNewline = store.CchEol;

            // count text and dependant characters
            _lscpLim = plsLineInfo->cpLimToContinue;
            _lastRun = fullText.CountText(_lscpLim, firstCharIndex, out _cchLength);

            Debug.Assert(_cchLength > 0);

            if (plsLineInfo->endr != LsEndRes.endrEndPara &&
                plsLineInfo->endr != LsEndRes.endrSoftCR)
            {
                // endrEndPara denotes that the line ends at paragraph end. It is a result of submitting Paragraph Separator to LS.
                // endrSoftCR denotes end of line but not end of paragraph. This is a result of submitting Line Separator to LS.
                _cchNewline = 0;

                if (plsLineInfo->dcpDepend >= 0)
                {
                    // According to SergeyGe [2/16/2006], dcpDepend reported from LS cannot made precise when considering
                    // the line ending with hyphenation - this is because LS does not have the knowledge about the amount
                    // of text, after the hyphenation point, being examined by its client during the process of finding
                    // the right place to hyphenate. LS client must therefore take into account the number of lookahead
                    // LSCP examined by hyphenator when computing the correct dcpDepend for the line. In our implementation
                    // it would just mean we take the max of the two values.
                    int lscpFirstIndependence = Math.Max(
                        plsLineInfo->cpLimToContinue + plsLineInfo->dcpDepend,
                        fullText.LscpHyphenationLookAhead
                        );

                    fullText.CountText(lscpFirstIndependence, firstCharIndex, out _cchDepend);
                    _cchDepend -= _cchLength;
                }
            }

            ParaProp pap = store.Pap;

            if (_height <= 0)
            {
                // if height has not been settled,
                // calculate line height and baseline offset
                if (pap.LineHeight > 0)
                {
                    // Host specifies line height, honor it.
                    _height         = pap.LineHeight;
                    _baselineOffset = (int)Math.Round(
                        _height
                        * pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, _pixelsPerDip, fullText.TextFormattingMode)
                        / pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, _pixelsPerDip, fullText.TextFormattingMode)
                        );
                }

                if (plsLineInfo->dvrMultiLineHeight == int.MaxValue)
                {
                    // Line is empty so text height and text baseline are based on the default typeface;
                    // it doesn't make sense even for an emtpy line to have zero text height
                    _textAscent = (int)Math.Round(pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, _pixelsPerDip, fullText.TextFormattingMode));
                    _textHeight = (int)Math.Round(pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, _pixelsPerDip, fullText.TextFormattingMode));
                }
                else
                {
                    _textAscent = plsLineInfo->dvrAscent;
                    _textHeight = _textAscent + plsLineInfo->dvrDescent;

                    if (fullText.VerticalAdjust)
                    {
                        // Line requires vertical repositioning of text runs
                        store.AdjustRunsVerticalOffset(
                            plsLineInfo->cpLimToContinue - firstCharIndex,
                            _height,
                            _baselineOffset,
                            out _textHeight,
                            out _textAscent
                            );
                    }
                }

                // if the client hasn't specified a line height then the line height and baseline
                // are the same as the text height and text baseline
                if (_height <= 0)
                {
                    _height         = _textHeight;
                    _baselineOffset = _textAscent;
                }
            }

            // Text alignment aligns the line to correspondent paragraph alignment start edge
            switch (pap.Align)
            {
            case TextAlignment.Right:

                // alignment rule:
                //   "The sum of paragraph start to line start and line width is equal to paragraph width"
                //
                //        PTL + LW = PW
                //        (PTT - LTT) + (LTT + TW) = PW
                // (thus) PTT = PW - TW
                _paragraphToText = paragraphWidth - _textWidthAtTrailing;
                break;

            case TextAlignment.Center:

                // alignment rule:
                //   "The sum of paragraph start to line start and half the line width is equal to half the paragraph width"
                //
                //        PTL + 0.5*LW = 0.5*PW
                //        (PTT - LTT) + 0.5*(LTT + TW) = 0.5*PW
                // (thus) PTT = 0.5 * (PW + LTT - TW)
                _paragraphToText = (int)Math.Round((paragraphWidth + _textStart - _textWidthAtTrailing) * 0.5);
                break;

            default:

                // alignment rule:
                //   "Paragraph start to line start is paragraph indent"
                //
                //        PTL = PI
                //        PTT - LTT = PI
                // (thus) PTT = PI + LTT
                _paragraphToText = pap.ParagraphIndent + _textStart;
                break;
            }
        }
            private void FormatLine(
                FullTextState           fullText,
                int                     cpFirst,
                int                     lineLength,
                int                     formatWidth,
                int                     finiteFormatWidth,
                int                     paragraphWidth,
                LineFlags               lineFlags,
                FormattedTextSymbols    collapsingSymbol
                )
            {
                _metrics._formatter = fullText.Formatter;
                Debug.Assert(_metrics._formatter != null);

                TextStore store = fullText.TextStore;
                TextStore markerStore = fullText.TextMarkerStore;
                FormatSettings settings = store.Settings;
                ParaProp pap = settings.Pap;

                _paragraphTextDecorations = pap.TextDecorations;
                if (_paragraphTextDecorations != null)
                {
                    if (_paragraphTextDecorations.Count != 0)
                    {
                        _defaultTextDecorationsBrush = pap.DefaultTextDecorationsBrush;
                    }
                    else
                    {
                        _paragraphTextDecorations = null;
                    }
                }

                // acquiring LS context
                TextFormatterContext context = _metrics._formatter.AcquireContext(fullText, IntPtr.Zero);

                LsLInfo plslineInfo = new LsLInfo();
                LsLineWidths lineWidths = new LsLineWidths();

                fullText.SetTabs(context);

                int lscpLineLength = 0; // line length in LSCP
                if (lineLength > 0)
                {
                    // line length is previously known (e.g. during optimal paragraph formatting),
                    // prefetch lsruns up to the specified line length.
                    lscpLineLength = PrefetchLSRuns(store, cpFirst, lineLength);
                }

                IntPtr ploline;
                LsErr lserr = context.CreateLine(
                    cpFirst,
                    lscpLineLength,
                    formatWidth,
                    lineFlags,
                    IntPtr.Zero,    // single-line formatting does not require break record
                    out ploline,
                    out plslineInfo,
                    out _depthQueryMax,
                    out lineWidths
                    );

                // Did we exceed the LineServices maximum line width?
                if (lserr == LsErr.TooLongParagraph)
                {
                    // Determine where to insert a fake line break. FullTextState.CpMeasured
                    // is a reasonable estimate since we know the nominal widths up to that
                    // point fit within the margin.
                    int cpLimit = fullText.CpMeasured;
                    int subtract = 1;

                    for (;;)
                    {
                        // The line must contain at least one character position.
                        if (cpLimit < 1)
                        {
                            cpLimit = 1;
                        }

                        store.InsertFakeLineBreak(cpLimit);

                        lserr = context.CreateLine(
                            cpFirst,
                            lscpLineLength,
                            formatWidth,
                            lineFlags,
                            IntPtr.Zero,    // single-line formatting does not require break record
                            out ploline,
                            out plslineInfo,
                            out _depthQueryMax,
                            out lineWidths
                            );

                        if (lserr != LsErr.TooLongParagraph || cpLimit == 1)
                        {
                            // We're done or can't chop off any more text.
                            break;
                        }
                        else
                        {
                            // Chop off more text and try again. Double the amount of
                            // text we chop off each time so we retry too many times.
                            cpLimit = fullText.CpMeasured - subtract;
                            subtract *= 2;
                        }
                    }
                }

                _ploline.Value = ploline;

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

                // release the context
                context.Release();

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

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

                unsafe
                {
                    // construct text metrics for the line
                    _metrics.Compute(
                        fullText,
                        cpFirst,
                        paragraphWidth,
                        collapsingSymbol,
                        ref lineWidths,
                        &plslineInfo
                        );
                }

                // keep record for min width as we may be formatting min/max
                _textMinWidthAtTrailing = lineWidths.upMinStartTrailing - _metrics._textStart;

                if (collapsingSymbol != null)
                {
                    _collapsingSymbol = collapsingSymbol;
                    _textMinWidthAtTrailing += TextFormatterImp.RealToIdeal(collapsingSymbol.Width);
                }
                else
                {
                    // overflow detection for potential collapsible line
                    if (_metrics._textStart + _metrics._textWidthAtTrailing > finiteFormatWidth)
                    {
                        bool hasOverflowed = true;
                        if (_textFormattingMode == TextFormattingMode.Display)
                        {
                            // apply display-mode rounding before checking for overflow
                            double realWidth = Width;
                            double realFormatWidth = _metrics._formatter.IdealToReal(finiteFormatWidth);
                            hasOverflowed = (TextFormatterImp.CompareReal(realWidth, realFormatWidth, _textFormattingMode) > 0);
                        }

                        if (hasOverflowed)
                        {
                            // line has overflowed
                            _statusFlags |= StatusFlags.HasOverflowed;

                            // let's keep the full text state around. We'll need it later for collapsing
                            _fullText = fullText;
                        }
                    }
                }

                if (    fullText != null
                    &&  (   fullText.KeepState
                        ||  (_statusFlags & StatusFlags.KeepState) != 0
                        )
                    )
                {
                    // the state of full text is to be kept after formatting is done
                    _fullText = fullText;
                }

                // retain all line properties for interactive operations
                _ploc = context.Ploc;
                _cpFirst = cpFirst;
                _paragraphWidth = paragraphWidth;

                if (pap.RightToLeft)
                    _statusFlags |= StatusFlags.RightToLeft;

                if (plslineInfo.fForcedBreak != 0)
                    _statusFlags |= StatusFlags.IsTruncated;

                // retain the state of plsruns
                _plsrunVector = store.PlsrunVector;
                _lsrunsMainText = store.LsrunList;

                if (markerStore != null)
                    _lsrunsMarkerText = markerStore.LsrunList;

                // we store the text source in the line in case drawing code calls
                // the TextSource to find out the text effect index.
                // 
                _textSource = settings.TextSource;
            }
Exemple #5
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);
        }
        internal unsafe void Compute(
            FullTextState           fullText,
            int                     firstCharIndex,
            int                     paragraphWidth,
            FormattedTextSymbols    collapsingSymbol,
            ref LsLineWidths        lineWidths,
            LsLInfo*                plsLineInfo
            )
        {
            _formatter = fullText.Formatter;
            TextStore store = fullText.TextStore;

            // obtain position of important distances
            _textStart = lineWidths.upStartMainText;
            _textWidthAtTrailing = lineWidths.upStartTrailing;
            _textWidth = lineWidths.upLimLine;

            // append line end collapsing symbol if any
            if (collapsingSymbol != null)
            {
                AppendCollapsingSymbolWidth(TextFormatterImp.RealToIdeal(collapsingSymbol.Width));
            }

            // make all widths relative to text start
            _textWidth -= _textStart;
            _textWidthAtTrailing -= _textStart;

            // keep the newline character count if any
            _cchNewline = store.CchEol;

            // count text and dependant characters
            _lscpLim = plsLineInfo->cpLimToContinue;
            _lastRun = fullText.CountText(_lscpLim, firstCharIndex, out _cchLength);

            Debug.Assert(_cchLength > 0);

            if (  plsLineInfo->endr != LsEndRes.endrEndPara 
               && plsLineInfo->endr != LsEndRes.endrSoftCR)
            {
                // endrEndPara denotes that the line ends at paragraph end. It is a result of submitting Paragraph Separator to LS.
                // endrSoftCR denotes end of line but not end of paragraph. This is a result of submitting Line Separator to LS.
                _cchNewline = 0;

                if (plsLineInfo->dcpDepend >= 0)
                {
                    // According to SergeyGe [2/16/2006], dcpDepend reported from LS cannot made precise when considering
                    // the line ending with hyphenation - this is because LS does not have the knowledge about the amount 
                    // of text, after the hyphenation point, being examined by its client during the process of finding
                    // the right place to hyphenate. LS client must therefore take into account the number of lookahead 
                    // LSCP examined by hyphenator when computing the correct dcpDepend for the line. In our implementation
                    // it would just mean we take the max of the two values. 
                    int lscpFirstIndependence = Math.Max(
                        plsLineInfo->cpLimToContinue + plsLineInfo->dcpDepend,
                        fullText.LscpHyphenationLookAhead
                        );

                    fullText.CountText(lscpFirstIndependence, firstCharIndex, out _cchDepend);
                    _cchDepend -= _cchLength;
                }
            }

            ParaProp pap = store.Pap;

            if (_height <= 0)
            {
                // if height has not been settled, 
                // calculate line height and baseline offset
                if(pap.LineHeight > 0)
                {
                    // Host specifies line height, honor it.
                    _height = pap.LineHeight;
                    _baselineOffset = (int)Math.Round(
                        _height
                        * pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)
                        / pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode)
                        );
                }

                if(plsLineInfo->dvrMultiLineHeight == int.MaxValue)
                {
                    // Line is empty so text height and text baseline are based on the default typeface;
                    // it doesn't make sense even for an emtpy line to have zero text height
                    _textAscent = (int)Math.Round(pap.DefaultTypeface.Baseline(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode));
                    _textHeight = (int)Math.Round(pap.DefaultTypeface.LineSpacing(pap.EmSize, Constants.DefaultIdealToReal, Util.PixelsPerDip, fullText.TextFormattingMode));
                }
                else
                {
                    _textAscent = plsLineInfo->dvrAscent;
                    _textHeight = _textAscent + plsLineInfo->dvrDescent;

                    if (fullText.VerticalAdjust)
                    {
                        // Line requires vertical repositioning of text runs
                        store.AdjustRunsVerticalOffset(
                            plsLineInfo->cpLimToContinue - firstCharIndex, 
                            _height,
                            _baselineOffset,
                            out _textHeight,
                            out _textAscent
                            );
                    }
                }

                // if the client hasn't specified a line height then the line height and baseline
                // are the same as the text height and text baseline
                if (_height <= 0)
                {
                    _height = _textHeight;
                    _baselineOffset = _textAscent;
                }
            }

            // Text alignment aligns the line to correspondent paragraph alignment start edge
            switch(pap.Align)
            {
                case TextAlignment.Right: 

                    // alignment rule: 
                    //   "The sum of paragraph start to line start and line width is equal to paragraph width"
                    //
                    //        PTL + LW = PW
                    //        (PTT - LTT) + (LTT + TW) = PW
                    // (thus) PTT = PW - TW
                    _paragraphToText = paragraphWidth - _textWidthAtTrailing;
                    break;

                case TextAlignment.Center: 

                    // alignment rule: 
                    //   "The sum of paragraph start to line start and half the line width is equal to half the paragraph width"
                    //
                    //        PTL + 0.5*LW = 0.5*PW
                    //        (PTT - LTT) + 0.5*(LTT + TW) = 0.5*PW
                    // (thus) PTT = 0.5 * (PW + LTT - TW)
                    _paragraphToText = (int)Math.Round((paragraphWidth + _textStart - _textWidthAtTrailing) * 0.5);
                    break;

                default:

                    // alignment rule: 
                    //   "Paragraph start to line start is paragraph indent"
                    //
                    //        PTL = PI
                    //        PTT - LTT = PI
                    // (thus) PTT = PI + LTT
                    _paragraphToText = pap.ParagraphIndent + _textStart;
                    break;
            }
        }
Exemple #7
0
        private FullTextBreakpoint(
            FullTextState           fullText,
            int                     firstCharIndex,
            int                     maxLineWidth,
            ref LsBreaks            lsbreaks,
            int                     breakIndex
            ) : this()
        {
            // According to antons: PTS only uses the width of a feasible break to avoid
            // clipping in subpage. At the moment, there is no good solution as of how
            // PTS client would be able to compute this width efficiently using LS. 
            // The work around - although could be conceived would simply be too slow.
            // The width should therefore be set to the paragraph width for the time being.
            //
            // Client of text formatter would simply pass the value of TextBreakpoint.Width
            // back to PTS pfnFormatLineVariants call.
            LsLineWidths lineWidths = new LsLineWidths();
            lineWidths.upLimLine = maxLineWidth;
            lineWidths.upStartMainText = fullText.TextStore.Settings.TextIndent;
            lineWidths.upStartMarker = lineWidths.upStartMainText;
            lineWidths.upStartTrailing = lineWidths.upLimLine;
            lineWidths.upMinStartTrailing = lineWidths.upStartTrailing;

            // construct the correspondent text metrics
            unsafe
            {
                _metrics.Compute(
                    fullText,
                    firstCharIndex,
                    maxLineWidth,
                    null,   // collapsingSymbol
                    ref lineWidths,
                    &lsbreaks.plslinfoArray[breakIndex]
                    );

                _ploline = new SecurityCriticalDataForSet<IntPtr>(lsbreaks.pplolineArray[breakIndex]);

                // keep the line penalty handle
                _penaltyResource = new SecurityCriticalDataForSet<IntPtr>(lsbreaks.plinepenaltyArray[breakIndex]);

                if (lsbreaks.plslinfoArray[breakIndex].fForcedBreak != 0)
                    _isLineTruncated = true;
            }
        }