[go: nahoru, domu]

14ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne/*
24ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Copyright (C) 2012 The Android Open Source Project
34ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *
44ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Licensed under the Apache License, Version 2.0 (the "License");
54ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * you may not use this file except in compliance with the License.
64ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * You may obtain a copy of the License at
74ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *
84ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *      http://www.apache.org/licenses/LICENSE-2.0
94ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *
104ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Unless required by applicable law or agreed to in writing, software
114ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * distributed under the License is distributed on an "AS IS" BASIS,
124ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * See the License for the specific language governing permissions and
144ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * limitations under the License.
154ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */
164ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
174ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunnepackage android.text;
184ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
194ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunneimport java.lang.reflect.Array;
20b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guyimport java.util.Arrays;
214ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
224ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne/**
234ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then
244ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * provides faster access to {@link Spanned#nextSpanTransition(int, int, Class)}.
254ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *
264ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Fields are left public for a convenient direct access.
274ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne *
284ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Note that empty spans are ignored by this class.
294ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * @hide
304ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */
314ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunnepublic class SpanSet<E> {
324ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    private final Class<? extends E> classType;
334ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
344ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    int numberOfSpans;
354ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    E[] spans;
364ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    int[] spanStarts;
374ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    int[] spanEnds;
384ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    int[] spanFlags;
394ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
404ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    SpanSet(Class<? extends E> type) {
414ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        classType = type;
424ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        numberOfSpans = 0;
434ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    }
444ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
454ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    @SuppressWarnings("unchecked")
464ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    public void init(Spanned spanned, int start, int limit) {
474ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        final E[] allSpans = spanned.getSpans(start, limit, classType);
484ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        final int length = allSpans.length;
494ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
504ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        if (length > 0 && (spans == null || spans.length < length)) {
514ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            // These arrays may end up being too large because of the discarded empty spans
524ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spans = (E[]) Array.newInstance(classType, length);
534ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanStarts = new int[length];
544ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanEnds = new int[length];
554ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanFlags = new int[length];
564ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        }
574ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
58b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy        int prevNumberOfSpans = numberOfSpans;
594ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        numberOfSpans = 0;
604ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        for (int i = 0; i < length; i++) {
614ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final E span = allSpans[i];
624ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
634ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final int spanStart = spanned.getSpanStart(span);
644ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final int spanEnd = spanned.getSpanEnd(span);
654ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            if (spanStart == spanEnd) continue;
664ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
674ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final int spanFlag = spanned.getSpanFlags(span);
684ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
694ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spans[numberOfSpans] = span;
704ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanStarts[numberOfSpans] = spanStart;
714ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanEnds[numberOfSpans] = spanEnd;
724ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            spanFlags[numberOfSpans] = spanFlag;
734ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
744ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            numberOfSpans++;
754ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        }
76b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy
77b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy        // cleanup extra spans left over from previous init() call
78b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy        if (numberOfSpans < prevNumberOfSpans) {
79b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy            // prevNumberofSpans was > 0, therefore spans != null
80b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy            Arrays.fill(spans, numberOfSpans, prevNumberOfSpans, null);
81b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy        }
824ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    }
834ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
844ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    /**
854ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     * Returns true if there are spans intersecting the given interval.
864ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     * @param end must be strictly greater than start
874ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     */
884ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    public boolean hasSpansIntersecting(int start, int end) {
894ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        for (int i = 0; i < numberOfSpans; i++) {
904ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            // equal test is valid since both intervals are not empty by construction
914ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            if (spanStarts[i] >= end || spanEnds[i] <= start) continue;
924ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            return true;
934ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        }
944ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        return false;
954ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    }
964ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
974ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    /**
984ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     * Similar to {@link Spanned#nextSpanTransition(int, int, Class)}
994ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     */
1004ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    int getNextTransition(int start, int limit) {
1014ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        for (int i = 0; i < numberOfSpans; i++) {
1024ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final int spanStart = spanStarts[i];
1034ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            final int spanEnd = spanEnds[i];
1044ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            if (spanStart > start && spanStart < limit) limit = spanStart;
1054ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne            if (spanEnd > start && spanEnd < limit) limit = spanEnd;
1064ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        }
1074ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        return limit;
1084ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    }
1094ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne
1104ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    /**
1114ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     * Removes all internal references to the spans to avoid memory leaks.
1124ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne     */
1134ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    public void recycle() {
114b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy        if (spans != null) {
115b3a9bc038d3a218b1dbdf7b5668e3d6c12be5ee4Romain Guy            Arrays.fill(spans, 0, numberOfSpans, null);
1164ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne        }
1174ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne    }
1184ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne}
119