Exemple #1
0
        //-------------------------------------------------------------------
        //
        //  Constructors
        //
        //-------------------------------------------------------------------

        #region Constructors

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="host">
        /// TextFormatter host
        /// </param>
        /// <param name="cpPara">
        /// Character position of paragraph
        /// </param>
        /// <param name="durTrack">
        /// Track width
        /// </param>
        /// <param name="paraClient">
        /// Owner of the line
        /// </param>
        /// <param name="runCache">
        /// Text run cache
        /// </param>
        internal OptimalTextSource(TextFormatterHost host, int cpPara, int durTrack, TextParaClient paraClient, TextRunCache runCache) : base(paraClient)
        {
            _host = host;
            _durTrack = durTrack;
            _runCache = runCache;
            _cpPara = cpPara;
        }
Exemple #2
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
     );
Exemple #3
0
        [FriendAccessAllowed]   // used by Framework
        internal abstract TextParagraphCache CreateParagraphCache(
#endif
            TextSource textSource,
            int firstCharIndex,
            double paragraphWidth,
            TextParagraphProperties paragraphProperties,
            TextLineBreak previousLineBreak,
            TextRunCache textRunCache
            );
Exemple #4
0
 public abstract MinMaxParagraphWidth FormatMinMaxParagraphWidth(TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties, TextRunCache textRunCache);
Exemple #5
0
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------

        #region Internal Methods

        /// <summary>
        /// Create and format text line.
        /// </summary>
        /// <param name="dcp">First character position for the line.</param>
        /// <param name="formatWidth">Width to pass to LS formatter.</param>
        /// <param name="paragraphWidth">Line wrapping width.</param>
        /// <param name="lineProperties">Line's properties.</param>
        /// <param name="textRunCache">Run cache.</param>
        /// <param name="formatter">Text formatter.</param>
        /// <remarks>
        /// formatWidth/paragraphWidth is an attempt to work around bug 114719.
        /// Unfortunately, Line Services cannot guarantee that once a line
        /// has been measured, measuring the same content with the actual line
        /// width will produce the same line.
        /// 
        /// For example, suppose we format dcp 0 with paragraphWidth = 100.
        /// Suppose this results in a line from dcp 0 - 10, with width = 95.
        ///
        /// We would expect that a call to FormatLine with dcp = 0,
        /// paragraphWidth = 95 would result in the same 10 char line.
        /// But in practice it might return a 9 char line.
        /// 
        /// The workaround is to pass in an explicit formatting width across
        /// multiple calls, even if the paragraphWidth changes.
        /// </remarks>
        internal void Format(int dcp, double formatWidth, double paragraphWidth, LineProperties lineProperties, TextRunCache textRunCache, TextFormatter formatter)
        {
            _lineProperties = lineProperties;
            _dcp = dcp;
            _paragraphWidth = paragraphWidth;

            // We must ignore TextAlignment here since formatWidth does not
            // necessarilly equal paragraphWidth.  We'll adjust on later calls.
            lineProperties.IgnoreTextAlignment = (lineProperties.TextAlignment != TextAlignment.Justify);
            try
            {
                _line = formatter.FormatLine(this, dcp, formatWidth, lineProperties, null, textRunCache);
            }
            finally
            {
                lineProperties.IgnoreTextAlignment = false;
            }
        }
Exemple #6
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;
        }
