diff options
author | 2013-06-25 17:28:39 +0900 | |
---|---|---|
committer | 2013-07-01 15:41:13 +0900 | |
commit | 675bcf191c3cdb5ba5af70efb9357ffceb389c2e (patch) | |
tree | fe00a1638a35ea52e4ce15573a3d924e3c7ef7b5 /java/src/com/android/inputmethod/latin/utils/TextRange.java | |
parent | 8142a7b637326e8fe8736de94246b1fffb4f2886 (diff) | |
download | latinime-675bcf191c3cdb5ba5af70efb9357ffceb389c2e.tar.gz latinime-675bcf191c3cdb5ba5af70efb9357ffceb389c2e.tar.xz latinime-675bcf191c3cdb5ba5af70efb9357ffceb389c2e.zip |
Move Range out of RichInputConnection and rename it.
Range has grown a bit too big to stay an internal class.
Change-Id: Ic3fbc48a5d10776eedd7559c4d696e5926b88288
Diffstat (limited to 'java/src/com/android/inputmethod/latin/utils/TextRange.java')
-rw-r--r-- | java/src/com/android/inputmethod/latin/utils/TextRange.java | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/java/src/com/android/inputmethod/latin/utils/TextRange.java b/java/src/com/android/inputmethod/latin/utils/TextRange.java new file mode 100644 index 000000000..5793e4170 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/utils/TextRange.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.latin.utils; + +import android.text.Spanned; +import android.text.style.SuggestionSpan; + +import java.util.Arrays; + +/** + * Represents a range of text, relative to the current cursor position. + */ +public final class TextRange { + private final CharSequence mTextAtCursor; + private final int mWordAtCursorStartIndex; + private final int mWordAtCursorEndIndex; + private final int mCursorIndex; + + public final CharSequence mWord; + + public int getNumberOfCharsInWordBeforeCursor() { + return mCursorIndex - mWordAtCursorStartIndex; + } + + public int getNumberOfCharsInWordAfterCursor() { + return mWordAtCursorEndIndex - mCursorIndex; + } + + /** + * Gets the suggestion spans that are put squarely on the word, with the exact start + * and end of the span matching the boundaries of the word. + * @return the list of spans. + */ + public SuggestionSpan[] getSuggestionSpansAtWord() { + if (!(mTextAtCursor instanceof Spanned && mWord instanceof Spanned)) { + return new SuggestionSpan[0]; + } + final Spanned text = (Spanned)mTextAtCursor; + // Note: it's fine to pass indices negative or greater than the length of the string + // to the #getSpans() method. The reason we need to get from -1 to +1 is that, the + // spans were cut at the cursor position, and #getSpans(start, end) does not return + // spans that end at `start' or begin at `end'. Consider the following case: + // this| is (The | symbolizes the cursor position + // ---- --- + // In this case, the cursor is in position 4, so the 0~7 span has been split into + // a 0~4 part and a 4~7 part. + // If we called #getSpans(0, 4) in this case, we would only get the part from 0 to 4 + // of the span, and not the part from 4 to 7, so we would not realize the span actually + // extends from 0 to 7. But if we call #getSpans(-1, 5) we'll get both the 0~4 and + // the 4~7 spans and we can merge them accordingly. + // Any span starting more than 1 char away from the word boundaries in any direction + // does not touch the word, so we don't need to consider it. That's why requesting + // -1 ~ +1 is enough. + // Of course this is only relevant if the cursor is at one end of the word. If it's + // in the middle, the -1 and +1 are not necessary, but they are harmless. + final SuggestionSpan[] spans = text.getSpans(mWordAtCursorStartIndex - 1, + mWordAtCursorEndIndex + 1, SuggestionSpan.class); + int readIndex = 0; + int writeIndex = 0; + for (; readIndex < spans.length; ++readIndex) { + final SuggestionSpan span = spans[readIndex]; + // The span may be null, as we null them when we find duplicates. Cf a few lines + // down. + if (null == span) continue; + // Tentative span start and end. This may be modified later if we realize the + // same span is also applied to other parts of the string. + int spanStart = text.getSpanStart(span); + int spanEnd = text.getSpanEnd(span); + for (int i = readIndex + 1; i < spans.length; ++i) { + if (span.equals(spans[i])) { + // We found the same span somewhere else. Read the new extent of this + // span, and adjust our values accordingly. + spanStart = Math.min(spanStart, text.getSpanStart(spans[i])); + spanEnd = Math.max(spanEnd, text.getSpanEnd(spans[i])); + // ...and mark the span as processed. + spans[i] = null; + } + } + if (spanStart == mWordAtCursorStartIndex && spanEnd == mWordAtCursorEndIndex) { + // If the span does not start and stop here, we ignore it. It probably extends + // past the start or end of the word, as happens in missing space correction + // or EasyEditSpans put by voice input. + spans[writeIndex++] = spans[readIndex]; + } + } + return writeIndex == readIndex ? spans : Arrays.copyOfRange(spans, 0, writeIndex); + } + + public TextRange(final CharSequence textAtCursor, final int wordAtCursorStartIndex, + final int wordAtCursorEndIndex, final int cursorIndex) { + if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex + || cursorIndex > wordAtCursorEndIndex + || wordAtCursorEndIndex > textAtCursor.length()) { + throw new IndexOutOfBoundsException(); + } + mTextAtCursor = textAtCursor; + mWordAtCursorStartIndex = wordAtCursorStartIndex; + mWordAtCursorEndIndex = wordAtCursorEndIndex; + mCursorIndex = cursorIndex; + mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex); + } +}
\ No newline at end of file |