android.text.style.ReplacementSpan Java Examples

The following examples show how to use android.text.style.ReplacementSpan. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SpansV1.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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);
        }
 
Example #2
Source File: Spans.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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;
}
 
Example #3
Source File: EllipsisSpannedContainer.java    From FastTextView with Apache License 2.0 6 votes vote down vote up
@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);
}
 
Example #4
Source File: SpansV1.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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;
}
 
Example #5
Source File: SpansV1.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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);
        }
 
Example #6
Source File: Spans.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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;
}
 
Example #7
Source File: TextMeasureUtil.java    From FastTextView with Apache License 2.0 6 votes vote down vote up
/**
 * 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);
}
 
Example #8
Source File: BaseKeyListener.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
private static int adjustReplacementSpan(CharSequence text, int offset, boolean moveToStart) {
    if (!(text instanceof Spanned)) {
        return offset;
    }

    ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset, ReplacementSpan.class);
    for (int i = 0; i < spans.length; i++) {
        final int start = ((Spanned) text).getSpanStart(spans[i]);
        final int end = ((Spanned) text).getSpanEnd(spans[i]);

        if (start < offset && end > offset) {
            offset = moveToStart ? start : end;
        }
    }
    return offset;
}
 
Example #9
Source File: MeasuredParagraph.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
private void applyReplacementRun(@NonNull ReplacementSpan replacement,
                                 @IntRange(from = 0) int start,  // inclusive, in copied buffer
                                 @IntRange(from = 0) int end,  // exclusive, in copied buffer
                                 /* Maybe Zero */ long nativeBuilderPtr) {
    // Use original text. Shouldn't matter.
    // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
    //       backward compatibility? or Should we initialize them for getFontMetricsInt?
    final float width = replacement.getSize(
            mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
    if (nativeBuilderPtr == 0) {
        // Assigns all width to the first character. This is the same behavior as minikin.
        mWidths.set(start, width);
        if (end > start + 1) {
            Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f);
        }
        mWholeWidth += width;
    } else {
        nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
                           width);
    }
}
 
Example #10
Source File: DynamicLayout.java    From android_9.0.0_r45 with Apache License 2.0 6 votes vote down vote up
private boolean contentMayProtrudeFromLineTopOrBottom(CharSequence text, int start, int end) {
    if (text instanceof Spanned) {
        final Spanned spanned = (Spanned) text;
        if (spanned.getSpans(start, end, ReplacementSpan.class).length > 0) {
            return true;
        }
    }
    // Spans other than ReplacementSpan can be ignored because line top and bottom are
    // disjunction of all tops and bottoms, although it's not optimal.
    final Paint paint = getPaint();
    if (text instanceof PrecomputedText) {
        PrecomputedText precomputed = (PrecomputedText) text;
        precomputed.getBounds(start, end, mTempRect);
    } else {
        paint.getTextBounds(text, start, end, mTempRect);
    }
    final Paint.FontMetricsInt fm = paint.getFontMetricsInt();
    return mTempRect.top < fm.top || mTempRect.bottom > fm.bottom;
}
 
Example #11
Source File: SpansV1.java    From Pioneer with Apache License 2.0 6 votes vote down vote up
@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;
}
 