Exemple #7
0
        /// <summary>
        /// Finds and returns the position after backspace at the edge of a caret unit in
        /// specified direction.
        /// </summary>
        /// <param name="position">
        /// Initial text position of an object/character.
        /// </param>
        /// <param name="dcp">
        /// Offset of the current position from start of TextContainer
        /// </param>
        /// <param name="lineIndex">
        /// Index of line in which position is found
        /// </param>
        internal ITextPointer GetBackspaceCaretUnitPosition(ITextPointer position, int dcp, int lineIndex)
        {
            Invariant.Assert(IsLayoutDataValid);

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            EnsureComplexContent();

            // Get character index for position
            int characterIndex = _complexContent.TextContainer.Start.GetOffsetToPosition(position);

            // Process special cases
            if (characterIndex == dcp)
            {
                if (lineIndex == 0)
                {
                    // Cannot go back any further
                    return position;
                }
                else
                {
                    // Change lineIndex and dcp to previous line
                    Debug.Assert(lineIndex > 0);
                    --lineIndex;
                    dcp -= GetLine(lineIndex).Length;
                    Debug.Assert(dcp >= 0);
                }
            }

            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            CharacterHit textSourceCharacterIndex = new CharacterHit(characterIndex, 0);
            CharacterHit backspaceCharacterHit;
            LineMetrics lineMetrics = GetLine(lineIndex);

            TextRunCache textRunCache = new TextRunCache();
            // Create and Format line
            using(Line line = CreateLine(lineProperties))
            {
                // Format line. Set showParagraphEllipsis flag to false since we are not using information about
                // ellipsis to change line offsets in this case.
                line.Format(dcp, wrappingWidth, GetLineProperties(lineIndex == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, false);

                // Check consistency of line formatting
                MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of [....]");

                backspaceCharacterHit = line.GetBackspaceCaretCharacterHit(textSourceCharacterIndex);
            }
            // Get CharacterHit and call line API

            // Determine logical direction for next caret index and create TextPointer from it
            LogicalDirection logicalDirection;
            if (backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength == dcp)
            {
                // Going forward brought us to the start of a line, context must be backward for previous line
                if (dcp == 0)
                {
                    // First line, so we will stay forward
                    logicalDirection = LogicalDirection.Forward;
                }
                else
                {
                    logicalDirection = LogicalDirection.Backward;
                }
            }
            else
            {
                logicalDirection = (backspaceCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward;
            }
            ITextPointer backspaceCaretPosition = _complexContent.TextContainer.Start.CreatePointer(backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength, logicalDirection);

            // Return backspaceCaretPosition
            return backspaceCaretPosition;
        }
Exemple #8
0
        /// <summary>
        /// Implementation of TextParagraphView.GetTightBoundingGeometryFromTextPositions.
        /// <seealso cref="TextParagraphView.GetTightBoundingGeometryFromTextPositions"/>
        /// </summary>
        internal Geometry GetTightBoundingGeometryFromTextPositions(ITextPointer startPosition, ITextPointer endPosition)
        {
#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StartTimer("TextBlock.GetTightBoundingGeometryFromTextPositions", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif
            Invariant.Assert(IsLayoutDataValid);
            Invariant.Assert(startPosition != null);
            Invariant.Assert(endPosition != null);
            Invariant.Assert(startPosition.CompareTo(endPosition) <= 0);

            Geometry geometry = null;

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            EnsureComplexContent(); // TextOM access requires complex content.

            int dcpPositionStart = _complexContent.TextContainer.Start.GetOffsetToPosition(startPosition);
            int dcpPositionEnd = _complexContent.TextContainer.Start.GetOffsetToPosition(endPosition);

            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);

            TextRunCache textRunCache = new TextRunCache();
            Line line = CreateLine(lineProperties);

            int dcpLineStart = 0;
            ITextPointer endOfLineTextPointer = _complexContent.TextContainer.Start.CreatePointer(0);
            double lineOffset = 0;

            int lineCount = LineCount;
            for (int i = 0, count = lineCount; i < count; ++i)
            {
                LineMetrics lineMetrics = GetLine(i);

                if (dcpPositionEnd <= dcpLineStart)
                {
                    //  this line starts after the range's end.
                    //  safe to break from the loop.
                    break;
                }

                int dcpLineEnd = dcpLineStart + lineMetrics.Length;
                endOfLineTextPointer.MoveByOffset(lineMetrics.Length);

                if (dcpPositionStart < dcpLineEnd)
                {
                    using (line)
                    {
                        bool ellipsis = ParagraphEllipsisShownOnLine(i, lineOffset);
                        line.Format(dcpLineStart, wrappingWidth, GetLineProperties(dcpLineStart == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis);

                        if (Invariant.Strict)
                        {
                            // Check consistency of line formatting
                            MS.Internal.Invariant.Assert(GetLine(i).Length == line.Length, "Line length is out of [....]");
                        }

                        int dcpStart = Math.Max(dcpLineStart, dcpPositionStart);
                        int dcpEnd = Math.Min(dcpLineEnd, dcpPositionEnd);

                        if (dcpStart != dcpEnd)
                        {
                            IList<Rect> aryTextBounds = line.GetRangeBounds(dcpStart, dcpEnd - dcpStart, contentOffset.X, contentOffset.Y + lineOffset);

                            if (aryTextBounds.Count > 0)
                            {
                                int j = 0;
                                int c = aryTextBounds.Count;

                                do
                                {
                                    Rect rect = aryTextBounds[j];

                                    if (j == (c - 1)
                                       && dcpPositionEnd >= dcpLineEnd
                                       && TextPointerBase.IsNextToAnyBreak(endOfLineTextPointer, LogicalDirection.Backward))
                                    {
                                        double endOfParaGlyphWidth = FontSize * CaretElement.c_endOfParaMagicMultiplier;
                                        rect.Width = rect.Width + endOfParaGlyphWidth;
                                    }

                                    RectangleGeometry rectGeometry = new RectangleGeometry(rect);
                                    CaretElement.AddGeometry(ref geometry, rectGeometry);
                                } while (++j < c);
                            }
                        }
                    }
                }

                dcpLineStart += lineMetrics.Length;
                lineOffset += lineMetrics.Height;
            }

#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StopTimer("TextBlock.GetTightBoundingGeometryFromTextPositions", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif
            return (geometry);
        }
Exemple #9
0
        /// <summary>
        /// Retrieve text position from the distance (relative to the beginning
        /// of specified line).
        /// </summary>
        /// <param name="dcp">Index of the first character in the line.</param>
        /// <param name="distance">Distance relative to the beginning of the line.</param>
        /// <param name="lineVOffset">
        /// Vertical offset of the line in which the position lies,
        /// </param>
        /// <param name="index">
        /// Index of the line
        /// </param>
        /// <returns>
        /// A text position and its orientation matching or closest to the distance.
        /// </returns>
        internal ITextPointer GetTextPositionFromDistance(int dcp, double distance, double lineVOffset, int index)
        {
#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StartTimer("TextBlock.GetTextPositionFromDistance", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif
            Invariant.Assert(IsLayoutDataValid);

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            EnsureComplexContent(); // TextOM access requires complex content.

            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);
            distance -= contentOffset.X;
            lineVOffset -= contentOffset.Y;

            TextRunCache textRunCache = new TextRunCache();
            ITextPointer pos;
            using(Line line = CreateLine(lineProperties))
            {
                MS.Internal.Invariant.Assert(index >= 0 && index < LineCount);
                TextLineBreak textLineBreak = GetLine(index).TextLineBreak;
                bool ellipsis = ParagraphEllipsisShownOnLine(index, lineVOffset);
                line.Format(dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), textLineBreak, textRunCache, ellipsis);

                MS.Internal.Invariant.Assert(GetLine(index).Length == line.Length, "Line length is out of [....]");

                CharacterHit charIndex = line.GetTextPositionFromDistance(distance);
                LogicalDirection logicalDirection;

                logicalDirection = (charIndex.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward;
                pos = _complexContent.TextContainer.Start.CreatePointer(charIndex.FirstCharacterIndex + charIndex.TrailingLength, logicalDirection);
            }

#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StopTimer("TextBlock.GetTextPositionFromDistance", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif
            return pos;
        }
Exemple #10
0
        /// <summary>
        /// Returns an ICollection of bounding rectangles for the given ContentElement
        /// </summary>
        /// <param name="child">
        /// Content element for which rectangles are required
        /// </param>
        /// <remarks>
        /// Looks at the ContentElement e line by line and gets rectangle bounds for each line
        /// </remarks>
        protected virtual ReadOnlyCollection<Rect> GetRectanglesCore(ContentElement child)
        {
            if (child == null)
            {
                throw new ArgumentNullException("child");
            }

            // If layout data is not updated we assume that we will not be able to find the element we need and throw excception
            if (!IsLayoutDataValid)
            {
                // return empty collection
                return new ReadOnlyCollection<Rect>(new List<Rect>(0));
            }

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();

            // Check for complex content
            if (_complexContent == null || !(_complexContent.TextContainer is TextContainer))
            {
                // return empty collection
                return new ReadOnlyCollection<Rect>(new List<Rect>(0));
            }

            // First find the element start and end position
            TextPointer start = FindElementPosition((IInputElement)child);
            if (start == null)
            {
                return new ReadOnlyCollection<Rect>(new List<Rect>(0));
            }

            TextPointer end = null;
            if (child is TextElement)
            {
                end = new TextPointer(((TextElement)child).ElementEnd);
            }
            else if (child is FrameworkContentElement)
            {
                end = new TextPointer(start);
                end.MoveByOffset(+1);
            }

            if (end == null)
            {
                return new ReadOnlyCollection<Rect>(new List<Rect>(0));
            }

            int startOffset = _complexContent.TextContainer.Start.GetOffsetToPosition(start);
            int endOffset = _complexContent.TextContainer.Start.GetOffsetToPosition(end);

            int lineIndex = 0;
            int lineOffset = 0;
            double lineHeightOffset = 0;
            int lineCount = LineCount;
            while (startOffset >= (lineOffset + GetLine(lineIndex).Length) && lineIndex < lineCount)
            {
Debug.Assert(lineCount == LineCount);
                lineOffset += GetLine(lineIndex).Length;
                lineIndex++;
                lineHeightOffset += GetLine(lineIndex).Height;
            }
            Debug.Assert(lineIndex < lineCount);

            int lineStart = lineOffset;
            List<Rect> rectangles = new List<Rect>();
            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);

            TextRunCache textRunCache = new TextRunCache();

            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);
            do
            {
Debug.Assert(lineCount == LineCount);
                // Check that line index never exceeds line count
                Debug.Assert(lineIndex < lineCount);

                // Create lines as long as they are spanned by the element
                LineMetrics lineMetrics = GetLine(lineIndex);

                Line line = CreateLine(lineProperties);

                using (line)
                {
                    // Check if paragraph ellipsis are rendered
                    bool ellipsis = ParagraphEllipsisShownOnLine(lineIndex, lineOffset);
                    line.Format(lineStart, wrappingWidth, GetLineProperties(lineIndex == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis);

                    // Verify consistency of line formatting
                    // 
                    if (lineMetrics.Length == line.Length)
                    {
                        //MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of [....]");
                        //Debug.Assert(DoubleUtil.AreClose(CalcLineAdvance(line.Height, lineProperties), lineMetrics.Height), "Line height is out of [....].");

                        int boundStart = (startOffset >= lineStart) ? startOffset : lineStart;
                        int boundEnd = (endOffset < lineStart + lineMetrics.Length) ? endOffset : lineStart + lineMetrics.Length;

                        double xOffset = contentOffset.X;
                        double yOffset = contentOffset.Y + lineHeightOffset;
                        List<Rect> lineBounds = line.GetRangeBounds(boundStart, boundEnd - boundStart, xOffset, yOffset);
                        Debug.Assert(lineBounds.Count > 0);
                        rectangles.AddRange(lineBounds);
                    }
                }

                lineStart += lineMetrics.Length;
                lineHeightOffset += lineMetrics.Height;
                lineIndex++;
            }
            while (endOffset > lineStart);

            // Rectangles collection must be non-null
            Invariant.Assert(rectangles != null);
            return new ReadOnlyCollection<Rect>(rectangles);
        }
