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;
 }
Example #2
0
 @Override
 public void updateDrawState(TextPaint tp) {
   initIfNecessary(tp);
   tp.baselineShift = shift;
 }
  /**
   * Draws and/or measures a uniform run of text on a single line. No span of interest should start
   * or end in the middle of this run (if not drawing, character spans that don't affect metrics can
   * be ignored). Neither should the run direction change in the middle of the run.
   *
   * <p>
   *
   * <p>The x position is the leading edge of the text. In a right-to-left paragraph, this will be
   * to the right of the text to be drawn. Paint should not have an Align value other than LEFT or
   * positioning will isCancelled confused.
   *
   * <p>
   *
   * <p>On return, workPaint will reflect the original paint plus any modifications made by
   * character styles on the run.
   *
   * <p>
   *
   * <p>The returned width is signed and will be < 0 if the paragraph direction is right-to-left.
   */
  private static float drawUniformRun(
      Canvas canvas,
      Spanned text,
      int start,
      int end,
      int dir,
      boolean runIsRtl,
      float x,
      int top,
      int y,
      int bottom,
      Paint.FontMetricsInt fmi,
      TextPaint paint,
      TextPaint workPaint,
      boolean needWidth) {

    boolean haveWidth = false;
    float ret = 0;
    CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);

    ReplacementSpan replacement = null;

    // XXX: This shouldn't be modifying paint, only workPaint.
    // However, the members belonging to TextPaint should have default
    // values anyway.  Better to ensure this in the Layout constructor.
    paint.bgColor = 0;
    paint.baselineShift = 0;
    workPaint.set(paint);

    if (spans.length > 0) {
      for (CharacterStyle span : spans) {
        if (span instanceof ReplacementSpan) {
          replacement = (ReplacementSpan) span;
        } else {
          span.updateDrawState(workPaint);
        }
      }
    }

    if (replacement == null) {
      CharSequence tmp;
      int tmpstart, tmpend;

      if (runIsRtl) {
        tmp = TextUtils.getReverse(text, start, end);
        tmpstart = 0;
        // XXX: assumes getReverse doesn't change the length of the text
        tmpend = end - start;
      } else {
        tmp = text;
        tmpstart = start;
        tmpend = end;
      }

      if (fmi != null) {
        workPaint.getFontMetricsInt(fmi);
      }

      if (canvas != null) {
        if (workPaint.bgColor != 0) {
          int c = workPaint.getColor();
          Paint.Style s = workPaint.getStyle();
          workPaint.setColor(workPaint.bgColor);
          workPaint.setStyle(Paint.Style.FILL);

          if (!haveWidth) {
            ret = workPaint.measureText(tmp, tmpstart, tmpend);
            haveWidth = true;
          }

          if (dir == Layout.DIR_RIGHT_TO_LEFT) {
            canvas.drawRect(x - ret, top, x, bottom, workPaint);
          } else {
            canvas.drawRect(x, top, x + ret, bottom, workPaint);
          }

          workPaint.setStyle(s);
          workPaint.setColor(c);
        }

        if (dir == Layout.DIR_RIGHT_TO_LEFT) {
          if (!haveWidth) {
            ret = workPaint.measureText(tmp, tmpstart, tmpend);
            haveWidth = true;
          }

          canvas.drawText(tmp, tmpstart, tmpend, x - ret, y + workPaint.baselineShift, workPaint);
        } else {
          if (needWidth) {
            if (!haveWidth) {
              ret = workPaint.measureText(tmp, tmpstart, tmpend);
              haveWidth = true;
            }
          }

          canvas.drawText(tmp, tmpstart, tmpend, x, y + workPaint.baselineShift, workPaint);
        }
      } else {
        if (needWidth && !haveWidth) {
          ret = workPaint.measureText(tmp, tmpstart, tmpend);
          haveWidth = true;
        }
      }
    } else {
      ret = replacement.getSize(workPaint, text, start, end, fmi);

      if (canvas != null) {
        if (dir == Layout.DIR_RIGHT_TO_LEFT) {
          replacement.draw(canvas, text, start, end, x - ret, top, y, bottom, workPaint);
        } else {
          replacement.draw(canvas, text, start, end, x, top, y, bottom, workPaint);
        }
      }
    }

    if (dir == Layout.DIR_RIGHT_TO_LEFT) {
      return -ret;
    } else {
      return ret;
    }
  }
 @Override
 public void updateDrawState(@NonNull TextPaint tp) {
   initIfNecessary(tp.ascent());
   tp.baselineShift = shift;
 }