Java 类android.text.style.ReplacementSpan 实例源码

项目:FastTextView    文件:TextMeasureUtil.java   
/**
 * Do not support cross Span.
 *
 * @param text       text
 * @param parentSpan parentSpan
 * @param start      start index of parentSpan
 * @param end        end index of parentSpan
 * @param paint      TextPaint
 * @return recursive calculated width
 */
public int recursiveGetSizeWithReplacementSpan(CharSequence text, ReplacementSpan parentSpan, @IntRange(from = 0) int start, @IntRange(from = 0) int end, Paint paint) {
  if (text instanceof Spanned) {
    Spanned spannedText = (Spanned) text;
    List<ReplacementSpan> spans = getSortedReplacementSpans(spannedText, start, end);
    if (!spans.isEmpty()) {
      int lastIndexCursor = 0;
      int width = 0;
      for (ReplacementSpan span : spans) {
        if (span == parentSpan) {
          continue;
        }
        int spanStart = spannedText.getSpanStart(span);
        int spanEnd = spannedText.getSpanEnd(span);
        width += parentSpan.getSize(paint, text, lastIndexCursor, spanStart, null);
        width += span.getSize(paint, text, spanStart, spanEnd, null);
        lastIndexCursor = spanEnd;
      }
      if (lastIndexCursor < end) {
        width += parentSpan.getSize(paint, text, lastIndexCursor, end, null);
      }
      return width;
    }
  }
  return parentSpan.getSize(paint, text, start, end, null);
}
项目:FastTextView    文件:EllipsisSpannedContainer.java   
@Override
public <T> T[] getSpans(int start, int end, Class<T> type) {
  if (mEllipsisEnd >= end && mEllipsisStart <= end) {
    T[] spans1 = mSourceSpanned.getSpans(start, Math.max(mEllipsisStart, start), type);
    T[] spans2 = mSourceSpanned.getSpans(Math.min(end, mEllipsisEnd), end, type);
    int offset = mCustomEllipsisSpan != null
        && (type.isAssignableFrom(ReplacementSpan.class) || type == mCustomEllipsisSpan.getClass()) ?
        1 : 0;
    int minLen = spans1.length + spans2.length + offset;
    T[] spans = (T[]) Array.newInstance(type, minLen);
    if (spans.length > minLen) {
      spans = Arrays.copyOf(spans, minLen);
    }
    System.arraycopy(spans1, 0, spans, 0, spans1.length);
    if (offset > 0) {
      spans[spans1.length] =  (T) mCustomEllipsisSpan;
    }
    System.arraycopy(spans2, 0, spans, spans1.length + offset, spans2.length);
    return spans;
  }
  return mSourceSpanned.getSpans(start, end, type);
}
项目:Emojier-Andriod    文件:SpanableUtil.java   
/**
 * get real translate charsequence
 * @param content
 * @return
 */
