// Token: 0x06002EE3 RID: 12003 RVA: 0x000D3B5C File Offset: 0x000D1D5C
        internal override ITextPointer GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction)
        {
            FixedTextPointer ftp = this.Container.VerifyPosition(position);
            FixedPosition    fixedPosition;

            if (this._GetFixedPosition(ftp, out fixedPosition))
            {
                DependencyObject element = this.FixedPage.GetElement(fixedPosition.Node);
                if (element is Glyphs)
                {
                    Glyphs       glyphs       = (Glyphs)element;
                    GlyphRun     glyphRun     = glyphs.ToGlyphRun();
                    int          num          = (glyphRun.Characters == null) ? 0 : glyphRun.Characters.Count;
                    CharacterHit characterHit = (fixedPosition.Offset == num) ? new CharacterHit(fixedPosition.Offset - 1, 1) : new CharacterHit(fixedPosition.Offset, 0);
                    CharacterHit obj          = (direction == LogicalDirection.Forward) ? glyphRun.GetNextCaretCharacterHit(characterHit) : glyphRun.GetPreviousCaretCharacterHit(characterHit);
                    if (!characterHit.Equals(obj))
                    {
                        LogicalDirection edge = LogicalDirection.Forward;
                        if (obj.TrailingLength > 0)
                        {
                            edge = LogicalDirection.Backward;
                        }
                        int offset = obj.FirstCharacterIndex + obj.TrailingLength;
                        return(this._CreateTextPointer(new FixedPosition(fixedPosition.Node, offset), edge));
                    }
                }
            }
            ITextPointer textPointer = position.CreatePointer();

            textPointer.MoveToNextInsertionPosition(direction);
            return(textPointer);
        }
Esempio n. 2
0
        /// <summary>
        /// Gets the visual column from a document position (relative to top left of the document).
        /// </summary>
        public int GetVisualColumn(Point point)
        {
            TextLine     textLine = GetTextLineByVisualYPosition(point.Y);
            CharacterHit ch       = textLine.GetCharacterHitFromDistance(point.X);

            return(ch.FirstCharacterIndex + ch.TrailingLength);
        }
Esempio n. 3
0
        internal Span GetAvalonTextElementSpan(Int32 bufferPosition)
        {
            if (!this.ContainsPosition(bufferPosition))
            {
                throw new ArgumentOutOfRangeException("bufferPosition");
            }
            if ((bufferPosition < this.LineSpan.Start) || (bufferPosition > this.LineSpan.End))
            {
                throw new ArgumentOutOfRangeException("bufferPosition");
            }
            if (bufferPosition > (this.LineSpan.End - this.NewlineLength))
            {
                return(new Span(this.LineSpan.End, 0));
            }
            if (bufferPosition == (this.LineSpan.End - this.NewlineLength))
            {
                return(new Span(this.LineSpan.End - this.NewlineLength, this.NewlineLength));
            }
            Int32 lineRelativePosition = this.GetLineRelativePosition(bufferPosition);

            if (lineRelativePosition < 0)
            {
                lineRelativePosition = 0;
            }
            Int32        indexOfLineContaining = this.GetIndexOfLineContaining(lineRelativePosition);
            TextLine     line = _textLines[indexOfLineContaining];
            CharacterHit nextCaretCharacterHit  = line.GetNextCaretCharacterHit(new CharacterHit(lineRelativePosition, 0));
            Int32        bufferRelativePosition = this.GetBufferRelativePosition(nextCaretCharacterHit.FirstCharacterIndex + nextCaretCharacterHit.TrailingLength);

            nextCaretCharacterHit = line.GetPreviousCaretCharacterHit(new CharacterHit(this.GetLineRelativePosition(bufferRelativePosition), 0));
            Int32 start = this.GetBufferRelativePosition(nextCaretCharacterHit.FirstCharacterIndex);

            return(new Span(start, bufferRelativePosition - start));
        }
Esempio n. 4
0
        /// <inheritdoc/>
        public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
        {
            var characterIndex = characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0);

            if (characterIndex > TextRange.End)
            {
                if (NewLineLength > 0)
                {
                    return(Start + Width);
                }
                return(Start + WidthIncludingTrailingWhitespace);
            }

            var currentDistance = Start;

            foreach (var textRun in _shapedTextRuns)
            {
                if (characterIndex > textRun.Text.End)
                {
                    currentDistance += textRun.Size.Width;

                    continue;
                }

                return(currentDistance + textRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(characterIndex)));
            }

            return(currentDistance);
        }
Esempio n. 5
0
        internal int GetVisualColumnFloor(Point point, bool allowVirtualSpace, out bool isAtEndOfLine)
        {
            TextLine textLine = GetTextLineByVisualYPosition(point.Y);

            if (point.X > textLine.WidthIncludingTrailingWhitespace)
            {
                isAtEndOfLine = true;
                if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1])
                {
                    // clicking virtual space in the last line
                    int virtualX = (int)((point.X - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
                    return(VisualLengthWithEndOfLineMarker + virtualX);
                }
                else
                {
                    // GetCharacterHitFromDistance returns a hit with FirstCharacterIndex=last character in line
                    // and TrailingLength=1 when clicking behind the line, so the floor function needs to handle this case
                    // specially and return the line's end column instead.
                    return(GetTextLineVisualStartColumn(textLine) + textLine.Length);
                }
            }
            else
            {
                isAtEndOfLine = false;
            }
            CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X);

            return(ch.FirstCharacterIndex);
        }
Esempio n. 6
0
        /// <summary>
        /// Tries to find the previous character hit.
        /// </summary>
        /// <param name="characterHit">The current character hit.</param>
        /// <param name="previousCharacterHit">The previous character hit.</param>
        /// <returns></returns>
        private bool TryFindPreviousCharacterHit(CharacterHit characterHit, out CharacterHit previousCharacterHit)
        {
            previousCharacterHit = characterHit;

            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

            if (codepointIndex < TextRange.Start)
            {
                return(false); // Cannot go backward anymore.
            }

            var runIndex = GetRunIndexAtCodepointIndex(codepointIndex);

            while (runIndex >= 0)
            {
                var run = _textRuns[runIndex];

                previousCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);

                if (previousCharacterHit.FirstCharacterIndex < codepointIndex)
                {
                    return(true);
                }

                runIndex--;
            }

            return(false);
        }
Esempio n. 7
0
        /// <inheritdoc/>
        public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
        {
            int  nextVisibleCp;
            bool navigableCpFound;

            if (characterHit.TrailingLength == 0)
            {
                navigableCpFound = FindNextCodepointIndex(characterHit.FirstCharacterIndex, out nextVisibleCp);

                if (navigableCpFound)
                {
                    // Move from leading to trailing edge
                    return(new CharacterHit(nextVisibleCp, 1));
                }
            }

            navigableCpFound = FindNextCodepointIndex(characterHit.FirstCharacterIndex + 1, out nextVisibleCp);

            if (navigableCpFound)
            {
                // Move from trailing edge of current character to trailing edge of next
                return(new CharacterHit(nextVisibleCp, 1));
            }

            // Can't move, we're after the last character
            return(characterHit);
        }
            public override double GetDistanceFromCharacterHit(CharacterHit characterHit)
            {
                double distance = 0;
                int    index    = 0;

                foreach (var entry in entries)
                {
                    if (entry.Item2 == null)
                    {
                        if (index == characterHit.FirstCharacterIndex)
                        {
                            return(distance);
                        }
                        distance += entry.Item4;
                        index    += entry.Item1.Length;

                        continue;
                    }

                    index = getCharOffset(entry.Item1.CharacterBufferReference);
                    var widthList = entry.Item2.AdvanceWidths;
                    for (int i = 0; i < widthList.Count; i++)
                    {
                        if (index == characterHit.FirstCharacterIndex)
                        {
                            return(distance);
                        }
                        distance += widthList[i];
                        index++;
                    }
                }
                return(distance);
            }
Esempio n. 9
0
        /// <inheritdoc/>
        public override CharacterHit GetCharacterHitFromDistance(double distance)
        {
            if (distance < 0)
            {
                // hit happens before the line, return the first position
                return(new CharacterHit(TextRange.Start));
            }

            // process hit that happens within the line
            var characterHit = new CharacterHit();

            foreach (var run in _textRuns)
            {
                characterHit = run.GlyphRun.GetCharacterHitFromDistance(distance, out _);

                if (distance <= run.Size.Width)
                {
                    break;
                }

                distance -= run.Size.Width;
            }

            return(characterHit);
        }
