Пример #1
0
            private void QueryLineCpPpoint(
                int                 lscpQuery,
                LsQSubInfo[]        subLineInfo,
                out int             actualDepthQuery,
                out LsTextCell      lsTextCell
                )
            {
                Debug.Assert(_ploline.Value != IntPtr.Zero);

                LsErr lserr = LsErr.None;

                lsTextCell = new LsTextCell();

                // Never hit LS with any LSCP beyond its last, the result is unreliable and varies between drops.
                int lscpValidQuery = (lscpQuery < _metrics._lscpLim ? lscpQuery : _metrics._lscpLim - 1);

                unsafe
                {
                    fixed(LsQSubInfo* plsqsubl = subLineInfo)
                    {
                        lserr = UnsafeNativeMethods.LoQueryLineCpPpoint(
                            _ploline.Value,
                            lscpValidQuery,
                            subLineInfo.Length,
                            (System.IntPtr)plsqsubl,
                            out actualDepthQuery,
                            out lsTextCell
                            );
                    }
                }

                if(lserr != LsErr.None)
                {
                    TextFormatterContext.ThrowExceptionFromLsError(SR.Get(SRID.QueryLineFailure, lserr), lserr);
                }

                if (lsTextCell.lscpEndCell < lsTextCell.lscpStartCell)
                {
                    // When hit-testing is done on a generated hyphen of a hyphenated word, LS can only tell
                    // the start LSCP and not the end LSCP. Argurably this is LS bug. In such situation they
                    // should assume the end LSCP being the last LSCP of the line.
                    //
                    // However our code assumes that LS must tell both and the text cell must have size greater
                    // than one codepoint. We count on that to reliably advance the caret position.
                    //
                    // The LSPTS bug#1005 has been filed and while we are still debating, we need to unblock
                    // ourselves. What we can do is to assume that the next caret stop in this case is always
                    // the next codepoint.
                    lsTextCell.lscpEndCell = lsTextCell.lscpStartCell;
                }
            }
Пример #2
0
            /// <summary>
            /// Given a specified current character index, calculate the character index
            /// to the closest caret stop before or at the current index; and the number
            /// of codepoints from the closest caret stop to the next caret stop.
            /// </summary>
            private bool GetNextOrPreviousCaretStop(
                int                      currentIndex,
                CaretDirection           direction,
                out int                  caretStopIndex,
                out int                  offsetToNextCaretStopIndex
                )
            {
                caretStopIndex = currentIndex;
                offsetToNextCaretStopIndex = 0;

                if (    HasCollapsed
                    &&  _collapsedRange != null
                    &&  currentIndex >= _collapsedRange.TextSourceCharacterIndex
                    )
                {
                    // current index is within collapsed range,
                    caretStopIndex = _collapsedRange.TextSourceCharacterIndex;

                    if (currentIndex < _collapsedRange.TextSourceCharacterIndex + _collapsedRange.Length)
                        offsetToNextCaretStopIndex = _collapsedRange.Length;

                    return true;
                }

                LsQSubInfo[] sublineInfo = new LsQSubInfo[_depthQueryMax];
                LsTextCell lsTextCell = new LsTextCell();

                int lscpVisisble = GetInternalCp(currentIndex);
                bool found = FindNextOrPreviousVisibleCp(lscpVisisble, direction, out lscpVisisble);

                if (!found)
                {
                    return false; // there is no caret stop anymore in the given direction.
                }

                int actualSublineCount;

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

                // Locate the current caret stop
                caretStopIndex = GetExternalCp(lsTextCell.lscpStartCell);

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

                    if (lsrun.IsHitTestable)
                    {
                        if (    lsrun.HasExtendedCharacter
                            ||  (direction != CaretDirection.Backspace && lsrun.NeedsCaretInfo)
                            )
                        {
                            // 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.
                            offsetToNextCaretStopIndex = lsTextCell.lscpEndCell + 1 - lsTextCell.lscpStartCell;
                        }
                        else
                        {
                            // caret stops before every codepoint
                            caretStopIndex = GetExternalCp(lscpVisisble);
                            offsetToNextCaretStopIndex = 1;
                        }
                    }
                    else
                    {
                        // run is not hit-testable, caret navigation is not allowed in the run,
                        // the next caret stop is therefore either at the end of the run or the end of the line whichever reached first.
                        offsetToNextCaretStopIndex = Math.Min(Length, lsrun.Length - caretStopIndex + lsrun.OffsetToFirstCp + _cpFirst);
                    }
                }

                return true;
            }
Пример #3
0
 internal static extern LsErr LoQueryLinePointPcp(
     IntPtr                  ploline,
     ref LSPOINT             ptQuery,        //  use POINT as POINTUV
     int                     depthQueryMax,
     IntPtr                  pSubLineInfo,   // passing raw pinned pointer for out array
     out int                 actualDepthQuery,
     out LsTextCell          lsTextCell
     );
Пример #4
0
            /// <summary>
            /// Get distance from the start of text cell to the specified lscp
            /// </summary>
            private int GetDistanceInsideTextCell(
                int                 lscpCurrent,
                bool                isTrailing,
                LsQSubInfo[]        sublineInfo,
                int                 actualSublineCount,
                ref LsTextCell      lsTextCell
                )
            {
                int distanceInCell = 0;

                // 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;

                // 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.
                //
                // Assuming caret stops at every codepoint in the run.
                int caretStopCount = lsTextCell.lscpEndCell + 1 - lsTextCell.lscpStartCell;
                int codepointsFromStartCell = lscpCurrent - lsTextCell.lscpStartCell;

                // the last subline contains the run that owns the querying lscp
                LSRun lsrun = GetRun((Plsrun)sublineInfo[actualSublineCount - 1].plsrun);

                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
                    caretStopCount = 1;
                }

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

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

                    if (codepointsFromStartCell < i)
                    {
                        if (isTrailing)
                        {
                            // hit-test at the trailing edge of the current caret stop, include the current caret advance
                            return (distanceInCell + caretAdvance) * direction;
                        }

                        // hit-test at the leading edge of the current caret stop, return the accumulated distance
                        return distanceInCell * direction;
                    }

                    distanceInCell += caretAdvance;
                }

                // hit-test beyond the last caret stop, return the total accumated distance up to the trailing edge of the last caret stop.
                return distanceInCell * direction;
            }
Пример #5
0
 internal static extern LsErr LoQueryLineCpPpoint(
     IntPtr                  ploline,
     int                     lscpQuery,
     int                     depthQueryMax,
     IntPtr                  pSubLineInfo,   // passing raw pinned pointer for out array
     out int                 actualDepthQuery,
     out LsTextCell          lsTextCell
     );