public static CharSequence getTranslateTxt(CharSequence content) {
    StringBuilder sBuilder = new StringBuilder();
    if (content instanceof SpannableStringBuilder) {
        SpannableStringBuilder spanSb = (SpannableStringBuilder) content;
        if (spanSb.toString().contains(EMHolderEntity.FINAL_HOLDER)) {
            for (int i = 0; i < spanSb.length(); i++) {
                ReplacementSpan[] spans = spanSb.getSpans(i, i + 1, ReplacementSpan.class);
                if (spans.length > 0) {
                    if (spans[0] instanceof EMImageSpan) {
                        EMImageSpan imgSpan = (EMImageSpan) spans[0];
                        sBuilder.append(imgSpan.mTransferTxt);
                    } else if (spans[0] instanceof DefEmojSpan) {
                        DefEmojSpan defSpan = (DefEmojSpan) spans[0];
                        sBuilder.append(defSpan.mTransferTxt);
                    }
                } else {
                    sBuilder.append(spanSb.subSequence(i, i + 1));
                }
            }
        } else {
            sBuilder.append(content);
        }
    }
    return sBuilder;
}
项目:Emojier-Andriod    文件:EMContentUtil.java   
public static CharSequence getTranslateTxt(CharSequence content) {
    StringBuilder sBuilder = new StringBuilder();
    if (content instanceof SpannableStringBuilder) {
        SpannableStringBuilder spanSb = (SpannableStringBuilder) content;
        if (spanSb.toString().contains(EMHolderEntity.FINAL_HOLDER)) {
            for (int i = 0; i < spanSb.length(); i++) {
                ReplacementSpan[] spans = spanSb.getSpans(i, i + 1, ReplacementSpan.class);
                if (spans.length > 0) {
                    if (spans[0] instanceof EMImageSpan) {
                        EMImageSpan imgSpan = (EMImageSpan) spans[0];
                        sBuilder.append(imgSpan.mTransferTxt);
                    } else if (spans[0] instanceof DefEmojSpan) {
                        DefEmojSpan defSpan = (DefEmojSpan) spans[0];
                        sBuilder.append(defSpan.mTransferTxt);
                    }
                } else {
                    sBuilder.append(spanSb.subSequence(i, i + 1));
                }
            }
        } else {
            sBuilder.append(content);
        }
    }
    return sBuilder;
}
项目:Pioneer    文件:Spans.java   
@Override
public int getSize(@NonNull Rect outRect, @NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
    int width = super.getSize(outRect, paint, text, start, end, fm);
    if (styles != null) {
        for (CharacterStyle style : styles) {
            if (style instanceof SupportSpan) {
                width = Math.max(width, ((SupportSpan) style).getSize(frame, paint, text, start, end, fm));
            } else if (style instanceof ReplacementSpan) {
                width = Math.max(width, ((ReplacementSpan) style).getSize(paint, text, start, end, fm));
            } else if (paint instanceof TextPaint) {
                if (style instanceof MetricAffectingSpan) {
                    ((MetricAffectingSpan) style).updateMeasureState((TextPaint) paint);
                }
            }
        }
    }
    frame.right = width;
    return width;
}
项目:Pioneer    文件:SpansV1.java   
@Override
public int getSize(@NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
    width = 0;
    for (CharacterStyle style : styles) {
        if (style instanceof ReplacementSpan) {
            width = Math.max(width, ((ReplacementSpan) style).getSize(paint, text, start, end, fm));
        } else if (paint instanceof TextPaint) {
            if (style instanceof MetricAffectingSpan) {
                ((MetricAffectingSpan) style).updateMeasureState((TextPaint) paint);
            }
        }
    }
    if (fm != null) {
        paint.getFontMetricsInt(fm);
    }
    paint.getFontMetricsInt(fontMetricsInt);
    width = Math.max(width, (int) Math.ceil(paint.measureText(text, start, end)));
    frame.right = width;
    frame.top = fontMetricsInt.top;
    frame.bottom = fontMetricsInt.bottom;
    if (bitmap == null) {
        bitmap = Bitmap.createBitmap(width, frame.bottom - frame.top, Bitmap.Config.ARGB_8888);
        bitmapCanvas = new Canvas(bitmap);
    }
    return width;
}
项目:Pioneer    文件:SpansV1.java   
@Override
        public void draw(@NonNull Canvas canvas, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
//            bitmapCanvas.drawColor(Color.GRAY, PorterDuff.Mode.CLEAR);
            int color = /*paint instanceof TextPaint ? ((TextPaint) paint).bgColor :*/ paint.getColor();
            bitmapCanvas.drawColor(color);
            for (CharacterStyle style : styles) {
                if (style instanceof ReplacementSpan) {
                    ((ReplacementSpan) style).draw(bitmapCanvas, text, start, end, 0, top, y, bottom, paint);
                } else if (paint instanceof TextPaint) {
                    style.updateDrawState((TextPaint) paint);
                }
            }
            paint.setXfermode(xfermode);
            bitmapCanvas.drawText(text, start, end, 0, y, paint);
            canvas.drawBitmap(bitmap, x, 0, null);
        }