Esempio n. 10
0
        /// <summary>
        /// Tries to find the next character hit.
        /// </summary>
        /// <param name="characterHit">The current character hit.</param>
        /// <param name="nextCharacterHit">The next character hit.</param>
        /// <returns></returns>
        private bool TryFindNextCharacterHit(CharacterHit characterHit, out CharacterHit nextCharacterHit)
        {
            nextCharacterHit = characterHit;

            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

            if (codepointIndex >= TextRange.Start + TextRange.Length)
            {
                return(false); // Cannot go forward anymore
            }

            var runIndex = GetRunIndexAtCodepointIndex(codepointIndex);

            while (runIndex < TextRuns.Count)
            {
                var run = _textRuns[runIndex];

                nextCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);

                if (codepointIndex <= nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength)
                {
                    return(true);
                }

                runIndex++;
            }

            return(false);
        }
Esempio n. 11
0
        public void Should_Get_Next_Caret_CharacterHit(string text)
        {
            using (Start())
            {
                var defaultProperties = new GenericTextRunProperties(Typeface.Default);

                var textSource = new SingleBufferTextSource(text, defaultProperties);

                var formatter = new TextFormatterImpl();

                var textLine =
                    formatter.FormatLine(textSource, 0, double.PositiveInfinity,
                                         new GenericTextParagraphProperties(defaultProperties));

                var clusters = textLine.TextRuns.Cast <ShapedTextCharacters>().SelectMany(x => x.GlyphRun.GlyphClusters)
                               .ToArray();

                var nextCharacterHit = new CharacterHit(0);

                for (var i = 1; i < clusters.Length; i++)
                {
                    nextCharacterHit = textLine.GetNextCaretCharacterHit(nextCharacterHit);

                    Assert.Equal(clusters[i], nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength);
                }
            }
        }
Esempio n. 12
0
        public ICaretPosition MoveCaretToLocation(Double horizontalDistance)
        {
            Double offset = horizontalDistance - this.HorizontalOffset;

            if (offset < 0)
            {
                return(_textView.Caret.MoveTo(this.LineSpan.Start, CaretPlacement.LeftOfCharacter));
            }
            if (this.NewlineLength == 0)
            {
                if (offset >= this.Width)
                {
                    return(_textView.Caret.MoveTo(this.LineSpan.End, CaretPlacement.LeftOfCharacter));
                }
            }
            else if (offset >= (this.Width - 7))
            {
                return(_textView.Caret.MoveTo(this.LineSpan.End - this.NewlineLength, CaretPlacement.LeftOfCharacter));
            }
            Int32        indexOfTextLineAtDistance = this.GetIndexOfTextLineAtDistance(offset);
            TextLine     line = _textLines[indexOfTextLineAtDistance];
            Double       num3 = _textLineDistances[indexOfTextLineAtDistance];
            CharacterHit characterHitFromDistance = line.GetCharacterHitFromDistance(offset - num3);
            Int32        bufferRelativePosition   = this.GetBufferRelativePosition(characterHitFromDistance.FirstCharacterIndex);

            if (bufferRelativePosition > (this.LineSpan.End - this.NewlineLength))
            {
                return(_textView.Caret.MoveTo(this.LineSpan.End - this.NewlineLength, CaretPlacement.LeftOfCharacter));
            }
            return(_textView.Caret.MoveTo(bufferRelativePosition, (characterHitFromDistance.TrailingLength == 0) ? CaretPlacement.LeftOfCharacter : CaretPlacement.RightOfCharacter));
        }
Esempio n. 13
0
        // Token: 0x06003510 RID: 13584 RVA: 0x000F0934 File Offset: 0x000EEB34
        private int GlyphRunHitTest(GlyphRun run, double xoffset, bool LTR)
        {
            double       distance = LTR ? (xoffset - run.BaselineOrigin.X) : (run.BaselineOrigin.X - xoffset);
            bool         flag;
            CharacterHit caretCharacterHitFromDistance = run.GetCaretCharacterHitFromDistance(distance, out flag);

            return(caretCharacterHitFromDistance.FirstCharacterIndex + caretCharacterHitFromDistance.TrailingLength);
        }
Esempio n. 14
0
        //Returns the character offset in a GlyphRun given an X position
        private int GlyphRunHitTest(GlyphRun run, double xoffset, bool LTR)
        {
            bool         isInside;
            double       distance = LTR ? xoffset - run.BaselineOrigin.X : run.BaselineOrigin.X - xoffset;
            CharacterHit hit      = run.GetCaretCharacterHitFromDistance(distance, out isInside);

            return(hit.FirstCharacterIndex + hit.TrailingLength);
        }
Esempio n. 15
0
        /// <inheritdoc/>
        public override CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
        {
            if (TryFindPreviousCharacterHit(characterHit, out var previousCharacterHit))
            {
                return(previousCharacterHit);
            }

            return(new CharacterHit(TextRange.Start)); // Can't move, we're before the first character
        }
Esempio n. 16
0
        /// <inheritdoc/>
        public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
        {
            if (TryFindNextCharacterHit(characterHit, out var nextCharacterHit))
            {
                return(nextCharacterHit);
            }

            return(new CharacterHit(TextRange.End)); // Can't move, we're after the last character
        }
Esempio n. 17
0
        /// <summary>
        /// Tries to find the next character hit.
        /// </summary>
        /// <param name="characterHit">The current character hit.</param>
        /// <param name="nextCharacterHit">The next character hit.</param>
        /// <returns></returns>
        private bool TryFindNextCharacterHit(CharacterHit characterHit, out CharacterHit nextCharacterHit)
        {
            nextCharacterHit = characterHit;

            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

            if (codepointIndex >= TextRange.End)
            {
                return(false); // Cannot go forward anymore
            }

            if (codepointIndex < TextRange.Start)
            {
                codepointIndex = TextRange.Start;
            }

            var runIndex = GetRunIndexAtCharacterIndex(codepointIndex, LogicalDirection.Forward);

            while (runIndex < _textRuns.Count)
            {
                var run = _textRuns[runIndex];

                var foundCharacterHit =
                    run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength,
                                                         out _);

                var isAtEnd = foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength ==
                              TextRange.Length;

                if (isAtEnd && !run.GlyphRun.IsLeftToRight)
                {
                    nextCharacterHit = foundCharacterHit;

                    return(true);
                }

                var characterIndex = codepointIndex - run.Text.Start;

                if (characterIndex < 0 && run.ShapedBuffer.IsLeftToRight)
                {
                    foundCharacterHit = new CharacterHit(foundCharacterHit.FirstCharacterIndex);
                }

                nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ?
                                   foundCharacterHit :
                                   new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength);

                if (isAtEnd || nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex)
                {
                    return(true);
                }

                runIndex++;
            }

            return(false);
        }
Esempio n. 18
0
        /// <summary>
        /// Calculates the offset for the corresponding TextPointer from a CharacterHit
        /// </summary>
        /// <remarks>
        /// This is necessary to ensure that we don't try to create a position at an offset greater than TextContainer's symbol count.
        /// This may happen when a line is collapsed with ellipsis and we hit-test at the trailing edge of ellipsis, the trailing length
        /// returned for the CharacterHit is the length of all collapsed characters, including the synthetic EOP. If we try to
        /// create a position at this trailing length we can exceed TextContainer's symbol count.
        /// </remarks>
        private int CalcPositionOffset(CharacterHit charHit)
        {
            int offset = charHit.FirstCharacterIndex + charHit.TrailingLength;

            if (this.EndOfParagraph)
            {
                offset = Math.Min(_dcp + this.Length, offset);
            }
            return(offset);
        }
        // Token: 0x0600660A RID: 26122 RVA: 0x001CB238 File Offset: 0x001C9438
        private int CalcPositionOffset(CharacterHit charHit)
        {
            int num = charHit.FirstCharacterIndex + charHit.TrailingLength;

            if (base.EndOfParagraph)
            {
                num = Math.Min(this._dcp + base.Length, num);
            }
            return(num);
        }