Exemple #11
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 
     );
Exemple #12
0
 internal FormattingContext(bool measureMode, bool clearOnLeft, bool clearOnRight, TextRunCache textRunCache) 
 {
     MeasureMode = measureMode;
     ClearOnLeft = clearOnLeft;
     ClearOnRight = clearOnRight; 
     TextRunCache = textRunCache;
     LineFormatLengthTarget = -1; 
 } 
Exemple #13
0
        /// <summary>
        /// Verify all text formatting arguments
        /// </summary>
        private void VerifyTextFormattingArguments(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextRunCache                textRunCache
            )
        {
            if (textSource == null)
                throw new ArgumentNullException("textSource");

            if (textRunCache == null)
                throw new ArgumentNullException("textRunCache");

            if (paragraphProperties == null)
                throw new ArgumentNullException("paragraphProperties");

            if (paragraphProperties.DefaultTextRunProperties == null)
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties");

            if (paragraphProperties.DefaultTextRunProperties.Typeface == null)
                throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface");

            if (DoubleUtil.IsNaN(paragraphWidth))
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN));

            if (double.IsInfinity(paragraphWidth))
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity));

            if (    paragraphWidth < 0
                || paragraphWidth > Constants.RealInfiniteWidth)
            {
                throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth));
            }

            double realMaxFontRenderingEmSize = Constants.RealInfiniteWidth / Constants.GreatestMutiplierOfEm;

            if (    paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0
                ||  paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize)
            {
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize));
            }

            if (paragraphProperties.Indent > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth));

            if (paragraphProperties.LineHeight > Constants.RealInfiniteWidth)
                throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, Constants.RealInfiniteWidth));

            if (   paragraphProperties.DefaultIncrementalTab < 0
                || paragraphProperties.DefaultIncrementalTab > Constants.RealInfiniteWidth)
            {
                throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, Constants.RealInfiniteWidth));
            }
        }
