/** * 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; }
/** * 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; } } } }