Esempio n. 20
0
        public void Should_Get_Distance_From_CharacterHit(double[] advances, ushort[] clusters, int start, int trailingLength, double expectedDistance)
        {
            using (var glyphRun = CreateGlyphRun(advances, clusters))
            {
                var characterHit = new CharacterHit(start, trailingLength);

                var distance = glyphRun.GetDistanceFromCharacterHit(characterHit);

                Assert.Equal(expectedDistance, distance);
            }
        }
Esempio n. 21
0
        public void Should_Get_Distance_From_CharacterHit(double[] advances, int[] clusters, int start, int trailingLength, double expectedDistance)
        {
            using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
                using (var glyphRun = CreateGlyphRun(advances, clusters))
                {
                    var characterHit = new CharacterHit(start, trailingLength);

                    var distance = glyphRun.GetDistanceFromCharacterHit(characterHit);

                    Assert.Equal(expectedDistance, distance);
                }
        }
Esempio n. 22
0
        static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine,
                                     CharacterHit ch, bool allowWrapToNextLine)
        {
            int newVisualColumn    = ch.FirstCharacterIndex + ch.TrailingLength;
            int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);

            if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length)
            {
                newVisualColumn = targetLineStartCol + targetLine.Length - 1;
            }
            int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset;

            SetCaretPosition(textArea, newVisualColumn, newOffset);
        }
        /// <summary>
        /// Gets the visual column from a document position (relative to top left of the document).
        /// If the user clicks between two visual columns, rounds to the nearest column.
        /// </summary>
        public int GetVisualColumn(TextLine textLine, double xPos, bool allowVirtualSpace)
        {
            if (xPos > textLine.WidthIncludingTrailingWhitespace)
            {
                if (allowVirtualSpace && textLine == TextLines[TextLines.Count - 1])
                {
                    int virtualX = (int)Math.Round((xPos - textLine.WidthIncludingTrailingWhitespace) / textView.WideSpaceWidth);
                    return(VisualLengthWithEndOfLineMarker + virtualX);
                }
            }
            CharacterHit ch = textLine.GetCharacterHitFromDistance(xPos);

            return(ch.FirstCharacterIndex + ch.TrailingLength);
        }
Esempio n. 24
0
        /// <inheritdoc/>
        public override CharacterHit GetPreviousCaretCharacterHit(CharacterHit characterHit)
        {
            if (TryFindPreviousCharacterHit(characterHit, out var previousCharacterHit))
            {
                return(previousCharacterHit);
            }

            if (characterHit.FirstCharacterIndex <= FirstTextSourceIndex)
            {
                characterHit = new CharacterHit(FirstTextSourceIndex);
            }

            return(characterHit); // Can't move, we're before the first character
        }
        public void Should_Get_Previous_Caret_CharacterHit_Bidi()
        {
            const string text = "אבג 1 ABC";

            using (Start())
            {
                var defaultProperties = new GenericTextRunProperties(Typeface.Default);

                var textSource = new SingleBufferTextSource(text, defaultProperties);

                var formatter = new TextFormatterImpl();

                var textLine =
                    formatter.FormatLine(textSource, 0, double.PositiveInfinity,
                                         new GenericTextParagraphProperties(defaultProperties));

                var clusters = new List <int>();

                foreach (var textRun in textLine.TextRuns.OrderBy(x => x.Text.Start))
                {
                    var shapedRun = (ShapedTextCharacters)textRun;

                    clusters.AddRange(shapedRun.IsReversed ?
                                      shapedRun.ShapedBuffer.GlyphClusters.Reverse() :
                                      shapedRun.ShapedBuffer.GlyphClusters);
                }

                clusters.Reverse();

                var nextCharacterHit = new CharacterHit(text.Length - 1);

                foreach (var cluster in clusters)
                {
                    var currentCaretIndex = nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength;

                    Assert.Equal(cluster, currentCaretIndex);

                    nextCharacterHit = textLine.GetPreviousCaretCharacterHit(nextCharacterHit);
                }

                var lastCharacterHit = nextCharacterHit;

                nextCharacterHit = textLine.GetPreviousCaretCharacterHit(lastCharacterHit);

                Assert.Equal(lastCharacterHit.FirstCharacterIndex, nextCharacterHit.FirstCharacterIndex);

                Assert.Equal(lastCharacterHit.TrailingLength, nextCharacterHit.TrailingLength);
            }
        }
Esempio n. 26
0
        /// <summary>
        /// Gets the visual column from a document position (relative to top left of the document).
        /// If the user clicks between two visual columns, returns the first of those columns.
        /// </summary>
        public int GetVisualColumnFloor(Point point)
        {
            TextLine textLine = GetTextLineByVisualYPosition(point.Y);

            if (point.X > textLine.WidthIncludingTrailingWhitespace)
            {
                // GetCharacterHitFromDistance returns a hit with FirstCharacterIndex=last character inline
                // and TrailingLength=1 when clicking behind the line, so the floor function needs to handle this case
                // specially end return the line's end column instead.
                return(GetTextLineVisualStartColumn(textLine) + textLine.Length);
            }
            CharacterHit ch = textLine.GetCharacterHitFromDistance(point.X);

            return(ch.FirstCharacterIndex);
        }
Esempio n. 27
0
        /// <summary>
        /// Tries to find the previous character hit.
        /// </summary>
        /// <param name="characterHit">The current character hit.</param>
        /// <param name="previousCharacterHit">The previous character hit.</param>
        /// <returns></returns>
        private bool TryFindPreviousCharacterHit(CharacterHit characterHit, out CharacterHit previousCharacterHit)
        {
            var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

            if (characterIndex == TextRange.Start)
            {
                previousCharacterHit = new CharacterHit(TextRange.Start);

                return(true);
            }

            previousCharacterHit = characterHit;

            if (characterIndex < TextRange.Start)
            {
                return(false); // Cannot go backward anymore.
            }

            var runIndex = GetRunIndexAtCharacterIndex(characterIndex, LogicalDirection.Backward);

            while (runIndex >= 0)
            {
                var run = _textRuns[runIndex];

                var foundCharacterHit =
                    run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex - 1, out _);

                if (foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength < characterIndex)
                {
                    previousCharacterHit = foundCharacterHit;

                    return(true);
                }

                previousCharacterHit = characterHit.TrailingLength != 0 ?
                                       foundCharacterHit :
                                       new CharacterHit(foundCharacterHit.FirstCharacterIndex);

                if (previousCharacterHit != characterHit)
                {
                    return(true);
                }

                runIndex--;
            }

            return(false);
        }
Esempio n. 28
0
        /// <inheritdoc/>
        public override CharacterHit GetNextCaretCharacterHit(CharacterHit characterHit)
        {
            if (TryFindNextCharacterHit(characterHit, out var nextCharacterHit))
            {
                return(nextCharacterHit);
            }

            // Can't move, we're after the last character
            var runIndex = GetRunIndexAtCharacterIndex(TextRange.End, LogicalDirection.Forward);

            var textRun = _textRuns[runIndex];

            characterHit = textRun.GlyphRun.GetNextCaretCharacterHit(characterHit);

            return(characterHit);
        }