Example #12
Source File: Truss.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
/** 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;
}
 
Example #13
Source File: Spans.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
@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);
        }
    }
}
 
Example #14
Source File: Truss.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
/** 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;
}
 
Example #15
Source File: Truss.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
/** 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;
}
 
Example #16
Source File: Truss.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
/** 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;
}
 
Example #17
Source File: Spans.java    From Pioneer with Apache License 2.0 5 votes vote down vote up
@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);
        }
    }
}
 
Example #18
Source File: TextUtils.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
public static int getOffsetAfter(CharSequence text, int offset) {
    int len = text.length();

    if (offset == len)
        return len;
    if (offset == len - 1)
        return len;

    char c = text.charAt(offset);

    if (c >= '\uD800' && c <= '\uDBFF') {
        char c1 = text.charAt(offset + 1);

        if (c1 >= '\uDC00' && c1 <= '\uDFFF')
            offset += 2;
        else
            offset += 1;
    } else {
        offset += 1;
    }

    if (text instanceof Spanned) {
        ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,
                                                   ReplacementSpan.class);

        for (int i = 0; i < spans.length; i++) {
            int start = ((Spanned) text).getSpanStart(spans[i]);
            int end = ((Spanned) text).getSpanEnd(spans[i]);

            if (start < offset && end > offset)
                offset = end;
        }
    }

    return offset;
}
 
Example #19
Source File: TextMeasureUtil.java    From FastTextView with Apache License 2.0 5 votes vote down vote up
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;
}
 
Example #20
Source File: Layout.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
private int getOffsetAtStartOf(int offset) {
    // XXX this probably should skip local reorderings and
    // zero-width characters, look at callers
    if (offset == 0)
        return 0;

    CharSequence text = mText;
    char c = text.charAt(offset);

    if (c >= '\uDC00' && c <= '\uDFFF') {
        char c1 = text.charAt(offset - 1);

        if (c1 >= '\uD800' && c1 <= '\uDBFF')
            offset -= 1;
    }

    if (mSpannedText) {
        ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,
                                                   ReplacementSpan.class);

        for (int i = 0; i < spans.length; i++) {
            int start = ((Spanned) text).getSpanStart(spans[i]);
            int end = ((Spanned) text).getSpanEnd(spans[i]);

            if (start < offset && end > offset)
                offset = start;
        }
    }

    return offset;
}
 
Example #21
Source File: TextUtils.java    From android_9.0.0_r45 with Apache License 2.0 5 votes vote down vote up
public static int getOffsetBefore(CharSequence text, int offset) {
    if (offset == 0)
        return 0;
    if (offset == 1)
        return 0;

    char c = text.charAt(offset - 1);

    if (c >= '\uDC00' && c <= '\uDFFF') {
        char c1 = text.charAt(offset - 2);

        if (c1 >= '\uD800' && c1 <= '\uDBFF')
            offset -= 2;
        else
            offset -= 1;
    } else {
        offset -= 1;
    }

    if (text instanceof Spanned) {
        ReplacementSpan[] spans = ((Spanned) text).getSpans(offset, offset,
                                                   ReplacementSpan.class);

        for (int i = 0; i < spans.length; i++) {
            int start = ((Spanned) text).getSpanStart(spans[i]);
            int end = ((Spanned) text).getSpanEnd(spans[i]);

            if (start < offset && end > offset)
                offset = start;
        }
    }

    return offset;
}
 
Example #22
Source File: ShapingRunLocator.java    From Tehreer-Android with Apache License 2.0 4 votes vote down vote up
public ReplacementSpan getReplacement() {
    return mCurrent.replacement;
}
 
Example #23
Source File: TextLineImpl23.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
/**
 * 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;
}
 
Example #24
Source File: TextLineImpl15.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
/**
 * 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;
}
 
Example #25
Source File: EllipsisSpannedContainer.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
public void setCustomEllipsisSpan(ReplacementSpan customEllipsisSpan) {
  mCustomEllipsisSpan = customEllipsisSpan;
}
 
Example #26
Source File: ReadMoreTextView.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
public void setCustomCollapseSpan(ReplacementSpan collapseSpan) {
  mCollapseSpan = collapseSpan;
}
 
Example #27
Source File: FastTextView.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
public void setCustomEllipsisSpan(ReplacementSpan customEllipsisSpan) {
  mCustomEllipsisSpan = customEllipsisSpan;
}
 
Example #28
Source File: FastTextView.java    From FastTextView with Apache License 2.0 4 votes vote down vote up
public ReplacementSpan getCustomEllipsisSpan() {
  return mCustomEllipsisSpan;
}
 
Example #29
Source File: TextLine.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
/**
 * 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;
}
 
Example #30
Source File: MeasuredParagraph.java    From android_9.0.0_r45 with Apache License 2.0 4 votes vote down vote up
/**
 * Reset internal state and analyzes text for bidirectional runs.
 *
 * @param text the character sequence to be measured
 * @param start the inclusive start offset of the target region in the text
 * @param end the exclusive end offset of the target region in the text
 * @param textDir the text direction
 */
private void resetAndAnalyzeBidi(@NonNull CharSequence text,
                                 @IntRange(from = 0) int start,  // inclusive
                                 @IntRange(from = 0) int end,  // exclusive
                                 @NonNull TextDirectionHeuristic textDir) {
    reset();
    mSpanned = text instanceof Spanned ? (Spanned) text : null;
    mTextStart = start;
    mTextLength = end - start;

    if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) {
        mCopiedBuffer = new char[mTextLength];
    }
    TextUtils.getChars(text, start, end, mCopiedBuffer, 0);

    // Replace characters associated with ReplacementSpan to U+FFFC.
    if (mSpanned != null) {
        ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class);

        for (int i = 0; i < spans.length; i++) {
            int startInPara = mSpanned.getSpanStart(spans[i]) - start;
            int endInPara = mSpanned.getSpanEnd(spans[i]) - start;
            // The span interval may be larger and must be restricted to [start, end)
            if (startInPara < 0) startInPara = 0;
            if (endInPara > mTextLength) endInPara = mTextLength;
            Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER);
        }
    }

    if ((textDir == TextDirectionHeuristics.LTR
            || textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR
            || textDir == TextDirectionHeuristics.ANYRTL_LTR)
            && TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) {
        mLevels.clear();
        mParaDir = Layout.DIR_LEFT_TO_RIGHT;
        mLtrWithoutBidi = true;
    } else {
        final int bidiRequest;
        if (textDir == TextDirectionHeuristics.LTR) {
            bidiRequest = Layout.DIR_REQUEST_LTR;
        } else if (textDir == TextDirectionHeuristics.RTL) {
            bidiRequest = Layout.DIR_REQUEST_RTL;
        } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
            bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
        } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
            bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
        } else {
            final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength);
            bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
        }
        mLevels.resize(mTextLength);
        mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray());
        mLtrWithoutBidi = false;
    }
}