项目:Pioneer    文件:Spans.java   
@Override
public int getSize(@NonNull Rect outRect, @NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
    int width = super.getSize(outRect, paint, text, start, end, fm);
    if (styles != null) {
        for (CharacterStyle style : styles) {
            if (style instanceof SupportSpan) {
                width = Math.max(width, ((SupportSpan) style).getSize(frame, paint, text, start, end, fm));
            } else if (style instanceof ReplacementSpan) {
                width = Math.max(width, ((ReplacementSpan) style).getSize(paint, text, start, end, fm));
            } else if (paint instanceof TextPaint) {
                if (style instanceof MetricAffectingSpan) {
                    ((MetricAffectingSpan) style).updateMeasureState((TextPaint) paint);
                }
            }
        }
    }
    frame.right = width;
    return width;
}
项目:Pioneer    文件:SpansV1.java   
@Override
public int getSize(@NonNull Paint paint, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, @Nullable Paint.FontMetricsInt fm) {
    width = 0;
    for (CharacterStyle style : styles) {
        if (style instanceof ReplacementSpan) {
            width = Math.max(width, ((ReplacementSpan) style).getSize(paint, text, start, end, fm));
        } else if (paint instanceof TextPaint) {
            if (style instanceof MetricAffectingSpan) {
                ((MetricAffectingSpan) style).updateMeasureState((TextPaint) paint);
            }
        }
    }
    if (fm != null) {
        paint.getFontMetricsInt(fm);
    }
    paint.getFontMetricsInt(fontMetricsInt);
    width = Math.max(width, (int) Math.ceil(paint.measureText(text, start, end)));
    frame.right = width;
    frame.top = fontMetricsInt.top;
    frame.bottom = fontMetricsInt.bottom;
    if (bitmap == null) {
        bitmap = Bitmap.createBitmap(width, frame.bottom - frame.top, Bitmap.Config.ARGB_8888);
        bitmapCanvas = new Canvas(bitmap);
    }
    return width;
}
项目:Pioneer    文件:SpansV1.java   
@Override
        public void draw(@NonNull Canvas canvas, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
//            bitmapCanvas.drawColor(Color.GRAY, PorterDuff.Mode.CLEAR);
            int color = /*paint instanceof TextPaint ? ((TextPaint) paint).bgColor :*/ paint.getColor();
            bitmapCanvas.drawColor(color);
            for (CharacterStyle style : styles) {
                if (style instanceof ReplacementSpan) {
                    ((ReplacementSpan) style).draw(bitmapCanvas, text, start, end, 0, top, y, bottom, paint);
                } else if (paint instanceof TextPaint) {
                    style.updateDrawState((TextPaint) paint);
                }
            }
            paint.setXfermode(xfermode);
            bitmapCanvas.drawText(text, start, end, 0, y, paint);
            canvas.drawBitmap(bitmap, x, 0, null);
        }