Esempio n. 29
0
        /// <summary>
        /// Tries to find the next character hit.
        /// </summary>
        /// <param name="characterHit">The current character hit.</param>
        /// <param name="nextCharacterHit">The next character hit.</param>
        /// <returns></returns>
        private bool TryFindNextCharacterHit(CharacterHit characterHit, out CharacterHit nextCharacterHit)
        {
            nextCharacterHit = characterHit;

            var codepointIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength;

            if (codepointIndex > TextRange.End)
            {
                return(false); // Cannot go forward anymore
            }

            var runIndex = GetRunIndexAtCodepointIndex(codepointIndex);

            while (runIndex < TextRuns.Count)
            {
                var run = _textRuns[runIndex];

                var foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(characterHit.FirstCharacterIndex + characterHit.TrailingLength, out _);

                var isAtEnd = foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength ==
                              TextRange.Length;

                var characterIndex = codepointIndex - run.Text.Start;

                var codepoint = Codepoint.ReadAt(run.GlyphRun.Characters, characterIndex, out _);

                if (codepoint.IsBreakChar)
                {
                    foundCharacterHit = run.GlyphRun.FindNearestCharacterHit(codepointIndex - 1, out _);

                    isAtEnd = true;
                }

                nextCharacterHit = isAtEnd || characterHit.TrailingLength != 0 ?
                                   foundCharacterHit :
                                   new CharacterHit(foundCharacterHit.FirstCharacterIndex + foundCharacterHit.TrailingLength);

                if (isAtEnd || nextCharacterHit.FirstCharacterIndex > characterHit.FirstCharacterIndex)
                {
                    return(true);
                }

                runIndex++;
            }

            return(false);
        }
        /// <summary>
        /// Validate the input character hit
        /// </summary>
        internal static void VerifyCaretCharacterHit(
            CharacterHit characterHit,
            int cpFirst,
            int cchLength
            )
        {
            if (characterHit.FirstCharacterIndex < cpFirst ||
                characterHit.FirstCharacterIndex > cpFirst + cchLength)
            {
                throw new ArgumentOutOfRangeException("cpFirst", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength));
            }

            if (characterHit.TrailingLength < 0)
            {
                throw new ArgumentOutOfRangeException("cchLength", SR.Get(SRID.ParameterCannotBeNegative));
            }
        }
        /// <summary>
        /// Client to get the next character hit for caret navigation
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <returns>the next character hit</returns>
        public override CharacterHit GetNextCaretCharacterHit(
            CharacterHit    characterHit
            )
        {
            TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _cpLength);

            int nextVisisbleCp;
            bool navigableCpFound;
            if (characterHit.TrailingLength == 0)
            {
                navigableCpFound = FindNextVisibleCp(characterHit.FirstCharacterIndex, out nextVisisbleCp);
                if (navigableCpFound)
                {
                    // Move from leading to trailing edge
                    return new CharacterHit(nextVisisbleCp, 1);
                }
            }

            navigableCpFound = FindNextVisibleCp(characterHit.FirstCharacterIndex + 1, out nextVisisbleCp);
            if (navigableCpFound)
            {
                // Move from trailing edge of current character to trailing edge of next
                return new CharacterHit(nextVisisbleCp, 1);
            }

            // Can't move, we're after the last character
            return characterHit;
        }
        /// <summary>
        /// Client to get the previous character hit for caret navigation
        /// </summary>
        /// <param name="characterHit">the current character hit</param>
        /// <returns>the previous character hit</returns>
        public override CharacterHit GetPreviousCaretCharacterHit(
            CharacterHit    characterHit
            )
        {
            TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _cpLength);
            int previousVisisbleCp;
            bool navigableCpFound;

            int cpHit = characterHit.FirstCharacterIndex;
            bool trailingHit = (characterHit.TrailingLength != 0);

            // Input can be right after the end of the current line. Snap it to be at the end of the line.
            if (cpHit >= _cpFirst + _cpLength)
            {
                cpHit = _cpFirst + _cpLength - 1;
                trailingHit = true;
            }

            if (trailingHit)
            {
                navigableCpFound = FindPreviousVisibleCp(cpHit, out previousVisisbleCp);
                if (navigableCpFound)
                {
                    // Move from trailing to leading edge
                    return new CharacterHit(previousVisisbleCp, 0);
                }
            }

            navigableCpFound = FindPreviousVisibleCp(cpHit - 1, out previousVisisbleCp);
            if (navigableCpFound)
            {
                // Move from leading edge of current character to leading edge of previous
                return new CharacterHit(previousVisisbleCp, 0);
            }

            // Can't move, we're before the first character
            return characterHit;
        }
Esempio n. 33
0
        private ITextPointer BackspaceCaretUnitPositionFromDcpSimpleLines( 
            int dcp,
            ITextPointer position, 
            ref PTS.FSTEXTDETAILSFULL textDetails)
        {
            ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap);
 
            // Get list of lines
            PTS.FSLINEDESCRIPTIONSINGLE[] arrayLineDesc; 
            PtsHelper.LineListSimpleFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); 

            // Declare backspace position and set it to initial position 
            ITextPointer backspaceCaretPosition = position;

            // First iterate through lines
            for (int index = 0; index < arrayLineDesc.Length; index++) 
            {
                PTS.FSLINEDESCRIPTIONSINGLE lineDesc = arrayLineDesc[index]; 
 
                // 'dcp' needs to be within line range. If position points to dcpLim,
                // it means that the next line starts from such position, hence go to the next line. 
                if (((lineDesc.dcpFirst <= dcp) && (lineDesc.dcpLim > dcp))
                    || ((lineDesc.dcpLim == dcp) && (index == arrayLineDesc.Length - 1)))
                {
                    if (dcp == lineDesc.dcpFirst) 
                    {
                        // Go to previous line 
                        if (index == 0) 
                        {
                            return position; 
                        }
                        else
                        {
                            // Update dcp, lineDesc 
                            Debug.Assert(index > 0);
                            --index; 
                            lineDesc = arrayLineDesc[index]; 
                        }
                    } 

                    // Create and format line
                    Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition);
                    Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(lineDesc.fClearOnLeft), PTS.ToBoolean(lineDesc.fClearOnRight), TextParagraph.TextRunCache); 

                    if(IsOptimalParagraph) 
                    { 
                        ctx.LineFormatLengthTarget = lineDesc.dcpLim - lineDesc.dcpFirst;
                    } 

                    TextParagraph.FormatLineCore(line, lineDesc.pfsbreakreclineclient, ctx, lineDesc.dcpFirst, lineDesc.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), lineDesc.dcpFirst);

                    // Assert that number of characters in Text line is the same as our expected length 
                    Invariant.Assert(line.SafeLength == lineDesc.dcpLim - lineDesc.dcpFirst, "Line length is out of [....]");
 
                    // Create CharacterHit and get backspace index from line API 
                    CharacterHit textSourceCharacterIndex = new CharacterHit(dcp, 0);
                    CharacterHit backspaceCharacterHit = line.GetBackspaceCaretCharacterHit(textSourceCharacterIndex); 
                    LogicalDirection logicalDirection;
                    if (backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength == lineDesc.dcpFirst)
                    {
                        // Going forward brought us to the start of a line, context must be backward for previous line 
                        if (index == 0)
                        { 
                            // First line, so we will stay forward 
                            logicalDirection = LogicalDirection.Forward;
                        } 
                        else
                        {
                            logicalDirection = LogicalDirection.Backward;
                        } 
                    }
                    else 
                    { 
                        logicalDirection = (backspaceCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward;
                    } 
                    backspaceCaretPosition = GetTextPosition(backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength, logicalDirection);

                    // Dispose the line
                    line.Dispose(); 
                    break;
                } 
            } 
            Debug.Assert(backspaceCaretPosition != null);
            return backspaceCaretPosition; 
        }
Esempio n. 34
0
        private bool IsAtCaretUnitBoundaryFromDcpSimpleLines( 
            int dcp, 
            ITextPointer position,
            ref PTS.FSTEXTDETAILSFULL textDetails) 
        {
            ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap);

            // Get list of lines 
            PTS.FSLINEDESCRIPTIONSINGLE[] arrayLineDesc;
            PtsHelper.LineListSimpleFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); 
 
            bool isAtCaretUnitBoundary = false;
 
            // First iterate through lines
            for (int index = 0; index < arrayLineDesc.Length; index++)
            {
                PTS.FSLINEDESCRIPTIONSINGLE lineDesc = arrayLineDesc[index]; 

                // 'dcp' needs to be within line range. If position points to dcpLim, 
                // it means that the next line starts from such position, hence go to the next line. 
                if (((lineDesc.dcpFirst <= dcp) && (lineDesc.dcpLim > dcp))
                    || ((lineDesc.dcpLim == dcp) && (index == arrayLineDesc.Length - 1))) 
                {
                    CharacterHit charHit = new CharacterHit();
                    if (dcp >= lineDesc.dcpLim - 1 && index == arrayLineDesc.Length - 1)
                    { 
                        // Special case: last line has additional character to mark the end of paragraph.
                        // We should not try and check for next source character index 
                        // But just return true in this case 
                        return true;
                    } 

                    if (position.LogicalDirection == LogicalDirection.Backward)
                    {
                        if (lineDesc.dcpFirst == dcp) 
                        {
                            if (index == 0) 
                            { 
                                // First position of first line does not have a trailing edge. Return false.
                                return false; 
                            }
                            else
                            {
                                // Get the trailing edge of the last character on the previous line, at dcp - 1 
                                index--;
                                lineDesc = arrayLineDesc[index]; 
                                Invariant.Assert(dcp > 0); 
                                charHit = new CharacterHit(dcp - 1, 1);
                            } 
                        }
                        else
                        {
                            // Get CharacterHit at trailing edge of previous position 
                            Invariant.Assert(dcp > 0);
                            charHit = new CharacterHit(dcp - 1, 1); 
                        } 
                    }
                    else if (position.LogicalDirection == LogicalDirection.Forward) 
                    {
                        // Get character hit at leading edge
                        charHit = new CharacterHit(dcp, 0);
                    } 

                    // Create and format line 
                    Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); 
                    Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(lineDesc.fClearOnLeft), PTS.ToBoolean(lineDesc.fClearOnRight), TextParagraph.TextRunCache);
 
                    if(IsOptimalParagraph)
                    {
                        ctx.LineFormatLengthTarget = lineDesc.dcpLim - lineDesc.dcpFirst;
                    } 

                    TextParagraph.FormatLineCore(line, lineDesc.pfsbreakreclineclient, ctx, lineDesc.dcpFirst, lineDesc.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), lineDesc.dcpFirst); 
 
                    // Assert that number of characters in Text line is the same as our expected length
                    Invariant.Assert(line.SafeLength == lineDesc.dcpLim - lineDesc.dcpFirst, "Line length is out of [....]"); 
                    isAtCaretUnitBoundary = line.IsAtCaretCharacterHit(charHit);

                    // Dispose the line
                    line.Dispose(); 
                    break;
                } 
            } 
            return isAtCaretUnitBoundary;
        } 
