Skip to content

Commit 6810a24

Browse files
Gilles DebunneAndroid (Google) Code Review
authored andcommitted
Merge "New SpanSet class extracted from TextLine."
2 parents b001475 + 4ffb879 commit 6810a24

File tree

2 files changed

+111
-74
lines changed

2 files changed

+111
-74
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (C) 2012 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.text;
18+
19+
import java.lang.reflect.Array;
20+
21+
/**
22+
* A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then
23+
* provides faster access to {@link Spanned#nextSpanTransition(int, int, Class)}.
24+
*
25+
* Fields are left public for a convenient direct access.
26+
*
27+
* Note that empty spans are ignored by this class.
28+
* @hide
29+
*/
30+
public class SpanSet<E> {
31+
private final Class<? extends E> classType;
32+
33+
int numberOfSpans;
34+
E[] spans;
35+
int[] spanStarts;
36+
int[] spanEnds;
37+
int[] spanFlags;
38+
39+
SpanSet(Class<? extends E> type) {
40+
classType = type;
41+
numberOfSpans = 0;
42+
}
43+
44+
@SuppressWarnings("unchecked")
45+
public void init(Spanned spanned, int start, int limit) {
46+
final E[] allSpans = spanned.getSpans(start, limit, classType);
47+
final int length = allSpans.length;
48+
49+
if (length > 0 && (spans == null || spans.length < length)) {
50+
// These arrays may end up being too large because of the discarded empty spans
51+
spans = (E[]) Array.newInstance(classType, length);
52+
spanStarts = new int[length];
53+
spanEnds = new int[length];
54+
spanFlags = new int[length];
55+
}
56+
57+
numberOfSpans = 0;
58+
for (int i = 0; i < length; i++) {
59+
final E span = allSpans[i];
60+
61+
final int spanStart = spanned.getSpanStart(span);
62+
final int spanEnd = spanned.getSpanEnd(span);
63+
if (spanStart == spanEnd) continue;
64+
65+
final int spanFlag = spanned.getSpanFlags(span);
66+
67+
spans[numberOfSpans] = span;
68+
spanStarts[numberOfSpans] = spanStart;
69+
spanEnds[numberOfSpans] = spanEnd;
70+
spanFlags[numberOfSpans] = spanFlag;
71+
72+
numberOfSpans++;
73+
}
74+
}
75+
76+
/**
77+
* Returns true if there are spans intersecting the given interval.
78+
* @param end must be strictly greater than start
79+
*/
80+
public boolean hasSpansIntersecting(int start, int end) {
81+
for (int i = 0; i < numberOfSpans; i++) {
82+
// equal test is valid since both intervals are not empty by construction
83+
if (spanStarts[i] >= end || spanEnds[i] <= start) continue;
84+
return true;
85+
}
86+
return false;
87+
}
88+
89+
/**
90+
* Similar to {@link Spanned#nextSpanTransition(int, int, Class)}
91+
*/
92+
int getNextTransition(int start, int limit) {
93+
for (int i = 0; i < numberOfSpans; i++) {
94+
final int spanStart = spanStarts[i];
95+
final int spanEnd = spanEnds[i];
96+
if (spanStart > start && spanStart < limit) limit = spanStart;
97+
if (spanEnd > start && spanEnd < limit) limit = spanEnd;
98+
}
99+
return limit;
100+
}
101+
102+
/**
103+
* Removes all internal references to the spans to avoid memory leaks.
104+
*/
105+
public void recycle() {
106+
// The spans array is guaranteed to be not null when numberOfSpans is > 0
107+
for (int i = 0; i < numberOfSpans; i++) {
108+
spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled
109+
}
110+
}
111+
}

core/java/android/text/TextLine.java

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
import com.android.internal.util.ArrayUtils;
3232

33-
import java.lang.reflect.Array;
34-
3533
/**
3634
* Represents a line of styled text, for measuring in visual order and
3735
* for rendering.
@@ -860,78 +858,6 @@ private float handleReplacement(ReplacementSpan replacement, TextPaint wp,
860858
return runIsRtl ? -ret : ret;
861859
}
862860

863-
private static class SpanSet<E> {
864-
int numberOfSpans;
865-
E[] spans;
866-
int[] spanStarts;
867-
int[] spanEnds;
868-
int[] spanFlags;
869-
final Class<? extends E> classType;
870-
871-
SpanSet(Class<? extends E> type) {
872-
classType = type;
873-
numberOfSpans = 0;
874-
}
875-
876-
@SuppressWarnings("unchecked")
877-
public void init(Spanned spanned, int start, int limit) {
878-
final E[] allSpans = spanned.getSpans(start, limit, classType);
879-
final int length = allSpans.length;
880-
881-
if (length > 0 && (spans == null || spans.length < length)) {
882-
// These arrays may end up being too large because of empty spans
883-
spans = (E[]) Array.newInstance(classType, length);
884-
spanStarts = new int[length];
885-
spanEnds = new int[length];
886-
spanFlags = new int[length];
887-
}
888-
889-
numberOfSpans = 0;
890-
for (int i = 0; i < length; i++) {
891-
final E span = allSpans[i];
892-
893-
final int spanStart = spanned.getSpanStart(span);
894-
final int spanEnd = spanned.getSpanEnd(span);
895-
if (spanStart == spanEnd) continue;
896-
897-
final int spanFlag = spanned.getSpanFlags(span);
898-
899-
spans[numberOfSpans] = span;
900-
spanStarts[numberOfSpans] = spanStart;
901-
spanEnds[numberOfSpans] = spanEnd;
902-
spanFlags[numberOfSpans] = spanFlag;
903-
904-
numberOfSpans++;
905-
}
906-
}
907-
908-
public boolean hasSpansIntersecting(int start, int end) {
909-
for (int i = 0; i < numberOfSpans; i++) {
910-
// equal test is valid since both intervals are not empty by construction
911-
if (spanStarts[i] >= end || spanEnds[i] <= start) continue;
912-
return true;
913-
}
914-
return false;
915-
}
916-
917-
int getNextTransition(int start, int limit) {
918-
for (int i = 0; i < numberOfSpans; i++) {
919-
final int spanStart = spanStarts[i];
920-
final int spanEnd = spanEnds[i];
921-
if (spanStart > start && spanStart < limit) limit = spanStart;
922-
if (spanEnd > start && spanEnd < limit) limit = spanEnd;
923-
}
924-
return limit;
925-
}
926-
927-
public void recycle() {
928-
// The spans array is guaranteed to be not null when numberOfSpans is > 0
929-
for (int i = 0; i < numberOfSpans; i++) {
930-
spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled
931-
}
932-
}
933-
}
934-
935861
/**
936862
* Utility function for handling a unidirectional run. The run must not
937863
* contain tabs or emoji but can contain styles.

0 commit comments

Comments
 (0)