项目:FastTextView    文件:TextMeasureUtil.java   
public static List<ReplacementSpan> getSortedReplacementSpans(final Spanned spanned, int start, int end) {
  List<ReplacementSpan> sortedSpans = new LinkedList<>();
  ReplacementSpan[] spans = spanned.getSpans(start, end, ReplacementSpan.class);
  if (spans.length > 0) {
    sortedSpans.addAll(Arrays.asList(spans));
  }
  Collections.sort(sortedSpans, new Comparator<ReplacementSpan>() {
    @Override
    public int compare(ReplacementSpan span1, ReplacementSpan span2) {
      return spanned.getSpanStart(span1) - spanned.getSpanStart(span2);
    }
  });
  return sortedSpans;
}
项目:Pioneer    文件:Spans.java   
@Override
public void draw(@NonNull Rect outRect, @NonNull Canvas canvas, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
    for (CharacterStyle style : styles) {
        if (style instanceof SupportSpan) {
            ((SupportSpan) style).draw(frame, canvas, text, start, end, x, top, y, bottom, paint);
        } else if (style instanceof ReplacementSpan) {
            ((ReplacementSpan) style).draw(canvas, text, start, end, x, top, y, bottom, paint);
        } else if (paint instanceof TextPaint) {
            style.updateDrawState((TextPaint) paint);
        }
    }
}
项目:Pioneer    文件:Truss.java   
/** Starts {@code span} at the current position in the builder. */
public Truss pushSpan(Object span) {
    if (span instanceof ReplacementSpan) {
        replacements++;
    } else if (replacements > 0 && span instanceof CharacterStyle) {
        span = convert((CharacterStyle) span);
    }
    stack.addLast(new Span(builder.length(), span));
    return this;
}
项目:Pioneer    文件:Truss.java   
/** End the most recently pushed span at the current position in the builder. */
public Truss popSpan() {
    Span span = stack.removeLast();
    if (span.span instanceof ReplacementSpan) {
        replacements--;
    }
    builder.setSpan(span.span, span.start, builder.length(), SPAN_INCLUSIVE_EXCLUSIVE);
    return this;
}
项目:Pioneer    文件:Spans.java   
@Override
public void draw(@NonNull Rect outRect, @NonNull Canvas canvas, CharSequence text, @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
    for (CharacterStyle style : styles) {
        if (style instanceof SupportSpan) {
            ((SupportSpan) style).draw(frame, canvas, text, start, end, x, top, y, bottom, paint);
        } else if (style instanceof ReplacementSpan) {
            ((ReplacementSpan) style).draw(canvas, text, start, end, x, top, y, bottom, paint);
        } else if (paint instanceof TextPaint) {
            style.updateDrawState((TextPaint) paint);
        }
    }
}
项目:Pioneer    文件:Truss.java   
/** Starts {@code span} at the current position in the builder. */
public Truss pushSpan(Object span) {
    if (span instanceof ReplacementSpan) {
        replacements++;
    } else if (replacements > 0 && span instanceof CharacterStyle) {
        span = convert((CharacterStyle) span);
    }
    stack.addLast(new Span(builder.length(), span));
    return this;
}
项目:Pioneer    文件:Truss.java   
/** End the most recently pushed span at the current position in the builder. */
public Truss popSpan() {
    Span span = stack.removeLast();
    if (span.span instanceof ReplacementSpan) {
        replacements--;
    }
    builder.setSpan(span.span, span.start, builder.length(), SPAN_INCLUSIVE_EXCLUSIVE);
    return this;
}
项目:IntentsLab    文件:FormattedTextBuilder.java   
private void onSpanAdded(Object span) {
    if (span instanceof MetricAffectingSpan) {
        mHasMetricAffectingSpan = true;
    }
    if (span instanceof ReplacementSpan) {
        mHasReplacementSpan = true;
    }
    if (span instanceof ParagraphStyle) {
        mHasParagraphStyle = true;
    }
}
项目:android-bubble-text    文件:ChipsEditText.java   
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    manipulatedSpan = null;
    if (after < count && !manualModeOn) {
        ReplacementSpan[] spans = ((Spannable)s).getSpans(start, start+count, ReplacementSpan.class);
        if (spans.length == 1) {
            manipulatedSpan = spans[0];
        } else {
            manipulatedSpan = null;
        }
    }
}
项目:FastTextView    文件:FastTextView.java   
public void setCustomEllipsisSpan(ReplacementSpan customEllipsisSpan) {
  mCustomEllipsisSpan = customEllipsisSpan;
}
项目:FastTextView    文件:FastTextView.java   
public ReplacementSpan getCustomEllipsisSpan() {
  return mCustomEllipsisSpan;
}
项目:FastTextView    文件:ReadMoreTextView.java   
public void setCustomCollapseSpan(ReplacementSpan collapseSpan) {
  mCollapseSpan = collapseSpan;
}
项目:FastTextView    文件:EllipsisSpannedContainer.java   
public void setCustomEllipsisSpan(ReplacementSpan customEllipsisSpan) {
  mCustomEllipsisSpan = customEllipsisSpan;
}
项目:FastTextView    文件:TextLineImpl15.java   
/**
 * Utility function for measuring and rendering a replacement.
 *
 * @param replacement the replacement
 * @param wp          the work paint
 * @param start       the start of the run
 * @param limit       the limit of the run
 * @param runIsRtl    true if the run is right-to-left
 * @param c           the canvas, can be null if not rendering
 * @param x           the edge of the replacement closest to the leading margin
 * @param top         the top of the line
 * @param y           the baseline
 * @param bottom      the bottom of the line
 * @param fmi         receives metrics information, can be null
 * @param needWidth   true if the width of the replacement is needed
 * @return the signed width of the run based on the run direction; only
 * valid if needWidth is true
 */