Esempio n. 35
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;
        }
Esempio n. 36
0
 //-------------------------------------------------------------------
 // Retrieve text position for backspace caret position
 //
 // index: CharacterHit for current position
 //
 // Returns: Text position index.
 //-------------------------------------------------------------------
 internal CharacterHit GetBackspaceCaretCharacterHit(CharacterHit index)
 {
     return _line.GetBackspaceCaretCharacterHit(index);
 }
Esempio n. 37
0
 /// <summary>
 /// Client to get the previous character hit for caret navigation
 /// </summary>
 /// <param name="characterHit">the current character hit</param>
 /// <returns>the previous character hit</returns>
 public abstract CharacterHit GetPreviousCaretCharacterHit(
     CharacterHit    characterHit
     );
Esempio n. 38
0
 /// <summary>
 /// Client to get the previous character hit after backspacing
 /// </summary>
 /// <param name="characterHit">the current character hit</param>
 /// <returns>the character hit after backspacing</returns>
 public abstract CharacterHit GetBackspaceCaretCharacterHit(
     CharacterHit    characterHit
     );
        static void SetCaretPosition(TextArea textArea, VisualLine targetVisualLine, TextLine targetLine,
		                             CharacterHit ch, bool allowWrapToNextLine)
        {
            int newVisualColumn = ch.FirstCharacterIndex + ch.TrailingLength;
            int targetLineStartCol = targetVisualLine.GetTextLineVisualStartColumn(targetLine);
            if (!allowWrapToNextLine && newVisualColumn >= targetLineStartCol + targetLine.Length)
                newVisualColumn = targetLineStartCol + targetLine.Length - 1;
            int newOffset = targetVisualLine.GetRelativeOffset(newVisualColumn) + targetVisualLine.FirstDocumentLine.Offset;
            SetCaretPosition(textArea, newVisualColumn, newOffset);
        }
Esempio n. 40
0
        internal bool IsAtCaretCharacterHit(CharacterHit characterHit, int cpFirst)
        {   
            // TrailingLength is used as a flag to indicate whether the character 
            // hit is on the leading or trailing edge of the character.
            if (characterHit.TrailingLength == 0)
            {
                CharacterHit nextHit = GetNextCaretCharacterHit(characterHit);
                if (nextHit == characterHit)
                {
                    // At this point we only know that no caret stop is available 
                    // after the input, we caliberate the input to the end of the line.
                    nextHit = new CharacterHit(cpFirst + Length - 1, 1);
                }

                CharacterHit previousHit = GetPreviousCaretCharacterHit(nextHit);
                return previousHit == characterHit;
            }
            else
            {
                CharacterHit previousHit = GetPreviousCaretCharacterHit(characterHit);              
                CharacterHit nextHit     = GetNextCaretCharacterHit(previousHit);
                return nextHit == characterHit; 
            }
        }
Esempio n. 41
0
 /// <summary>
 /// Client to get the distance from the beginning of the line from the specified 
 /// character hit.
 /// </summary>
 /// <param name="characterHit">character hit of the character to query the distance.</param>
 /// <returns>distance in text flow direction from the beginning of the line.</returns>
 public abstract double GetDistanceFromCharacterHit(
     CharacterHit    characterHit
     );
Esempio n. 42
0
 /// <summary>
 /// Client to get the next character hit for caret navigation
 /// </summary>
 /// <param name="characterHit">the current character hit</param>
 /// <returns>the next character hit</returns>
 public abstract CharacterHit GetNextCaretCharacterHit(
     CharacterHit    characterHit
     );
Esempio n. 43
0
        /// <summary>
        /// <see cref="ITextView.IsAtCaretUnitBoundary"/>
        /// </summary>
        bool ITextView.IsAtCaretUnitBoundary(ITextPointer position)
        {
            Invariant.Assert(this.IsLayoutValid);
            Invariant.Assert(Contains(position));
            bool boundary = false;

            int lineIndex = GetLineIndexFromPosition(position);

            CharacterHit sourceCharacterHit = new CharacterHit();
            if (position.LogicalDirection == LogicalDirection.Forward)
            {
                // Forward context, go to leading edge of position offset
                sourceCharacterHit = new CharacterHit(position.Offset, 0);
            }
            else if (position.LogicalDirection == LogicalDirection.Backward)
            {
                if (position.Offset > _lineMetrics[lineIndex].Offset)
                {
                    // For backward context, go to trailing edge of previous character
                    sourceCharacterHit = new CharacterHit(position.Offset - 1, 1);
                }
                else
                {
                    // There is no previous trailing edge on this line. We don't consider this a unit boundary.
                    return false;
                }
            }

            using (TextBoxLine line = GetFormattedLine(lineIndex))
            {
                boundary = line.IsAtCaretCharacterHit(sourceCharacterHit);             
            }

            return boundary;
        }
Esempio n. 44
0
        /// <summary>
        /// <see cref="ITextView.GetNextCaretUnitPosition"/>
        /// </summary>
        ITextPointer ITextView.GetNextCaretUnitPosition(ITextPointer position, LogicalDirection direction)
        {
            Invariant.Assert(this.IsLayoutValid);
            Invariant.Assert(Contains(position));

            // Special case document start/end.
            if (position.Offset == 0 && direction == LogicalDirection.Backward)
            {
                return position.GetFrozenPointer(LogicalDirection.Forward);
            }
            else if (position.Offset == _host.TextContainer.SymbolCount && direction == LogicalDirection.Forward)
            {
                return position.GetFrozenPointer(LogicalDirection.Backward);
            }

            int lineIndex = GetLineIndexFromPosition(position);

            CharacterHit sourceCharacterHit = new CharacterHit(position.Offset, 0);
            CharacterHit nextCharacterHit;

            using (TextBoxLine line = GetFormattedLine(lineIndex))
            {
                if (direction == LogicalDirection.Forward)
                {
                    // Get the next caret position from the line
                    nextCharacterHit = line.GetNextCaretCharacterHit(sourceCharacterHit);
                }
                else
                {
                    // Get previous caret position from the line
                    nextCharacterHit = line.GetPreviousCaretCharacterHit(sourceCharacterHit);
                }
            }

            // Determine logical direction for next caret index and create TextPointer from it.
            LogicalDirection logicalDirection;
            if (nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == _lineMetrics[lineIndex].EndOffset &&
                direction == LogicalDirection.Forward)
            {
                // Going forward brought us to the end of a line, context must be forward for next line.
                if (lineIndex == _lineMetrics.Count - 1)
                {
                    // Last line so context must stay backward.
                    logicalDirection = LogicalDirection.Backward;
                }
                else
                {
                    logicalDirection = LogicalDirection.Forward;
                }
            }
            else if (nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength == _lineMetrics[lineIndex].Offset &&
                     direction == LogicalDirection.Backward)
            {
                // Going backward brought us to the start of a line, context must be backward for previous line.
                if (lineIndex == 0)
                {
                    // First line, so we will stay forward.
                    logicalDirection = LogicalDirection.Forward;
                }
                else
                {
                    logicalDirection = LogicalDirection.Backward;
                }
            }
            else
            {
                logicalDirection = (nextCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward;
            }

            ITextPointer nextCaretUnitPosition = _host.TextContainer.CreatePointerAtOffset(nextCharacterHit.FirstCharacterIndex + nextCharacterHit.TrailingLength, logicalDirection);
            nextCaretUnitPosition.Freeze();
            return nextCaretUnitPosition;
        }
Esempio n. 45
0
 //-------------------------------------------------------------------
 // Retrieve text position for previous caret position
 //
 // index: CharacterHit for current position
 //
 // Returns: Text position index.
 //-------------------------------------------------------------------
 internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index)
 {
     return _line.GetPreviousCaretCharacterHit(index);
 }
