• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.annotation.UnsupportedAppUsage;
20 import java.lang.reflect.Array;
21 import java.util.Arrays;
22 
23 /**
24  * A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then
25  * provides faster access to {@link Spanned#nextSpanTransition(int, int, Class)}.
26  *
27  * Fields are left public for a convenient direct access.
28  *
29  * Note that empty spans are ignored by this class.
30  * @hide
31  */
32 public class SpanSet<E> {
33     private final Class<? extends E> classType;
34 
35     int numberOfSpans;
36     @UnsupportedAppUsage
37     E[] spans;
38     int[] spanStarts;
39     int[] spanEnds;
40     int[] spanFlags;
41 
SpanSet(Class<? extends E> type)42     SpanSet(Class<? extends E> type) {
43         classType = type;
44         numberOfSpans = 0;
45     }
46 
47     @SuppressWarnings("unchecked")
init(Spanned spanned, int start, int limit)48     public void init(Spanned spanned, int start, int limit) {
49         final E[] allSpans = spanned.getSpans(start, limit, classType);
50         final int length = allSpans.length;
51 
52         if (length > 0 && (spans == null || spans.length < length)) {
53             // These arrays may end up being too large because of the discarded empty spans
54             spans = (E[]) Array.newInstance(classType, length);
55             spanStarts = new int[length];
56             spanEnds = new int[length];
57             spanFlags = new int[length];
58         }
59 
60         int prevNumberOfSpans = numberOfSpans;
61         numberOfSpans = 0;
62         for (int i = 0; i < length; i++) {
63             final E span = allSpans[i];
64 
65             final int spanStart = spanned.getSpanStart(span);
66             final int spanEnd = spanned.getSpanEnd(span);
67             if (spanStart == spanEnd) continue;
68 
69             final int spanFlag = spanned.getSpanFlags(span);
70 
71             spans[numberOfSpans] = span;
72             spanStarts[numberOfSpans] = spanStart;
73             spanEnds[numberOfSpans] = spanEnd;
74             spanFlags[numberOfSpans] = spanFlag;
75 
76             numberOfSpans++;
77         }
78 
79         // cleanup extra spans left over from previous init() call
80         if (numberOfSpans < prevNumberOfSpans) {
81             // prevNumberofSpans was > 0, therefore spans != null
82             Arrays.fill(spans, numberOfSpans, prevNumberOfSpans, null);
83         }
84     }
85 
86     /**
87      * Returns true if there are spans intersecting the given interval.
88      * @param end must be strictly greater than start
89      */
hasSpansIntersecting(int start, int end)90     public boolean hasSpansIntersecting(int start, int end) {
91         for (int i = 0; i < numberOfSpans; i++) {
92             // equal test is valid since both intervals are not empty by construction
93             if (spanStarts[i] >= end || spanEnds[i] <= start) continue;
94             return true;
95         }
96         return false;
97     }
98 
99     /**
100      * Similar to {@link Spanned#nextSpanTransition(int, int, Class)}
101      */
getNextTransition(int start, int limit)102     int getNextTransition(int start, int limit) {
103         for (int i = 0; i < numberOfSpans; i++) {
104             final int spanStart = spanStarts[i];
105             final int spanEnd = spanEnds[i];
106             if (spanStart > start && spanStart < limit) limit = spanStart;
107             if (spanEnd > start && spanEnd < limit) limit = spanEnd;
108         }
109         return limit;
110     }
111 
112     /**
113      * Removes all internal references to the spans to avoid memory leaks.
114      */
recycle()115     public void recycle() {
116         if (spans != null) {
117             Arrays.fill(spans, 0, numberOfSpans, null);
118         }
119     }
120 }
121