Exemple #14
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
                );
        }
Exemple #15
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)
                );
        }
Exemple #16
0
        /// <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;
        }
Exemple #17
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);
        }
Exemple #18
0
        /// <summary>
        /// Hit tests to the correct ContentElement within the ContentHost
        /// that the mouse is over.
        /// </summary>
        /// <param name="point">Mouse coordinates relative to the ContentHost.</param>
        protected virtual IInputElement InputHitTestCore(Point point)
        {
            // If layout data is not updated return 'this'.
            if (!IsLayoutDataValid) { return this; }

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();

            // If there is only one line and it is already cached, use it to do hit-testing.
            // Otherwise, do following:
            // a) use cached line information to find which line has been hit,
            // b) re-create the line that has been hit,
            // c) hit-test the line.
            IInputElement ie = null;
            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);
            point -= contentOffset; // // Take into account content offset.

            if (point.X < 0 || point.Y < 0) return this;

            ie = null;
            int dcp = 0;
            double lineOffset = 0;

            TextRunCache textRunCache = new TextRunCache();

            int lineCount = LineCount;
            for (int i = 0; i < lineCount; i++)
            {
Debug.Assert(lineCount == LineCount);
                LineMetrics lineMetrics = GetLine(i);

                if (lineOffset + lineMetrics.Height > point.Y)
                {
                    // The current line has been hit. Format the line and
                    // retrieve IInputElement from the hit position.
                    Line line = CreateLine(lineProperties);
                    using (line)
                    {
                        // Check if paragraph ellipsis are rendered
                        bool ellipsis = ParagraphEllipsisShownOnLine(i, lineOffset);
                        line.Format(dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis);

                        // Verify consistency of line formatting
                        // Check that lineMetrics.Length is in [....] with line.Length
                        // 


                        // 






                        if ((line.Start <= point.X) && (line.Start + line.Width >= point.X))
                        {
                            ie = line.InputHitTest(point.X);
                        }
                    }
                    break; // Line covering the point has been found; no need to continue.
                }

                dcp += lineMetrics.Length;
                lineOffset += lineMetrics.Height;
            }

            // If nothing has been hit, assume that element itself has been hit.
            return (ie != null) ? ie : this;
        }