Esempio n. 46
0
            /// <summary>
            /// Client to get the distance from the beginning of the line from the specified character hit.
            /// </summary>
            /// <param name="characterHit">index to text source's character store</param>
            /// <returns>distance in text flow direction from the beginning of the line.</returns>
            public override double GetDistanceFromCharacterHit(
                CharacterHit    characterHit
                )
            {
                if ((_statusFlags & StatusFlags.IsDisposed) != 0)
                {
                    throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed));
                }

                TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _metrics._cchLength);

                return _metrics._formatter.IdealToReal(LSLineUToParagraphU(DistanceFromCharacterHit(characterHit)));
            }
Esempio n. 47
0
 /// <summary>
 /// Returns true of char hit is at caret unit boundary.
 /// </summary>
 /// <param name="charHit">
 /// CharacterHit to be tested.
 /// </param>
 internal bool IsAtCaretCharacterHit(CharacterHit charHit)
 {
     return _line.IsAtCaretCharacterHit(charHit, _dcp);
 }
Esempio n. 48
0
            /// <summary>
            /// Get hittest distance relative to line start from specified character hit
            /// </summary>
            private int DistanceFromCharacterHit(CharacterHit characterHit)
            {
                int hitTestDistance = 0;

                if (_ploline.Value == IntPtr.Zero)
                {
                    // Returning start of the line for empty line
                    return hitTestDistance;
                }

                if (characterHit.FirstCharacterIndex >= _cpFirst + _metrics._cchLength)
                {
                    // Returning line width for character hit beyond the last caret stop
                    return _metrics._textStart + _metrics._textWidthAtTrailing;
                }

                if (    HasCollapsed
                    &&  _collapsedRange != null
                    &&  characterHit.FirstCharacterIndex >= _collapsedRange.TextSourceCharacterIndex
                    )
                {
                    // The current character hit is beyond the beginning of the collapsed range
                    int lineEndDistance = _metrics._textStart + _metrics._textWidthAtTrailing;

                    if (    characterHit.FirstCharacterIndex >= _collapsedRange.TextSourceCharacterIndex + _collapsedRange.Length
                        ||  characterHit.TrailingLength != 0
                        || _collapsingSymbol == null
                        )
                    {
                        // The current character hit either hits outside,
                        // or it's at the trailing edge of the collapsed range
                        return lineEndDistance;
                    }

                    return lineEndDistance - TextFormatterImp.RealToIdeal(_collapsingSymbol.Width);
                }

                int actualSublineCount;
                LsTextCell lsTextCell;
                LsQSubInfo[] sublineInfo = new LsQSubInfo[_depthQueryMax];

                int lscpCurrent = GetInternalCp(characterHit.FirstCharacterIndex);

                QueryLineCpPpoint(
                    lscpCurrent,
                    sublineInfo,
                    out actualSublineCount,
                    out lsTextCell
                    );

                if (actualSublineCount > 0)
                {
                    return lsTextCell.pointUvStartCell.x + GetDistanceInsideTextCell(
                        lscpCurrent,
                        characterHit.TrailingLength != 0,
                        sublineInfo,
                        actualSublineCount,
                        ref lsTextCell
                        );
                }

                return hitTestDistance;
            }
Esempio n. 49
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;
        }
Esempio n. 50
0
            /// <summary>
            /// Client to get the next character hit for caret navigation
            /// </summary>
            /// <param name="characterHit">the current character hit</param>
            /// <returns>the next character hit</returns>
            public override CharacterHit GetNextCaretCharacterHit(
                CharacterHit    characterHit
                )
            {
                if ((_statusFlags & StatusFlags.IsDisposed) != 0)
                {
                    throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed));
                }

                TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _metrics._cchLength);

                if (_ploline.Value == System.IntPtr.Zero)
                {
                    return characterHit;
                }

                int caretStopIndex;
                int offsetToNextCaretStopIndex;

                bool found = GetNextOrPreviousCaretStop(
                    characterHit.FirstCharacterIndex,
                    CaretDirection.Forward,
                    out caretStopIndex,
                    out offsetToNextCaretStopIndex
                    );

                if (!found)
                {
                    // The current index is beyond the last caret stop.
                    return characterHit;
                }

                if (caretStopIndex <= characterHit.FirstCharacterIndex && characterHit.TrailingLength != 0)
                {
                    // We treat trailing length of the current character hit as a flag on the way in.
                    // A non-zero value indicates that it is on the trailing edge of the current
                    // caret stop. At this point, the current caret stop fully encloses the input index,
                    // and the input is at the trailing edge. In this case, we move it to the trailing
                    // edge of the next caret stop.
                    found = GetNextOrPreviousCaretStop(
                        caretStopIndex + offsetToNextCaretStopIndex,
                        CaretDirection.Forward,
                        out caretStopIndex,
                        out offsetToNextCaretStopIndex
                        );

                    if (!found)
                    {
                        // This current index is beyond the last caret stop
                        return characterHit;
                    }

                    return new CharacterHit(caretStopIndex, offsetToNextCaretStopIndex);
                }

                // If the current character hit is at the leading edge,
                // move it to trailing edge of the current caret stop.
                return new CharacterHit(caretStopIndex, offsetToNextCaretStopIndex);
            }
Esempio n. 51
0
        private bool IsAtCaretUnitBoundaryFromDcpCompositeLines( 
            int dcp,
            ITextPointer position,
            ref PTS.FSTEXTDETAILSFULL textDetails)
        { 
            ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap);
 
            // Get list of lines 
            PTS.FSLINEDESCRIPTIONCOMPOSITE[] arrayLineDesc;
            PtsHelper.LineListCompositeFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); 

            bool isAtCaretUnitBoundary = false;

            // First iterate through lines 
            for (int index = 0; index < arrayLineDesc.Length; index++)
            { 
                PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc = arrayLineDesc[index]; 
                if (lineDesc.cElements == 0)
                { 
                    continue;
                }

                // Get list of line elements. 
                PTS.FSLINEELEMENT[] arrayLineElement;
                PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); 
 
                for (int elIndex = 0; elIndex < arrayLineElement.Length; elIndex++)
                { 
                    PTS.FSLINEELEMENT element = arrayLineElement[elIndex];

                    // 'dcp' needs to be within line range. If position points to dcpLim,
                    // it means that the next line starts from such position, hence go to the next line. 
                    if (((element.dcpFirst <= dcp) && (element.dcpLim > dcp))
                        || ((element.dcpLim == dcp) && (elIndex == arrayLineElement.Length - 1) && (index == arrayLineDesc.Length - 1))) 
                    { 
                        CharacterHit charHit = new CharacterHit();
                        if (dcp >= element.dcpLim - 1 && elIndex == arrayLineElement.Length - 1 && index == arrayLineDesc.Length - 1) 
                        {
                            // Special case: at the end of the last line there is a special character that
                            // does not belong to the line.  Return true for this case
                            return true; 
                        }
 
                        if (position.LogicalDirection == LogicalDirection.Backward) 
                        {
                            // Beginning of element. 
                            if (dcp == element.dcpFirst)
                            {
                                if (elIndex > 0)
                                { 
                                    // Beginning of element, but not of line. Create char hit at last dcp of previous element, trailing edge.
                                    --elIndex; 
                                    element = arrayLineElement[elIndex]; 
                                    charHit = new CharacterHit(dcp - 1, 1);
                                } 
                                else
                                {
                                    // Beginning of line
                                    if (index == 0) 
                                    {
                                        // Backward context at start position of first line is not considered a unit boundary 
                                        return false; 
                                    }
                                    else 
                                    {

                                        // Go to previous line
                                        --index; 
                                        lineDesc = arrayLineDesc[index];
                                        if (lineDesc.cElements == 0) 
                                        { 
                                            return false;
                                        } 
                                        else
                                        {
                                            // Get list of line elements.
                                            PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); 
                                            element = arrayLineElement[arrayLineElement.Length - 1];
                                            charHit = new CharacterHit(dcp - 1, 1); 
                                        } 
                                    }
                                } 
                            }
                            else
                            {
                                // Get trailing edge of previous dcp 
                                Invariant.Assert(dcp > 0);
                                charHit = new CharacterHit(dcp - 1, 1); 
                            } 
                        }
                        else if (position.LogicalDirection == LogicalDirection.Forward) 
                        {
                            // Create character hit at leading edge
                            charHit = new CharacterHit(dcp, 0);
                        } 

                        // Create and format line 
                        Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); 
                        Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(element.fClearOnLeft), PTS.ToBoolean(element.fClearOnRight), TextParagraph.TextRunCache);
 
                        if(IsOptimalParagraph)
                        {
                            ctx.LineFormatLengthTarget = element.dcpLim - element.dcpFirst;
                        } 

                        TextParagraph.FormatLineCore(line, element.pfsbreakreclineclient, ctx, element.dcpFirst, element.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), element.dcpFirst); 
 
                        // Assert that number of characters in Text line is the same as our expected length
                        Invariant.Assert(line.SafeLength == element.dcpLim - element.dcpFirst, "Line length is out of [....]"); 
                        isAtCaretUnitBoundary = line.IsAtCaretCharacterHit(charHit);

                        // Dispose the line
                        line.Dispose(); 
                        return isAtCaretUnitBoundary;
                    } 
                } 
            }
            return isAtCaretUnitBoundary; 
        }