private float handleReplacement(ReplacementSpan replacement, TextPaint wp,
                                int start, int limit, boolean runIsRtl, Canvas c,
                                float x, int top, int y, int bottom, FontMetricsInt fmi,
                                boolean needWidth) {

  float ret = 0;

  int textStart = mStart + start;
  int textLimit = mStart + limit;

  if (needWidth || (c != null && runIsRtl)) {
    int previousTop = 0;
    int previousAscent = 0;
    int previousDescent = 0;
    int previousBottom = 0;
    int previousLeading = 0;

    boolean needUpdateMetrics = (fmi != null);

    if (needUpdateMetrics) {
      previousTop = fmi.top;
      previousAscent = fmi.ascent;
      previousDescent = fmi.descent;
      previousBottom = fmi.bottom;
      previousLeading = fmi.leading;
    }

    ret = replacement.getSize(wp, mText, textStart, textLimit, fmi);

    if (needUpdateMetrics) {
      updateMetrics(fmi, previousTop, previousAscent, previousDescent, previousBottom,
          previousLeading);
    }
  }

  if (c != null) {
    if (runIsRtl) {
      x -= ret;
    }
    replacement.draw(c, mText, textStart, textLimit,
        x, top, y, bottom, wp);
  }

  return runIsRtl ? -ret : ret;
}
项目:FastTextView    文件:TextLineImpl23.java   
/**
 * Utility function for measuring and rendering a replacement.
 *
 * @param replacement the replacement
 * @param wp          the work paint
 * @param start       the start of the run
 * @param limit       the limit of the run
 * @param runIsRtl    true if the run is right-to-left
 * @param c           the canvas, can be null if not rendering
 * @param x           the edge of the replacement closest to the leading margin
 * @param top         the top of the line
 * @param y           the baseline
 * @param bottom      the bottom of the line
 * @param fmi         receives metrics information, can be null
 * @param needWidth   true if the width of the replacement is needed
 * @return the signed width of the run based on the run direction; only
 * valid if needWidth is true
 */