Exemple #19
0
        [FriendAccessAllowed]   // used by Framework
        internal abstract TextParagraphCache CreateParagraphCache(
#endif
            TextSource                  textSource, 
            int                         firstCharIndex,
            double                      paragraphWidth, 
            TextParagraphProperties     paragraphProperties, 
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache 
            );
Exemple #20
0
        /// <summary>
        /// Retrieves detailed information about a line of text.
        /// </summary>
        /// <param name="dcp">Index of the first character in the line.</param>
        /// <param name="index"> Index of the line</param>
        /// <param name="lineVOffset"> Vertical offset of the line</param>
        /// <param name="cchContent">Number of content characters in the line.</param>
        /// <param name="cchEllipses">Number of content characters hidden by ellipses.</param>
        internal void GetLineDetails(int dcp, int index, double lineVOffset, out int cchContent, out int cchEllipses)
        {
            Invariant.Assert(IsLayoutDataValid);
            Invariant.Assert(index >= 0 && index < LineCount);

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);

            TextRunCache textRunCache = new TextRunCache();

            // Retrieve details from the line.
            using(Line line = CreateLine(lineProperties))
            {
                // Format line. Set showParagraphEllipsis flag to false
                TextLineBreak textLineBreak = GetLine(index).TextLineBreak;
                bool ellipsis = ParagraphEllipsisShownOnLine(index, lineVOffset);
                line.Format(dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), textLineBreak, textRunCache, ellipsis);

                MS.Internal.Invariant.Assert(GetLine(index).Length == line.Length, "Line length is out of [....]");

                cchContent = line.ContentLength;
                cchEllipses = line.GetEllipsesLength();
            }
        }