Esempio n. 52
0
 /// <summary>
 /// Client to get the previous character hit after backspacing
 /// </summary>
 /// <param name="characterHit">the current character hit</param>
 /// <returns>the character hit after backspacing</returns>
 public override CharacterHit GetBackspaceCaretCharacterHit(
     CharacterHit characterHit
     )
 {
     return GetPreviousCaretCharacterHitByBehavior(characterHit, CaretDirection.Backspace);
 }
Esempio n. 53
0
        private ITextPointer BackspaceCaretUnitPositionFromDcpCompositeLines(
            int dcp,
            ITextPointer position,
            ref PTS.FSTEXTDETAILSFULL textDetails) 
        {
            ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap); 
 
            // Get list of lines
            PTS.FSLINEDESCRIPTIONCOMPOSITE[] arrayLineDesc; 
            PtsHelper.LineListCompositeFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc);

            // Declare backspace position and set it to initial position
            ITextPointer backspaceCaretPosition = position; 

            // First iterate through lines 
            for (int index = 0; index < arrayLineDesc.Length; index++) 
            {
                PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc = arrayLineDesc[index]; 
                if (lineDesc.cElements == 0) { continue; }

                // Get list of line elements.
                PTS.FSLINEELEMENT[] arrayLineElement; 
                PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement);
 
                for (int elIndex = 0; elIndex < arrayLineElement.Length; elIndex++) 
                {
                    PTS.FSLINEELEMENT element = arrayLineElement[elIndex]; 

                    // 'dcp' needs to be within line range. If position points to dcpLim,
                    // it means that the next line starts from such position, hence go to the next line.
                    if (((element.dcpFirst <= dcp) && (element.dcpLim > dcp)) 
                        || ((element.dcpLim == dcp) && (elIndex == arrayLineElement.Length - 1) && (index == arrayLineDesc.Length - 1)))
                    { 
                        if (dcp == element.dcpFirst) 
                        {
                            // Beginning of element. 
                            if (dcp == 0)
                            {
                                // Assert that this is first elment on first line
                                Debug.Assert(index == 0); 
                                Debug.Assert(elIndex == 0);
                                return position; 
                            } 
                            else
                            { 
                                if (elIndex > 0)
                                {
                                    // Beginning of element, but not of line
                                    --elIndex; 
                                    element = arrayLineElement[elIndex];
                                } 
                                else 
                                {
                                    // There must be at least one line above this 
                                    Debug.Assert(index > 0);

                                    // Go to previous line
                                    --index; 
                                    lineDesc = arrayLineDesc[index];
                                    if (lineDesc.cElements == 0) 
                                    { 
                                        // Stay in same position
                                        return position; 
                                    }
                                    else
                                    {
                                        // Get list of line elements. 
                                        PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement);
                                        element = arrayLineElement[arrayLineElement.Length - 1]; 
                                    } 
                                }
                            } 
                        }

                        // Create and format line
                        Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition); 
                        Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(element.fClearOnLeft), PTS.ToBoolean(element.fClearOnRight), TextParagraph.TextRunCache);
 
                        if(IsOptimalParagraph) 
                        {
                            ctx.LineFormatLengthTarget = element.dcpLim - element.dcpFirst; 
                        }

                        TextParagraph.FormatLineCore(line, element.pfsbreakreclineclient, ctx, element.dcpFirst, element.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), element.dcpFirst);
 
                        // Assert that number of characters in Text line is the same as our expected length
                        Invariant.Assert(line.SafeLength == element.dcpLim - element.dcpFirst, "Line length is out of [....]"); 
 
                        // Create CharacterHit from dcp, and get backspace
                        CharacterHit charHit = new CharacterHit(dcp, 0); 
                        CharacterHit backspaceCharacterHit = line.GetBackspaceCaretCharacterHit(charHit);
                        LogicalDirection logicalDirection;
                        if (backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength == element.dcpFirst)
                        { 
                            // Going forward brought us to the start of a line, context must be backward for previous line
                            if (index == 0) 
                            { 
                                // First line, so we will stay forward
                                logicalDirection = LogicalDirection.Forward; 
                            }
                            else
                            {
                                logicalDirection = LogicalDirection.Backward; 
                            }
                        } 
                        else 
                        {
                            logicalDirection = (backspaceCharacterHit.TrailingLength > 0) ? LogicalDirection.Backward : LogicalDirection.Forward; 
                        }
                        backspaceCaretPosition = GetTextPosition(backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength, logicalDirection);

                        // Dispose the line 
                        line.Dispose();
                        return backspaceCaretPosition; 
                    } 
                }
            } 
            return backspaceCaretPosition;
        }
Esempio n. 54
0
            /// <summary>
            /// Calculate previous caret character hit based on the caret action
            /// </summary>
            private CharacterHit GetPreviousCaretCharacterHitByBehavior(
                CharacterHit    characterHit,
                CaretDirection  direction
                )
            {
                Debug.Assert(direction == CaretDirection.Backward || direction == CaretDirection.Backspace);

                if ((_statusFlags & StatusFlags.IsDisposed) != 0)
                {
                    throw new ObjectDisposedException(SR.Get(SRID.TextLineHasBeenDisposed));
                }

                TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _metrics._cchLength);

                if (_ploline.Value == IntPtr.Zero)
                {
                    return characterHit;
                }

                if (    characterHit.FirstCharacterIndex == _cpFirst
                    &&  characterHit.TrailingLength == 0)
                {
                    // We are already at the beginning of the line
                    return characterHit;
                }

                int caretStopIndex;
                int offsetToNextCaretStopIndex;

                bool found = GetNextOrPreviousCaretStop(
                    characterHit.FirstCharacterIndex,
                    direction,
                    out caretStopIndex,
                    out offsetToNextCaretStopIndex
                    );

                if (!found)
                {
                    // The current index is before the 1st caret stop.
                    return characterHit;
                }

                if (    offsetToNextCaretStopIndex != 0
                    &&  characterHit.TrailingLength == 0
                    &&  caretStopIndex != _cpFirst
                    &&  caretStopIndex >= characterHit.FirstCharacterIndex
                    )
                {
                    // If the current character hit is at the leading edge and it is not at the first caret stop,
                    // move it to leading edge of the previous caret stop. At this point, the current character stop
                    // fully encloses the input index and the input is at the leading edge.
                    found = GetNextOrPreviousCaretStop(
                        caretStopIndex - 1, // position at the character immediately preceding the current caret stop
                        direction,
                        out caretStopIndex,
                        out offsetToNextCaretStopIndex
                        );

                    if (!found)
                    {
                        // The current index is before the 1st caret stop.
                        return characterHit;
                    }
                }

                // The current chracter hit is either beyond the last caret stop,
                // or it's at the trailing edge of the current caret stop,
                // or the current index is at the leading edge of the first caret stop.
                //
                // In such cases, move to the leading edge of the closest caret stop.
                return new CharacterHit(caretStopIndex, 0);
            }
