Esempio n. 1
0
  /**
   * Returns the ascent of the text at start. This is used for scaling emoji.
   *
   * @param pos the line-relative position
   * @return the ascent of the text at start
   */
  float ascent(int pos) {
    if (mSpanned == null) {
      return mPaint.ascent();
    }

    pos += mStart;
    MetricAffectingSpan[] spans = mSpanned.getSpans(pos, pos + 1, MetricAffectingSpan.class);
    if (spans.length == 0) {
      return mPaint.ascent();
    }

    TextPaint wp = mWorkPaint;
    wp.set(mPaint);
    for (MetricAffectingSpan span : spans) {
      span.updateMeasureState(wp);
    }
    return wp.ascent();
  }
 float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len, FontMetricsInt fm) {
   int i;
   float wid;
   TextPaint workPaint = this.mWorkPaint;
   workPaint.set(paint);
   workPaint.baselineShift = 0;
   ReplacementSpan replacement = null;
   for (MetricAffectingSpan span : spans) {
     if (span instanceof ReplacementSpan) {
       replacement = (ReplacementSpan) span;
     } else {
       span.updateMeasureState(workPaint);
     }
   }
   if (replacement == null) {
     wid = addStyleRun(workPaint, len, fm);
   } else {
     wid =
         (float)
             replacement.getSize(
                 workPaint,
                 this.mText,
                 this.mTextStart + this.mPos,
                 (this.mTextStart + this.mPos) + len,
                 fm);
     float[] w = this.mWidths;
     w[this.mPos] = wid;
     int e = this.mPos + len;
     for (i = this.mPos + 1; i < e; i++) {
       w[i] = 0.0f;
     }
     this.mPos += len;
   }
   if (fm != null) {
     if (workPaint.baselineShift < 0) {
       fm.ascent += workPaint.baselineShift;
       fm.top += workPaint.baselineShift;
     } else {
       fm.descent += workPaint.baselineShift;
       fm.bottom += workPaint.baselineShift;
     }
   }
   return wid;
 }
  /**
   * Returns the advance widths for a uniform left-to-right run of text with no style changes in the
   * middle of the run. If any style is replacement text, the first character will isCancelled the
   * width of the replacement and the remaining characters will isCancelled a width of 0.
   *
   * @param paint the paint, will not be modified
   * @param workPaint a paint to modify; on return will reflect the original paint plus the effect
   *     of all spans on the run
   * @param text the text
   * @param start the start of the run
   * @param end the limit of the run
   * @param widths array to receive the advance widths of the characters. Must be at least a large
   *     as (end - start).
   * @param fmi FontMetrics information; can be null
   * @return the actual number of widths returned
   */
  public static int getTextWidths(
      TextPaint paint,
      TextPaint workPaint,
      Spanned text,
      int start,
      int end,
      float[] widths,
      Paint.FontMetricsInt fmi) {
    MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);

    ReplacementSpan replacement = null;
    workPaint.set(paint);

    for (MetricAffectingSpan span : spans) {
      if (span instanceof ReplacementSpan) {
        replacement = (ReplacementSpan) span;
      } else {
        span.updateMeasureState(workPaint);
      }
    }

    if (replacement == null) {
      workPaint.getFontMetricsInt(fmi);
      workPaint.getTextWidths(text, start, end, widths);
    } else {
      int wid = replacement.getSize(workPaint, text, start, end, fmi);

      if (end > start) {
        widths[0] = wid;
        for (int i = start + 1; i < end; i++) {
          widths[i - start] = 0;
        }
      }
    }
    return end - start;
  }
Esempio n. 4
0
  /**
   * Returns the next valid offset within this directional run, skipping conjuncts and zero-width
   * characters. This should not be called to walk off the end of the line, since the returned
   * values might not be valid on neighboring lines. If the returned offset is less than zero or
   * greater than the line length, the offset should be recomputed on the preceding or following
   * line, respectively.
   *
   * @param runIndex the run index
   * @param runStart the start of the run
   * @param runLimit the limit of the run
   * @param runIsRtl true if the run is right-to-left
   * @param offset the offset
   * @param after true if the new offset should logically follow the provided offset
   * @return the new offset
   */
  private int getOffsetBeforeAfter(
      int runIndex, int runStart, int runLimit, boolean runIsRtl, int offset, boolean after) {

    if (runIndex < 0 || offset == (after ? mLen : 0)) {
      // Walking off end of line.  Since we don't know
      // what cursor positions are available on other lines, we can't
      // return accurate values.  These are a guess.
      if (after) {
        return TextUtils.getOffsetAfter(mText, offset + mStart) - mStart;
      }
      return TextUtils.getOffsetBefore(mText, offset + mStart) - mStart;
    }

    TextPaint wp = mWorkPaint;
    wp.set(mPaint);

    int spanStart = runStart;
    int spanLimit;
    if (mSpanned == null) {
      spanLimit = runLimit;
    } else {
      int target = after ? offset + 1 : offset;
      int limit = mStart + runLimit;
      while (true) {
        spanLimit =
            mSpanned.nextSpanTransition(mStart + spanStart, limit, MetricAffectingSpan.class)
                - mStart;
        if (spanLimit >= target) {
          break;
        }
        spanStart = spanLimit;
      }

      MetricAffectingSpan[] spans =
          mSpanned.getSpans(mStart + spanStart, mStart + spanLimit, MetricAffectingSpan.class);
      spans = TextUtils.removeEmptySpans(spans, mSpanned, MetricAffectingSpan.class);

      if (spans.length > 0) {
        ReplacementSpan replacement = null;
        for (int j = 0; j < spans.length; j++) {
          MetricAffectingSpan span = spans[j];
          if (span instanceof ReplacementSpan) {
            replacement = (ReplacementSpan) span;
          } else {
            span.updateMeasureState(wp);
          }
        }

        if (replacement != null) {
          // If we have a replacement span, we're moving either to
          // the start or end of this span.
          return after ? spanLimit : spanStart;
        }
      }
    }

    int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
    int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE;
    if (mCharsValid) {
      return wp.getTextRunCursor(
          mChars, spanStart, spanLimit - spanStart, flags, offset, cursorOpt);
    } else {
      return wp.getTextRunCursor(
              mText, mStart + spanStart, mStart + spanLimit, flags, mStart + offset, cursorOpt)
          - mStart;
    }
  }