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; 204ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 214ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne/** 224ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then 234ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * provides faster access to {@link Spanned#nextSpanTransition(int, int, Class)}. 244ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * 254ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Fields are left public for a convenient direct access. 264ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * 274ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Note that empty spans are ignored by this class. 284ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * @hide 294ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */ 304ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunnepublic class SpanSet<E> { 314ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne private final Class<? extends E> classType; 324ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 334ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne int numberOfSpans; 344ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne E[] spans; 354ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne int[] spanStarts; 364ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne int[] spanEnds; 374ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne int[] spanFlags; 384ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 394ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne SpanSet(Class<? extends E> type) { 404ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne classType = type; 414ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne numberOfSpans = 0; 424ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 434ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 444ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne @SuppressWarnings("unchecked") 454ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne public void init(Spanned spanned, int start, int limit) { 464ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final E[] allSpans = spanned.getSpans(start, limit, classType); 474ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int length = allSpans.length; 484ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 494ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne if (length > 0 && (spans == null || spans.length < length)) { 504ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne // These arrays may end up being too large because of the discarded empty spans 514ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spans = (E[]) Array.newInstance(classType, length); 524ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanStarts = new int[length]; 534ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanEnds = new int[length]; 544ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanFlags = new int[length]; 554ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 564ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 574ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne numberOfSpans = 0; 584ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne for (int i = 0; i < length; i++) { 594ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final E span = allSpans[i]; 604ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 614ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int spanStart = spanned.getSpanStart(span); 624ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int spanEnd = spanned.getSpanEnd(span); 634ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne if (spanStart == spanEnd) continue; 644ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 654ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int spanFlag = spanned.getSpanFlags(span); 664ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 674ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spans[numberOfSpans] = span; 684ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanStarts[numberOfSpans] = spanStart; 694ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanEnds[numberOfSpans] = spanEnd; 704ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spanFlags[numberOfSpans] = spanFlag; 714ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 724ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne numberOfSpans++; 734ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 744ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 754ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 764ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne /** 774ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Returns true if there are spans intersecting the given interval. 784ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * @param end must be strictly greater than start 794ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */ 804ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne public boolean hasSpansIntersecting(int start, int end) { 814ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne for (int i = 0; i < numberOfSpans; i++) { 824ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne // equal test is valid since both intervals are not empty by construction 834ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne if (spanStarts[i] >= end || spanEnds[i] <= start) continue; 844ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne return true; 854ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 864ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne return false; 874ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 884ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 894ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne /** 904ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Similar to {@link Spanned#nextSpanTransition(int, int, Class)} 914ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */ 924ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne int getNextTransition(int start, int limit) { 934ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne for (int i = 0; i < numberOfSpans; i++) { 944ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int spanStart = spanStarts[i]; 954ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne final int spanEnd = spanEnds[i]; 964ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne if (spanStart > start && spanStart < limit) limit = spanStart; 974ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne if (spanEnd > start && spanEnd < limit) limit = spanEnd; 984ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 994ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne return limit; 1004ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 1014ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne 1024ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne /** 1034ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne * Removes all internal references to the spans to avoid memory leaks. 1044ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne */ 1054ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne public void recycle() { 1064ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne // The spans array is guaranteed to be not null when numberOfSpans is > 0 1074ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne for (int i = 0; i < numberOfSpans; i++) { 1084ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled 1094ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 1104ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne } 1114ffb879f4866f7d51070bfc9d10e7a2fdac62d4cGilles Debunne} 112