Esempio n. 55
0
            /// <summary>
            /// Get character hit from specified hittest distance relative to line start
            /// </summary>
            private CharacterHit CharacterHitFromDistance(int hitTestDistance)
            {
                // assuming the first cp of the line
                CharacterHit characterHit = new CharacterHit(_cpFirst, 0);

                if(_ploline.Value == IntPtr.Zero)
                {
                    // Returning the first cp for the empty line
                    return characterHit;
                }

                if (    HasCollapsed
                    &&  _collapsedRange != null
                    &&  _collapsingSymbol != null
                    )
                {
                    int lineEndDistance = _metrics._textStart + _metrics._textWidthAtTrailing;
                    int rangeWidth = TextFormatterImp.RealToIdeal(_collapsingSymbol.Width);

                    if (hitTestDistance >= lineEndDistance - rangeWidth)
                    {
                        if (lineEndDistance - hitTestDistance < rangeWidth / 2)
                        {
                            // The hit-test distance is within the trailing edge of the collapsed range,
                            // return the character hit at the beginning of the range.
                            return new CharacterHit(_collapsedRange.TextSourceCharacterIndex, _collapsedRange.Length);
                        }

                        // The hit-test distance is within the leading edge of the collapsed range,
                        // return the character hit at the beginning of the range.
                        return new CharacterHit(_collapsedRange.TextSourceCharacterIndex, 0);
                    }
                }

                LsTextCell lsTextCell;
                LsQSubInfo[] sublineInfo = new LsQSubInfo[_depthQueryMax];
                int actualSublineCount;

                QueryLinePointPcp(
                    new Point(hitTestDistance, 0),
                    sublineInfo,
                    out actualSublineCount,
                    out lsTextCell
                    );

                if (actualSublineCount > 0 && lsTextCell.dupCell > 0)
                {
                    // the last subline contains the run that owns the querying lscp
                    LSRun lsrun = GetRun((Plsrun)sublineInfo[actualSublineCount - 1].plsrun);

                    // Assuming caret stops at every codepoint.
                    //
                    // LsTextCell.lscpEndCell is the index to the last lscp still in the cell.
                    // The number of LSCP within the text cell is equal to the number of CP.
                    int caretStopCount = lsTextCell.lscpEndCell + 1 - lsTextCell.lscpStartCell;

                    int codepointsToNextCaretStop = lsrun.IsHitTestable ? 1 : lsrun.Length;

                    if (    lsrun.IsHitTestable
                        &&  (   lsrun.HasExtendedCharacter
                            ||  lsrun.NeedsCaretInfo)
                        )
                    {
                        // A hit-testable run with caret stops at every cluster boundaries,
                        // e.g. run with combining mark, with extended characters or complex scripts such as Thai
                        codepointsToNextCaretStop = caretStopCount;
                        caretStopCount = 1;
                    }

                    // All the UV coordinate in subline are in main direction. If the last subline where
                    // we hittest runs in the opposite direction, the logical advance from text cell start cp
                    // will be negative value.
                    int direction = (sublineInfo[actualSublineCount - 1].lstflowSubLine == sublineInfo[0].lstflowSubLine) ? 1 : -1;
                    hitTestDistance = (hitTestDistance - lsTextCell.pointUvStartCell.x) * direction;

                    Invariant.Assert(caretStopCount > 0);
                    int wholeAdvance = lsTextCell.dupCell / caretStopCount;
                    int remainingAdvance = lsTextCell.dupCell % caretStopCount;

                    for (int i = 0; i < caretStopCount; i++)
                    {
                        int caretAdvance = wholeAdvance;
                        if (remainingAdvance > 0)
                        {
                            caretAdvance++;
                            remainingAdvance--;
                        }

                        if (hitTestDistance <= caretAdvance)
                        {
                            if (hitTestDistance > caretAdvance / 2)
                            {
                                // hittest at the trailing edge of the current caret stop
                                return new CharacterHit(GetExternalCp(lsTextCell.lscpStartCell) + i, codepointsToNextCaretStop);
                            }

                            // hittest at the leading edge of the current caret stop
                            return new CharacterHit(GetExternalCp(lsTextCell.lscpStartCell) + i, 0);
                        }

                        hitTestDistance -= caretAdvance;
                    }

                    // hittest beyond the last caret stop, return the trailing edge of the last caret stop
                    return new CharacterHit(GetExternalCp(lsTextCell.lscpStartCell) + caretStopCount - 1, codepointsToNextCaretStop);
                }

                return characterHit;
            }
 /// <summary>
 /// Client to get the previous character hit after backspacing
 /// </summary>
 /// <param name="characterHit">the current character hit</param>
 /// <returns>the character hit after backspacing</returns>
 public override CharacterHit GetBackspaceCaretCharacterHit(
     CharacterHit    characterHit
     )
 {
     // same operation as move-to-previous
     return GetPreviousCaretCharacterHit(characterHit);
 }
 /// <summary>
 /// Client to get the distance from the beginning of the line from the specified
 /// character hit.
 /// </summary>
 /// <param name="characterHit">character hit of the character to query the distance.</param>
 /// <returns>distance in text flow direction from the beginning of the line.</returns>
 public override double GetDistanceFromCharacterHit(
     CharacterHit    characterHit
     )
 {
     TextFormatterImp.VerifyCaretCharacterHit(characterHit, _cpFirst, _cpLength);
     return DistanceFromCp(characterHit.FirstCharacterIndex + (characterHit.TrailingLength != 0 ? 1 : 0));
 }
Esempio n. 58
0
 //-------------------------------------------------------------------
 // Retrieve text position for next caret position
 //
 // index: CharacterHit for current position
 //
 // Returns: Text position index.
 //-------------------------------------------------------------------
 internal CharacterHit GetNextCaretCharacterHit(CharacterHit index)
 {
     return _line.GetNextCaretCharacterHit(index);
 }
Esempio n. 59
0
 /// <summary> 
 /// Calculates the offset for the corresponding TextPointer from a CharacterHit
 /// </summary>
 /// <remarks>
 /// This is necessary to ensure that we don't try to create a position at an offset greater than TextContainer's symbol count. 
 /// This may happen when a line is collapsed with ellipsis and we hit-test at the trailing edge of ellipsis, the trailing length
 /// returned for the CharacterHit is the length of all collapsed characters, including the synthetic EOP. If we try to 
 /// create a position at this trailing length we can exceed TextContainer's symbol count. 
 /// </remarks>
 private int CalcPositionOffset(CharacterHit charHit) 
 {
     int offset = charHit.FirstCharacterIndex + charHit.TrailingLength;
     if (this.EndOfParagraph)
     { 
         offset = Math.Min(_dcp + this.Length, offset);
     } 
     return offset; 
 }
Esempio n. 60
0
        /// <summary>
        /// <see cref="ITextView.GetBackspaceCaretUnitPosition"/>
        /// </summary>
        ITextPointer ITextView.GetBackspaceCaretUnitPosition(ITextPointer position)
        {
            Invariant.Assert(this.IsLayoutValid);
            Invariant.Assert(Contains(position));

            // Special case document start.
            if (position.Offset == 0)
            {
                return position.GetFrozenPointer(LogicalDirection.Forward);
            }

            int lineIndex = GetLineIndexFromPosition(position, LogicalDirection.Backward);

            CharacterHit sourceCharacterHit = new CharacterHit(position.Offset, 0);
            CharacterHit backspaceCharacterHit;

            using (TextBoxLine line = GetFormattedLine(lineIndex))
            {
                backspaceCharacterHit = line.GetBackspaceCaretCharacterHit(sourceCharacterHit);
            }

            LogicalDirection logicalDirection;
            if (backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength == _lineMetrics[lineIndex].Offset)
            {
                // Going backward brought us to the start of a line, context must be backward for previous line
                if (lineIndex == 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 backspaceUnitPosition = _host.TextContainer.CreatePointerAtOffset(backspaceCharacterHit.FirstCharacterIndex + backspaceCharacterHit.TrailingLength, logicalDirection);
            backspaceUnitPosition.Freeze();
            return backspaceUnitPosition;
        }