Exemple #21
0
 /// <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 abstract MinMaxParagraphWidth FormatMinMaxParagraphWidth(
     TextSource                  textSource,
     int                         firstCharIndex,
     TextParagraphProperties     paragraphProperties, 
     TextRunCache                textRunCache
     ); 
Exemple #22
0
        /// <summary>
        /// Retrieves bounds of an object/character at the specified TextPointer.
        /// Throws IndexOutOfRangeException if position is out of range.
        /// </summary>
        /// <param name="orientedPosition">Position of an object/character.</param>
        /// <returns>Bounds of an object/character.</returns>
        internal Rect GetRectangleFromTextPosition(ITextPointer orientedPosition)
        {
#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StartTimer("TextBlock.GetRectangleFromTextPosition", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif
            Invariant.Assert(IsLayoutDataValid);
            Invariant.Assert(orientedPosition != null);

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            EnsureComplexContent();

            // From TextFormatter get rectangle of a single character.
            // If orientation is Backward, get the length of th previous character.
            int characterIndex = _complexContent.TextContainer.Start.GetOffsetToPosition(orientedPosition);
            int originalCharacterIndex = characterIndex;
            if (orientedPosition.LogicalDirection == LogicalDirection.Backward && characterIndex > 0)
            {
                --characterIndex;
            }

            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);

            double lineOffset = 0;
            int dcp = 0;

            TextRunCache textRunCache = new TextRunCache();

            Rect rect = Rect.Empty;
            FlowDirection flowDirection = FlowDirection.LeftToRight;

            int lineCount = LineCount;
            for (int i = 0; i < lineCount; i++)
            {
Debug.Assert(lineCount == LineCount);
                LineMetrics lineMetrics = GetLine(i);

                // characterIndex needs to be within line range. If position points to
                // dcp + line.Length, it means that the next line starts from such position,
                // hence go to the next line.
                // But if this is the last line (EOP character), get rectangle form the last
                // character of the line.
                if (dcp + lineMetrics.Length > characterIndex ||
                    ((dcp + lineMetrics.Length == characterIndex) && (i == lineCount - 1)))
                {
                    using(Line line = CreateLine(lineProperties))
                    {

                        bool ellipsis = ParagraphEllipsisShownOnLine(i, lineOffset);
                        line.Format(dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis);

                        // Check consistency of line length
                        MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of [....]");

                        rect = line.GetBoundsFromTextPosition(characterIndex, out flowDirection);
                    }

                    break;
                }

                dcp += lineMetrics.Length;
                lineOffset += lineMetrics.Height;
            }

            if (!rect.IsEmpty) // Empty rects can't be modified
            {
                rect.X += contentOffset.X;
                rect.Y += contentOffset.Y + lineOffset;

                // Return only TopLeft and Height.
                // Adjust rect.Left by taking into account flow direction of the
                // content and orientation of input position.
                if (lineProperties.FlowDirection != flowDirection)
                {
                    if (orientedPosition.LogicalDirection == LogicalDirection.Forward || originalCharacterIndex == 0)
                    {
                        rect.X = rect.Right;
                    }
                }
                else
                {
                    // NOTE: check for 'originalCharacterIndex > 0' is only required for position at the beginning
                    //       content with Backward orientation. This should not be a valid position.
                    //       Remove it later
                    if (orientedPosition.LogicalDirection == LogicalDirection.Backward && originalCharacterIndex > 0)
                    {
                        rect.X = rect.Right;
                    }
                }
                rect.Width = 0;
            }
#if TEXTPANELLAYOUTDEBUG
            MS.Internal.PtsHost.TextPanelDebug.StopTimer("TextBlock.GetRectangleFromTextPosition", MS.Internal.PtsHost.TextPanelDebug.Category.TextView);
#endif

            return rect;
        }
Exemple #23
0
 internal TextCache(TextBoxView owner)
 {
     _lineProperties = owner.GetLineProperties();
     _textRunCache = new TextRunCache();
     Control hostControl = (Control)owner.Host;
     TextFormattingMode textFormattingMode = TextOptions.GetTextFormattingMode(hostControl);
     _textFormatter = System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(textFormattingMode);
 }
