2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.graphics;
19 import android.text.SpannableString;
20 import android.text.SpannableStringBuilder;
21 import android.text.SpannedString;
22 import android.text.TextUtils;
24 import java.awt.BasicStroke;
26 import java.awt.Toolkit;
27 import java.awt.font.FontRenderContext;
28 import java.awt.geom.AffineTransform;
29 import java.awt.geom.Rectangle2D;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
35 * A paint implementation overridden by the LayoutLib bridge.
37 public class Paint extends _Original_Paint {
39 private int mColor = 0xFFFFFFFF;
40 private float mStrokeWidth = 1.f;
41 private float mTextSize = 20;
42 private float mScaleX = 1;
43 private float mSkewX = 0;
44 private Align mAlign = Align.LEFT;
45 private Style mStyle = Style.FILL;
46 private float mStrokeMiter = 4.0f;
47 private Cap mCap = Cap.BUTT;
48 private Join mJoin = Join.MITER;
49 private int mFlags = 0;
52 * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
54 public static final class FontInfo {
56 java.awt.FontMetrics mMetrics;
59 private List<FontInfo> mFonts;
60 private final FontRenderContext mFontContext = new FontRenderContext(
61 new AffineTransform(), true, true);
63 public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
64 public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG;
65 public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG;
66 public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG;
67 public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
68 public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
69 public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG;
70 public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG;
71 public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
73 public static class FontMetrics extends _Original_Paint.FontMetrics {
76 public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
80 * The Style specifies if the primitive being drawn is filled,
81 * stroked, or both (in the same color). The default is FILL.
85 * Geometry and text drawn with this style will be filled, ignoring all
86 * stroke-related settings in the paint.
90 * Geometry and text drawn with this style will be stroked, respecting
91 * the stroke-related fields on the paint.
95 * Geometry and text drawn with this style will be both filled and
96 * stroked at the same time, respecting the stroke-related fields on
101 Style(int nativeInt) {
102 this.nativeInt = nativeInt;
108 * The Cap specifies the treatment for the beginning and ending of
109 * stroked lines and paths. The default is BUTT.
113 * The stroke ends with the path, and does not project beyond it.
117 * The stroke projects out as a square, with the center at the end
122 * The stroke projects out as a semicircle, with the center at the
127 private Cap(int nativeInt) {
128 this.nativeInt = nativeInt;
132 /** custom for layoutlib */
133 public int getJavaCap() {
136 return BasicStroke.CAP_BUTT;
138 return BasicStroke.CAP_ROUND;
141 return BasicStroke.CAP_SQUARE;
147 * The Join specifies the treatment where lines and curve segments
148 * join on a stroked path. The default is MITER.
152 * The outer edges of a join meet at a sharp angle
156 * The outer edges of a join meet in a circular arc.
160 * The outer edges of a join meet with a straight line
164 private Join(int nativeInt) {
165 this.nativeInt = nativeInt;
169 /** custom for layoutlib */
170 public int getJavaJoin() {
174 return BasicStroke.JOIN_MITER;
176 return BasicStroke.JOIN_ROUND;
178 return BasicStroke.JOIN_BEVEL;
184 * Align specifies how drawText aligns its text relative to the
185 * [x,y] coordinates. The default is LEFT.
189 * The text is drawn to the right of the x,y origin
193 * The text is drawn centered horizontally on the x,y origin
197 * The text is drawn to the left of the x,y origin
201 private Align(int nativeInt) {
202 this.nativeInt = nativeInt;
211 public Paint(int flags) {
212 setFlags(flags | DEFAULT_PAINT_FLAGS);
216 public Paint(Paint paint) {
222 public void finalize() throws Throwable {
227 public void reset() {
232 * Returns the list of {@link Font} objects. The first item is the main font, the rest
233 * are fall backs for characters not present in the main font.
235 public List<FontInfo> getFonts() {
239 private void initFont() {
240 mTypeface = Typeface.DEFAULT;
245 * Update the {@link Font} object from the typeface, text size and scaling
247 @SuppressWarnings("deprecation")
248 private void updateFontObject() {
249 if (mTypeface != null) {
250 // Get the fonts from the TypeFace object.
251 List<Font> fonts = mTypeface.getFonts();
253 // create new font objects as well as FontMetrics, based on the current text size
255 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
256 for (Font font : fonts) {
257 FontInfo info = new FontInfo();
258 info.mFont = font.deriveFont(mTextSize);
259 if (mScaleX != 1.0 || mSkewX != 0) {
260 // TODO: support skew
261 info.mFont = info.mFont.deriveFont(new AffineTransform(
262 mScaleX, mSkewX, 0, 0, 1, 0));
264 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
269 mFonts = Collections.unmodifiableList(infoList);
273 //----------------------------------------
275 public void set(Paint src) {
278 mTextSize = src.mTextSize;
279 mScaleX = src.mScaleX;
290 public void setCompatibilityScaling(float factor) {
291 super.setCompatibilityScaling(factor);
295 public int getFlags() {
300 public void setFlags(int flags) {
305 public boolean isAntiAlias() {
306 return super.isAntiAlias();
310 public boolean isDither() {
311 return super.isDither();
315 public boolean isLinearText() {
316 return super.isLinearText();
320 public boolean isStrikeThruText() {
321 return super.isStrikeThruText();
325 public boolean isUnderlineText() {
326 return super.isUnderlineText();
330 public boolean isFakeBoldText() {
331 return super.isFakeBoldText();
335 public boolean isSubpixelText() {
336 return super.isSubpixelText();
340 public boolean isFilterBitmap() {
341 return super.isFilterBitmap();
345 * Return the font's recommended interline spacing, given the Paint's
346 * settings for typeface, textSize, etc. If metrics is not null, return the
347 * fontmetric values in it.
349 * @param metrics If this object is not null, its fields are filled with
350 * the appropriate values given the paint's text attributes.
351 * @return the font's recommended interline spacing.
353 public float getFontMetrics(FontMetrics metrics) {
354 if (mFonts.size() > 0) {
355 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
356 if (metrics != null) {
357 // Android expects negative ascent so we invert the value from Java.
358 metrics.top = - javaMetrics.getMaxAscent();
359 metrics.ascent = - javaMetrics.getAscent();
360 metrics.descent = javaMetrics.getDescent();
361 metrics.bottom = javaMetrics.getMaxDescent();
362 metrics.leading = javaMetrics.getLeading();
365 return javaMetrics.getHeight();
371 public int getFontMetricsInt(FontMetricsInt metrics) {
372 if (mFonts.size() > 0) {
373 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
374 if (metrics != null) {
375 // Android expects negative ascent so we invert the value from Java.
376 metrics.top = - javaMetrics.getMaxAscent();
377 metrics.ascent = - javaMetrics.getAscent();
378 metrics.descent = javaMetrics.getDescent();
379 metrics.bottom = javaMetrics.getMaxDescent();
380 metrics.leading = javaMetrics.getLeading();
383 return javaMetrics.getHeight();
390 * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
392 public FontMetrics getFontMetrics() {
393 FontMetrics fm = new FontMetrics();
399 * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
401 public FontMetricsInt getFontMetricsInt() {
402 FontMetricsInt fm = new FontMetricsInt();
403 getFontMetricsInt(fm);
410 public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
411 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
415 public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
416 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
420 public Typeface setTypeface(Typeface typeface) {
421 if (typeface != null) {
422 mTypeface = typeface;
424 mTypeface = Typeface.DEFAULT;
433 public Typeface getTypeface() {
434 return super.getTypeface();
438 public int getColor() {
443 public void setColor(int color) {
448 public void setARGB(int a, int r, int g, int b) {
449 super.setARGB(a, r, g, b);
453 public void setAlpha(int alpha) {
454 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
458 public int getAlpha() {
459 return mColor >>> 24;
463 * Set or clear the shader object.
465 * Pass null to clear any previous shader.
466 * As a convenience, the parameter passed is also returned.
468 * @param shader May be null. the new shader to be installed in the paint
472 public Shader setShader(Shader shader) {
473 return mShader = shader;
477 public Shader getShader() {
478 return super.getShader();
482 * Set or clear the paint's colorfilter, returning the parameter.
484 * @param filter May be null. The new filter to be installed in the paint
488 public ColorFilter setColorFilter(ColorFilter filter) {
489 mColorFilter = filter;
494 public ColorFilter getColorFilter() {
495 return super.getColorFilter();
499 * Set or clear the xfermode object.
501 * Pass null to clear any previous xfermode.
502 * As a convenience, the parameter passed is also returned.
504 * @param xfermode May be null. The xfermode to be installed in the paint
508 public Xfermode setXfermode(Xfermode xfermode) {
509 return mXfermode = xfermode;
513 public Xfermode getXfermode() {
514 return super.getXfermode();
518 public Rasterizer setRasterizer(Rasterizer rasterizer) {
519 mRasterizer = rasterizer;
524 public Rasterizer getRasterizer() {
525 return super.getRasterizer();
529 public void setShadowLayer(float radius, float dx, float dy, int color) {
530 // TODO Auto-generated method stub
534 public void clearShadowLayer() {
535 super.clearShadowLayer();
538 public void setTextAlign(Align align) {
543 public void setTextAlign(android.graphics._Original_Paint.Align align) {
544 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
547 public Align getTextAlign() {
551 public void setStyle(Style style) {
556 public void setStyle(android.graphics._Original_Paint.Style style) {
557 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
560 public Style getStyle() {
565 public void setDither(boolean dither) {
566 mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
570 public void setAntiAlias(boolean aa) {
571 mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
575 public void setFakeBoldText(boolean flag) {
576 mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
580 public void setLinearText(boolean flag) {
581 mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
585 public void setSubpixelText(boolean flag) {
586 mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
590 public void setUnderlineText(boolean flag) {
591 mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
595 public void setStrikeThruText(boolean flag) {
596 mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
600 public void setFilterBitmap(boolean flag) {
601 mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
605 public float getStrokeWidth() {
610 public void setStrokeWidth(float width) {
611 mStrokeWidth = width;
615 public float getStrokeMiter() {
620 public void setStrokeMiter(float miter) {
621 mStrokeMiter = miter;
625 public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
626 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
629 public void setStrokeCap(Cap cap) {
633 public Cap getStrokeCap() {
638 public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
639 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
642 public void setStrokeJoin(Join join) {
646 public Join getStrokeJoin() {
651 public boolean getFillPath(Path src, Path dst) {
652 return super.getFillPath(src, dst);
656 public PathEffect setPathEffect(PathEffect effect) {
657 mPathEffect = effect;
662 public PathEffect getPathEffect() {
663 return super.getPathEffect();
667 public MaskFilter setMaskFilter(MaskFilter maskfilter) {
668 mMaskFilter = maskfilter;
673 public MaskFilter getMaskFilter() {
674 return super.getMaskFilter();
678 * Return the paint's text size.
680 * @return the paint's text size.
683 public float getTextSize() {
688 * Set the paint's text size. This value must be > 0
690 * @param textSize set the paint's text size.
693 public void setTextSize(float textSize) {
694 mTextSize = textSize;
700 * Return the paint's horizontal scale factor for text. The default value
703 * @return the paint's scale factor in X for drawing/measuring text
706 public float getTextScaleX() {
711 * Set the paint's horizontal scale factor for text. The default value
712 * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
713 * stretch the text narrower.
715 * @param scaleX set the paint's scale in X for drawing/measuring text.
718 public void setTextScaleX(float scaleX) {
725 * Return the paint's horizontal skew factor for text. The default value
728 * @return the paint's skew factor in X for drawing text.
731 public float getTextSkewX() {
736 * Set the paint's horizontal skew factor for text. The default value
737 * is 0. For approximating oblique text, use values around -0.25.
739 * @param skewX set the paint's skew factor in X for drawing text.
742 public void setTextSkewX(float skewX) {
749 public float getFontSpacing() {
750 return super.getFontSpacing();
754 * Return the distance above (negative) the baseline (ascent) based on the
755 * current typeface and text size.
757 * @return the distance above (negative) the baseline (ascent) based on the
758 * current typeface and text size.
761 public float ascent() {
762 if (mFonts.size() > 0) {
763 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
764 // Android expects negative ascent so we invert the value from Java.
765 return - javaMetrics.getAscent();
772 * Return the distance below (positive) the baseline (descent) based on the
773 * current typeface and text size.
775 * @return the distance below (positive) the baseline (descent) based on
776 * the current typeface and text size.
779 public float descent() {
780 if (mFonts.size() > 0) {
781 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
782 return javaMetrics.getDescent();
789 * Return the width of the text.
791 * @param text The text to measure
792 * @param index The index of the first character to start measuring
793 * @param count THe number of characters to measure, beginning with start
794 * @return The width of the text
797 public float measureText(char[] text, int index, int count) {
798 // WARNING: the logic in this method is similar to Canvas.drawText.
799 // Any change to this method should be reflected in Canvas.drawText
800 if (mFonts.size() > 0) {
801 FontInfo mainFont = mFonts.get(0);
803 int lastIndex = index + count;
805 while (i < lastIndex) {
806 // always start with the main font.
807 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
810 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
811 } else if (upTo > 0) {
812 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
814 // don't call continue at this point. Since it is certain the main font
815 // cannot display the font a index upTo (now ==i), we move on to the
816 // fallback fonts directly.
819 // no char supported, attempt to read the next char(s) with the
820 // fallback font. In this case we only test the first character
821 // and then go back to test with the main font.
822 // Special test for 2-char characters.
823 boolean foundFont = false;
824 for (int f = 1 ; f < mFonts.size() ; f++) {
825 FontInfo fontInfo = mFonts.get(f);
827 // need to check that the font can display the character. We test
828 // differently if the char is a high surrogate.
829 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
830 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
832 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
840 // in case no font can display the char, measure it with the main font.
841 if (foundFont == false) {
842 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
843 total += mainFont.mMetrics.charsWidth(text, i, size);
853 * Return the width of the text.
855 * @param text The text to measure
856 * @param start The index of the first character to start measuring
857 * @param end 1 beyond the index of the last character to measure
858 * @return The width of the text
861 public float measureText(String text, int start, int end) {
862 return measureText(text.toCharArray(), start, end - start);
866 * Return the width of the text.
868 * @param text The text to measure
869 * @return The width of the text
872 public float measureText(String text) {
873 return measureText(text.toCharArray(), 0, text.length());
877 * re-implement to call SpannableStringBuilder.measureText with a Paint object
878 * instead of an _Original_Paint
881 public float measureText(CharSequence text, int start, int end) {
882 if (text instanceof String) {
883 return measureText((String)text, start, end);
885 if (text instanceof SpannedString ||
886 text instanceof SpannableString) {
887 return measureText(text.toString(), start, end);
889 if (text instanceof SpannableStringBuilder) {
890 return ((SpannableStringBuilder)text).measureText(start, end, this);
893 char[] buf = TemporaryBuffer.obtain(end - start);
894 TextUtils.getChars(text, start, end, buf, 0);
895 float result = measureText(buf, 0, end - start);
896 TemporaryBuffer.recycle(buf);
901 * Measure the text, stopping early if the measured width exceeds maxWidth.
902 * Return the number of chars that were measured, and if measuredWidth is
903 * not null, return in it the actual width measured.
905 * @param text The text to measure
906 * @param index The offset into text to begin measuring at
907 * @param count The number of maximum number of entries to measure. If count
908 * is negative, then the characters before index are measured
909 * in reverse order. This allows for measuring the end of
911 * @param maxWidth The maximum width to accumulate.
912 * @param measuredWidth Optional. If not null, returns the actual width
914 * @return The number of chars that were measured. Will always be <=
918 public int breakText(char[] text, int index, int count,
919 float maxWidth, float[] measuredWidth) {
920 int inc = count > 0 ? 1 : -1;
922 int measureIndex = 0;
923 float measureAcc = 0;
924 for (int i = index ; i != index + count ; i += inc, measureIndex++) {
934 // measure from start to end
935 float res = measureText(text, start, end - start + 1);
937 if (measuredWidth != null) {
938 measuredWidth[measureIndex] = res;
942 if (res > maxWidth) {
943 // we should not return this char index, but since it's 0-based and we need
944 // to return a count, we simply return measureIndex;
954 * Measure the text, stopping early if the measured width exceeds maxWidth.
955 * Return the number of chars that were measured, and if measuredWidth is
956 * not null, return in it the actual width measured.
958 * @param text The text to measure
959 * @param measureForwards If true, measure forwards, starting at index.
960 * Otherwise, measure backwards, starting with the
961 * last character in the string.
962 * @param maxWidth The maximum width to accumulate.
963 * @param measuredWidth Optional. If not null, returns the actual width
965 * @return The number of chars that were measured. Will always be <=
969 public int breakText(String text, boolean measureForwards,
970 float maxWidth, float[] measuredWidth) {
971 return breakText(text,
972 0 /* start */, text.length() /* end */,
973 measureForwards, maxWidth, measuredWidth);
977 * Measure the text, stopping early if the measured width exceeds maxWidth.
978 * Return the number of chars that were measured, and if measuredWidth is
979 * not null, return in it the actual width measured.
981 * @param text The text to measure
982 * @param start The offset into text to begin measuring at
983 * @param end The end of the text slice to measure.
984 * @param measureForwards If true, measure forwards, starting at start.
985 * Otherwise, measure backwards, starting with end.
986 * @param maxWidth The maximum width to accumulate.
987 * @param measuredWidth Optional. If not null, returns the actual width
989 * @return The number of chars that were measured. Will always be <=
993 public int breakText(CharSequence text, int start, int end, boolean measureForwards,
994 float maxWidth, float[] measuredWidth) {
995 char[] buf = new char[end - start];
998 TextUtils.getChars(text, start, end, buf, 0);
1000 if (measureForwards) {
1001 result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
1003 result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
1010 * Return the advance widths for the characters in the string.
1012 * @param text The text to measure
1013 * @param index The index of the first char to to measure
1014 * @param count The number of chars starting with index to measure
1015 * @param widths array to receive the advance widths of the characters.
1016 * Must be at least a large as count.
1017 * @return the actual number of widths returned.
1020 public int getTextWidths(char[] text, int index, int count,
1022 if (mFonts.size() > 0) {
1023 if ((index | count) < 0 || index + count > text.length
1024 || count > widths.length) {
1025 throw new ArrayIndexOutOfBoundsException();
1028 // FIXME: handle multi-char characters.
1029 // Need to figure out if the lengths of the width array takes into account
1030 // multi-char characters.
1031 for (int i = 0; i < count; i++) {
1032 char c = text[i + index];
1033 boolean found = false;
1034 for (FontInfo info : mFonts) {
1035 if (info.mFont.canDisplay(c)) {
1036 widths[i] = info.mMetrics.charWidth(c);
1042 if (found == false) {
1055 * Return the advance widths for the characters in the string.
1057 * @param text The text to measure
1058 * @param start The index of the first char to to measure
1059 * @param end The end of the text slice to measure
1060 * @param widths array to receive the advance widths of the characters.
1061 * Must be at least a large as the text.
1062 * @return the number of unichars in the specified text.
1065 public int getTextWidths(String text, int start, int end, float[] widths) {
1066 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1067 throw new IndexOutOfBoundsException();
1069 if (end - start > widths.length) {
1070 throw new ArrayIndexOutOfBoundsException();
1073 return getTextWidths(text.toCharArray(), start, end - start, widths);
1077 * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
1078 * instead of an _Original_Paint
1081 public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
1082 if (text instanceof String) {
1083 return getTextWidths((String)text, start, end, widths);
1085 if (text instanceof SpannedString || text instanceof SpannableString) {
1086 return getTextWidths(text.toString(), start, end, widths);
1088 if (text instanceof SpannableStringBuilder) {
1089 return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
1092 char[] buf = TemporaryBuffer.obtain(end - start);
1093 TextUtils.getChars(text, start, end, buf, 0);
1094 int result = getTextWidths(buf, 0, end - start, widths);
1095 TemporaryBuffer.recycle(buf);
1100 public int getTextWidths(String text, float[] widths) {
1101 return super.getTextWidths(text, widths);
1105 * Return the path (outline) for the specified text.
1106 * Note: just like Canvas.drawText, this will respect the Align setting in
1109 * @param text The text to retrieve the path from
1110 * @param index The index of the first character in text
1111 * @param count The number of characterss starting with index
1112 * @param x The x coordinate of the text's origin
1113 * @param y The y coordinate of the text's origin
1114 * @param path The path to receive the data describing the text. Must
1115 * be allocated by the caller.
1118 public void getTextPath(char[] text, int index, int count,
1119 float x, float y, Path path) {
1121 // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
1123 if ((index | count) < 0 || index + count > text.length) {
1124 throw new ArrayIndexOutOfBoundsException();
1127 // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
1129 throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
1133 * Return the path (outline) for the specified text.
1134 * Note: just like Canvas.drawText, this will respect the Align setting
1137 * @param text The text to retrieve the path from
1138 * @param start The first character in the text
1139 * @param end 1 past the last charcter in the text
1140 * @param x The x coordinate of the text's origin
1141 * @param y The y coordinate of the text's origin
1142 * @param path The path to receive the data describing the text. Must
1143 * be allocated by the caller.
1146 public void getTextPath(String text, int start, int end,
1147 float x, float y, Path path) {
1148 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1149 throw new IndexOutOfBoundsException();
1152 getTextPath(text.toCharArray(), start, end - start, x, y, path);
1156 * Return in bounds (allocated by the caller) the smallest rectangle that
1157 * encloses all of the characters, with an implied origin at (0,0).
1159 * @param text String to measure and return its bounds
1160 * @param start Index of the first char in the string to measure
1161 * @param end 1 past the last char in the string measure
1162 * @param bounds Returns the unioned bounds of all the text. Must be
1163 * allocated by the caller.
1166 public void getTextBounds(String text, int start, int end, Rect bounds) {
1167 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1168 throw new IndexOutOfBoundsException();
1170 if (bounds == null) {
1171 throw new NullPointerException("need bounds Rect");
1174 getTextBounds(text.toCharArray(), start, end - start, bounds);
1178 * Return in bounds (allocated by the caller) the smallest rectangle that
1179 * encloses all of the characters, with an implied origin at (0,0).
1181 * @param text Array of chars to measure and return their unioned bounds
1182 * @param index Index of the first char in the array to measure
1183 * @param count The number of chars, beginning at index, to measure
1184 * @param bounds Returns the unioned bounds of all the text. Must be
1185 * allocated by the caller.
1188 public void getTextBounds(char[] text, int index, int count, Rect bounds) {
1190 if (mFonts.size() > 0) {
1191 if ((index | count) < 0 || index + count > text.length) {
1192 throw new ArrayIndexOutOfBoundsException();
1194 if (bounds == null) {
1195 throw new NullPointerException("need bounds Rect");
1198 FontInfo mainInfo = mFonts.get(0);
1200 Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
1201 bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
1205 public static void finalizer(int foo) {