private float handleReplacement(ReplacementSpan replacement, TextPaint wp,
                                int start, int limit, boolean runIsRtl, Canvas c,
                                float x, int top, int y, int bottom, FontMetricsInt fmi,
                                boolean needWidth) {

  float ret = 0;

  int textStart = mStart + start;
  int textLimit = mStart + limit;

  if (needWidth || (c != null && runIsRtl)) {
    int previousTop = 0;
    int previousAscent = 0;
    int previousDescent = 0;
    int previousBottom = 0;
    int previousLeading = 0;

    boolean needUpdateMetrics = (fmi != null);

    if (needUpdateMetrics) {
      previousTop = fmi.top;
      previousAscent = fmi.ascent;
      previousDescent = fmi.descent;
      previousBottom = fmi.bottom;
      previousLeading = fmi.leading;
    }

    ret = replacement.getSize(wp, mText, textStart, textLimit, fmi);

    if (needUpdateMetrics) {
      updateMetrics(fmi, previousTop, previousAscent, previousDescent, previousBottom,
          previousLeading);
    }
  }

  if (c != null) {
    if (runIsRtl) {
      x -= ret;
    }
    replacement.draw(c, mText, textStart, textLimit,
        x, top, y, bottom, wp);
  }

  return runIsRtl ? -ret : ret;
}
项目:Emojier-Andriod    文件:EMAssembleController.java   
public EMTranslatEntity assembleSpan(ArrayList<EMCharacterEntity> joinArr) throws JSONException {

        if (joinArr == null || joinArr.size() == 0) return null;

        SpannableStringBuilder spanSb = new SpannableStringBuilder();
        Vector<EMCandiateEntity> allStressEMKeys = new Vector<>();

        for (int i = 0; i < joinArr.size(); i++) {
            EMCharacterEntity entry = joinArr.get(i);
            switch (entry.mCharType) {
                case Normal:
                case Other:
                case Space:
                    entry.mWordStart = spanSb.length();
                    spanSb.append(entry.mWord);
                    break;
                case Emoj:
                    SpannableStringBuilder tempSpan = (SpannableStringBuilder) entry.mWord;
                    ReplacementSpan[] spans = tempSpan.getSpans(0, entry.mWord.length(), ReplacementSpan.class);
                    if (spans.length > 0) {
                        ReplacementSpan emojSpan = null;
                        if (spans[0] instanceof EMImageSpan) {
                            emojSpan = (EMImageSpan) spans[0];
                        } else if (spans[0] instanceof DefEmojSpan) {
                            emojSpan = (DefEmojSpan) spans[0];
                        }
                        spanSb.append(HOLDER_CHAR);
                        spanSb.setSpan(emojSpan, spanSb.length() - 1, spanSb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                    }
                    break;
                case Translate:
                    String emojProperty = EMDBMagager.getInstance().queryEmojByTag(entry.mWord.toString());
                    if (StringUtil.isNullOrEmpty(emojProperty)) {
                        spanSb.append(entry.mWord);
                    } else {
                        EMCandiateEntity candiateEmojEntity = new EMCandiateEntity(entry.mWord.toString(), entry.mWordStart);
                        candiateEmojEntity.parseRespJson(new JSONObject(emojProperty));
                        ArrayList<EMCandiateProperty> emojTagEntities = candiateEmojEntity.mEmojEntities;
                        if (emojTagEntities != null && emojTagEntities.size() == 1) {
                            String emojTagId = "#|" + candiateEmojEntity.mEMKey + "_" + emojTagEntities.get(0).mUniqueId + "|";
                            candiateEmojEntity.mEMStart = spanSb.length();
                            spanSb.append(HOLDER_CHAR);
                            DefEmojSpan emojResponseSpan = new DefEmojSpan(emojTagEntities.get(0));
                            emojResponseSpan.mOriginTxt = candiateEmojEntity.mEMKey;
                            emojResponseSpan.mTransferTxt = emojTagId;

                            spanSb.setSpan(emojResponseSpan, spanSb.toString().length() - 1, spanSb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

                            // handle here if cache key and emoji property
                            cacheCustomEmojToDB(emojTagId);
                        }else {
                            candiateEmojEntity.mEMStart = spanSb.length();
                            allStressEMKeys.add(candiateEmojEntity);
                            spanSb.append(entry.mWord);
                        }
                    }
                    break;
            }
        }

        EMTranslatEntity translatEntity = new EMTranslatEntity(spanSb, allStressEMKeys);
        return translatEntity;
    }
项目:IntentsLab    文件:FormattedTextBuilder.java   
@SuppressWarnings("unchecked")
@Override
public <T> T[] getSpans(int start, int end, Class<T> type) {
    // Fast path for common time-critical spans that aren't there
    if (type == MetricAffectingSpan.class && !mHasMetricAffectingSpan) {
        return (T[]) EMPTY_METRIC_AFFECTING_SPAN_ARRAY;
    }
    if (type == ReplacementSpan.class && !mHasReplacementSpan) {
        return (T[]) EMPTY_REPLACEMENT_SPAN_ARRAY;
    }
    if (!mHasParagraphStyle) {
        if (type == LeadingMarginSpan.class) {
            return (T[]) EMPTY_LEADING_MARGIN_SPAN_ARRAY;
        }
        if (type == LineHeightSpan.class) {
            return (T[]) EMPTY_LINE_HEIGHT_SPAN_ARRAY;
        }
        if (type == TabStopSpan.class) {
            return (T[]) EMPTY_TAB_STOP_SPAN_ARRAY;
        }
    }

    T[] spansFromSuperclass = mSpannableString.getSpans(start, end, type);

    if (
            mSpansArr.length == 0 || // We have no optimized spans
            isExcludedSpanType(type)) { // Query is about unoptimized span
        return spansFromSuperclass;
    }

    // Based on Arrays.binarySearch()
    int lo = 0;
    int hi = mSpansArr.length - 1;
    int mid = -2;

    while (lo <= hi) {
        mid = (lo + hi) >>> 1;
        int midVal = mSpansArr[mid].end;

        if (midVal < start) {
            lo = mid + 1;
        } else if (midVal > start) {
            hi = mid - 1;
        } else {
            break;
        }
    }

    // Iterate over spans in range
    List<T> result = null;
    for (; mid < mSpansArr.length && mSpansArr[mid].start < end; mid++) {
        if (mSpansArr[mid].end > start && type.isInstance(mSpansArr[mid].span)) {
            if (result == null) {
                result = LIST_POOL.acquire();
                if (spansFromSuperclass.length != 0) {
                    result.addAll(Arrays.asList(spansFromSuperclass));
                }
            }
            result.add((T) mSpansArr[mid].span);
        }
    }

    // If we have list then make array and pass to superclass
    if (result == null) {
        return spansFromSuperclass;
    } else {
        T[] resultArray = result.toArray((T[]) Array.newInstance(type, result.size()));
        LIST_POOL.release(result);
        return resultArray;
    }
}