Exemple #24
0
        /// <summary>
        /// Determines if the given position is at the edge of a caret unit
        /// in the specified direction, and returns true if it is and false otherwise.
        /// Used by the ITextView.IsCaretAtUnitBoundary(ITextPointer position) in
        /// TextParagraphView
        /// </summary>
        /// <param name="position">
        /// Position to test.
        /// </param>
        /// <param name="dcp">
        /// Offset of the current position from start of TextContainer
        /// </param>
        /// <param name="lineIndex">
        /// Index of line in which position is found
        /// </param>
        internal bool IsAtCaretUnitBoundary(ITextPointer position, int dcp, int lineIndex)
        {
            Invariant.Assert(IsLayoutDataValid);
            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();
            EnsureComplexContent();

            TextRunCache textRunCache = new TextRunCache();
            bool isAtCaretUnitBoundary = false;

            int characterIndex = _complexContent.TextContainer.Start.GetOffsetToPosition(position);
            CharacterHit charHit = new CharacterHit();
            if (position.LogicalDirection == LogicalDirection.Backward)
            {
                if (characterIndex > dcp)
                {
                    // Go to trailing edge of previous character
                    charHit = new CharacterHit(characterIndex - 1, 1);
                }
                else
                {
                    // We should not be at line's start dcp with backward context, except in case this is the first line. This is not
                    // a unit boundary
                    return false;
                }
            }
            else if (position.LogicalDirection == LogicalDirection.Forward)
            {
                // Get leading edge of this character index
                charHit = new CharacterHit(characterIndex, 0);
            }

            LineMetrics lineMetrics = GetLine(lineIndex);
            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);

            using(Line line = CreateLine(lineProperties))
            {
                // Format line. Set showParagraphEllipsis flag to false since we are not using information about
                // ellipsis to change line offsets in this case.
                line.Format(dcp, wrappingWidth, GetLineProperties(lineIndex == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, false);

                // Check consistency of line formatting
                MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of [....]");
                isAtCaretUnitBoundary = line.IsAtCaretCharacterHit(charHit);
            }

            return isAtCaretUnitBoundary;
        }
Exemple #25
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
         );
 }
Exemple #26
0
        // ------------------------------------------------------------------
        // Do content alignment.
        // ------------------------------------------------------------------
        private void AlignContent()
        {
            Debug.Assert(IsLayoutDataValid);
            Debug.Assert(CheckFlags(Flags.RequiresAlignment));

            // Line props may be invalid, even if Measure/Arrange is valid - rendering only props are changing.
            LineProperties lineProperties = GetLineProperties();

            double wrappingWidth = CalcWrappingWidth(RenderSize.Width);
            Vector contentOffset = CalcContentOffset(RenderSize, wrappingWidth);

            // Create / format all lines.
            // Since we are disposing line object, it can be reused to format following lines.
            Line line = CreateLine(lineProperties);
            TextRunCache textRunCache = new TextRunCache();

            int dcp = 0;
            double lineOffset = 0;
            int lineCount = LineCount;
            for (int i = 0; i < lineCount; i++)
            {
Debug.Assert(lineCount == LineCount);
                LineMetrics lineMetrics = GetLine(i);

                using (line)
                {
                    bool ellipsis = ParagraphEllipsisShownOnLine(i, lineOffset);
                    line.Format(dcp, wrappingWidth, GetLineProperties(dcp == 0, lineProperties), lineMetrics.TextLineBreak, textRunCache, ellipsis);
                    double lineHeight = CalcLineAdvance(line.Height, lineProperties);

                    // Check consistency of line formatting
                    MS.Internal.Invariant.Assert(lineMetrics.Length == line.Length, "Line length is out of [....]");
                    Debug.Assert(DoubleUtil.AreClose(lineHeight, lineMetrics.Height), "Line height is out of [....].");

                    // Calculated line width might be different from measure width in following cases:
                    // a) dynamically sized children, when FinalSize != AvailableSize
                    // b) non-default horizontal alignment, when FinalSize != AvailableSize
                    // Hence do not assert about matching line width with cached line metrics.

                    lineMetrics = UpdateLine(i, lineMetrics, line.Start, line.Width);
                    dcp += lineMetrics.Length;
                    lineOffset += lineHeight;
                }
            }
            SetFlags(false, Flags.RequiresAlignment);
        }
Exemple #27
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
                );
        }