Exemplo n.º 1
0
  /**
   * Returns information about a position on the line.
   *
   * @param offset the line-relative character offset, between 0 and the line length, inclusive
   * @param trailing true to measure the trailing edge of the character before offset, false to
   *     measure the leading edge of the character at offset.
   * @param fmi receives metrics information about the requested character, can be null.
   * @return the signed offset from the leading margin to the requested character edge.
   */
  float measure(int offset, boolean trailing, FontMetricsInt fmi) {
    int target = trailing ? offset - 1 : offset;
    if (target < 0) {
      return 0;
    }

    float h = 0;

    if (!mHasTabs) {
      if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
        return measureRun(0, offset, mLen, false, fmi);
      }
      if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
        return measureRun(0, offset, mLen, true, fmi);
      }
    }

    char[] chars = mChars;
    int[] runs = mDirections.mDirections;
    for (int i = 0; i < runs.length; i += 2) {
      int runStart = runs[i];
      int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
      if (runLimit > mLen) {
        runLimit = mLen;
      }
      boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;

      int segstart = runStart;
      for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
        int codept = 0;
        Bitmap bm = null;

        if (mHasTabs && j < runLimit) {
          codept = chars[j];
          if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) {
            codept = Character.codePointAt(chars, j);
            if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) {
              bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
            } else if (codept > 0xffff) {
              ++j;
              continue;
            }
          }
        }

        if (j == runLimit || codept == '\t' || bm != null) {
          boolean inSegment = target >= segstart && target < j;

          boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
          if (inSegment && advance) {
            return h += measureRun(segstart, offset, j, runIsRtl, fmi);
          }

          float w = measureRun(segstart, j, j, runIsRtl, fmi);
          h += advance ? w : -w;

          if (inSegment) {
            return h += measureRun(segstart, offset, j, runIsRtl, null);
          }

          if (codept == '\t') {
            if (offset == j) {
              return h;
            }
            h = mDir * nextTab(h * mDir);
            if (target == j) {
              return h;
            }
          }

          if (bm != null) {
            float bmAscent = ascent(j);
            float wid = bm.getWidth() * -bmAscent / bm.getHeight();
            h += mDir * wid;
            j++;
          }

          segstart = j + 1;
        }
      }
    }

    return h;
  }
Exemplo n.º 2
0
  /**
   * Renders the TextLine.
   *
   * @param c the canvas to render on
   * @param x the leading margin position
   * @param top the top of the line
   * @param y the baseline
   * @param bottom the bottom of the line
   */
  void draw(Canvas c, float x, int top, int y, int bottom) {
    if (!mHasTabs) {
      if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
        drawRun(c, 0, mLen, false, x, top, y, bottom, false);
        return;
      }
      if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
        drawRun(c, 0, mLen, true, x, top, y, bottom, false);
        return;
      }
    }

    float h = 0;
    int[] runs = mDirections.mDirections;
    RectF emojiRect = null;

    int lastRunIndex = runs.length - 2;
    for (int i = 0; i < runs.length; i += 2) {
      int runStart = runs[i];
      int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
      if (runLimit > mLen) {
        runLimit = mLen;
      }
      boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;

      int segstart = runStart;
      for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; j++) {
        int codept = 0;
        Bitmap bm = null;

        if (mHasTabs && j < runLimit) {
          codept = mChars[j];
          if (codept >= 0xd800 && codept < 0xdc00 && j + 1 < runLimit) {
            codept = Character.codePointAt(mChars, j);
            if (codept >= Layout.MIN_EMOJI && codept <= Layout.MAX_EMOJI) {
              bm = Layout.EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
            } else if (codept > 0xffff) {
              ++j;
              continue;
            }
          }
        }

        if (j == runLimit || codept == '\t' || bm != null) {
          h +=
              drawRun(
                  c, segstart, j, runIsRtl, x + h, top, y, bottom, i != lastRunIndex || j != mLen);

          if (codept == '\t') {
            h = mDir * nextTab(h * mDir);
          } else if (bm != null) {
            float bmAscent = ascent(j);
            float bitmapHeight = bm.getHeight();
            float scale = -bmAscent / bitmapHeight;
            float width = bm.getWidth() * scale;

            if (emojiRect == null) {
              emojiRect = new RectF();
            }
            emojiRect.set(x + h, y + bmAscent, x + h + width, y);
            c.drawBitmap(bm, null, emojiRect, mPaint);
            h += width;
            j++;
          }
          segstart = j + 1;
        }
      }
    }
  }