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 reset() {
227 * Returns the list of {@link Font} objects. The first item is the main font, the rest
228 * are fall backs for characters not present in the main font.
230 public List<FontInfo> getFonts() {
234 private void initFont() {
235 mTypeface = Typeface.DEFAULT;
240 * Update the {@link Font} object from the typeface, text size and scaling
242 @SuppressWarnings("deprecation")
243 private void updateFontObject() {
244 if (mTypeface != null) {
245 // Get the fonts from the TypeFace object.
246 List<Font> fonts = mTypeface.getFonts();
248 // create new font objects as well as FontMetrics, based on the current text size
250 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
251 for (Font font : fonts) {
252 FontInfo info = new FontInfo();
253 info.mFont = font.deriveFont(mTextSize);
254 if (mScaleX != 1.0 || mSkewX != 0) {
255 // TODO: support skew
256 info.mFont = info.mFont.deriveFont(new AffineTransform(
257 mScaleX, mSkewX, 0, 0, 1, 0));
259 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
264 mFonts = Collections.unmodifiableList(infoList);
268 //----------------------------------------
270 public void set(Paint src) {
273 mTextSize = src.mTextSize;
274 mScaleX = src.mScaleX;
285 public void setCompatibilityScaling(float factor) {
286 super.setCompatibilityScaling(factor);
290 public int getFlags() {
295 public void setFlags(int flags) {
300 public boolean isAntiAlias() {
301 return super.isAntiAlias();
305 public boolean isDither() {
306 return super.isDither();
310 public boolean isLinearText() {
311 return super.isLinearText();
315 public boolean isStrikeThruText() {
316 return super.isStrikeThruText();
320 public boolean isUnderlineText() {
321 return super.isUnderlineText();
325 public boolean isFakeBoldText() {
326 return super.isFakeBoldText();
330 public boolean isSubpixelText() {
331 return super.isSubpixelText();
335 public boolean isFilterBitmap() {
336 return super.isFilterBitmap();
340 * Return the font's recommended interline spacing, given the Paint's
341 * settings for typeface, textSize, etc. If metrics is not null, return the
342 * fontmetric values in it.
344 * @param metrics If this object is not null, its fields are filled with
345 * the appropriate values given the paint's text attributes.
346 * @return the font's recommended interline spacing.
348 public float getFontMetrics(FontMetrics metrics) {
349 if (mFonts.size() > 0) {
350 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
351 if (metrics != null) {
352 // Android expects negative ascent so we invert the value from Java.
353 metrics.top = - javaMetrics.getMaxAscent();
354 metrics.ascent = - javaMetrics.getAscent();
355 metrics.descent = javaMetrics.getDescent();
356 metrics.bottom = javaMetrics.getMaxDescent();
357 metrics.leading = javaMetrics.getLeading();
360 return javaMetrics.getHeight();
366 public int getFontMetricsInt(FontMetricsInt metrics) {
367 if (mFonts.size() > 0) {
368 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
369 if (metrics != null) {
370 // Android expects negative ascent so we invert the value from Java.
371 metrics.top = - javaMetrics.getMaxAscent();
372 metrics.ascent = - javaMetrics.getAscent();
373 metrics.descent = javaMetrics.getDescent();
374 metrics.bottom = javaMetrics.getMaxDescent();
375 metrics.leading = javaMetrics.getLeading();
378 return javaMetrics.getHeight();
385 * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
387 public FontMetrics getFontMetrics() {
388 FontMetrics fm = new FontMetrics();
394 * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
396 public FontMetricsInt getFontMetricsInt() {
397 FontMetricsInt fm = new FontMetricsInt();
398 getFontMetricsInt(fm);
405 public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
406 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
410 public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
411 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
415 public Typeface setTypeface(Typeface typeface) {
416 if (typeface != null) {
417 mTypeface = typeface;
419 mTypeface = Typeface.DEFAULT;
428 public Typeface getTypeface() {
429 return super.getTypeface();
433 public int getColor() {
438 public void setColor(int color) {
443 public void setARGB(int a, int r, int g, int b) {
444 super.setARGB(a, r, g, b);
448 public void setAlpha(int alpha) {
449 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
453 public int getAlpha() {
454 return mColor >>> 24;
458 * Set or clear the shader object.
460 * Pass null to clear any previous shader.
461 * As a convenience, the parameter passed is also returned.
463 * @param shader May be null. the new shader to be installed in the paint
467 public Shader setShader(Shader shader) {
468 return mShader = shader;
472 public Shader getShader() {
473 return super.getShader();
477 * Set or clear the paint's colorfilter, returning the parameter.
479 * @param filter May be null. The new filter to be installed in the paint
483 public ColorFilter setColorFilter(ColorFilter filter) {
484 mColorFilter = filter;
489 public ColorFilter getColorFilter() {
490 return super.getColorFilter();
494 * Set or clear the xfermode object.
496 * Pass null to clear any previous xfermode.
497 * As a convenience, the parameter passed is also returned.
499 * @param xfermode May be null. The xfermode to be installed in the paint
503 public Xfermode setXfermode(Xfermode xfermode) {
504 return mXfermode = xfermode;
508 public Xfermode getXfermode() {
509 return super.getXfermode();
513 public Rasterizer setRasterizer(Rasterizer rasterizer) {
514 mRasterizer = rasterizer;
519 public Rasterizer getRasterizer() {
520 return super.getRasterizer();
524 public void setShadowLayer(float radius, float dx, float dy, int color) {
525 // TODO Auto-generated method stub
529 public void clearShadowLayer() {
530 super.clearShadowLayer();
533 public void setTextAlign(Align align) {
538 public void setTextAlign(android.graphics._Original_Paint.Align align) {
539 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
542 public Align getTextAlign() {
546 public void setStyle(Style style) {
551 public void setStyle(android.graphics._Original_Paint.Style style) {
552 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
555 public Style getStyle() {
560 public void setDither(boolean dither) {
561 mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
565 public void setAntiAlias(boolean aa) {
566 mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
570 public void setFakeBoldText(boolean flag) {
571 mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
575 public void setLinearText(boolean flag) {
576 mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
580 public void setSubpixelText(boolean flag) {
581 mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
585 public void setUnderlineText(boolean flag) {
586 mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
590 public void setStrikeThruText(boolean flag) {
591 mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
595 public void setFilterBitmap(boolean flag) {
596 mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
600 public float getStrokeWidth() {
605 public void setStrokeWidth(float width) {
606 mStrokeWidth = width;
610 public float getStrokeMiter() {
615 public void setStrokeMiter(float miter) {
616 mStrokeMiter = miter;
620 public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
621 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
624 public void setStrokeCap(Cap cap) {
628 public Cap getStrokeCap() {
633 public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
634 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
637 public void setStrokeJoin(Join join) {
641 public Join getStrokeJoin() {
646 public boolean getFillPath(Path src, Path dst) {
647 return super.getFillPath(src, dst);
651 public PathEffect setPathEffect(PathEffect effect) {
652 mPathEffect = effect;
657 public PathEffect getPathEffect() {
658 return super.getPathEffect();
662 public MaskFilter setMaskFilter(MaskFilter maskfilter) {
663 mMaskFilter = maskfilter;
668 public MaskFilter getMaskFilter() {
669 return super.getMaskFilter();
673 * Return the paint's text size.
675 * @return the paint's text size.
678 public float getTextSize() {
683 * Set the paint's text size. This value must be > 0
685 * @param textSize set the paint's text size.
688 public void setTextSize(float textSize) {
689 mTextSize = textSize;
695 * Return the paint's horizontal scale factor for text. The default value
698 * @return the paint's scale factor in X for drawing/measuring text
701 public float getTextScaleX() {
706 * Set the paint's horizontal scale factor for text. The default value
707 * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
708 * stretch the text narrower.
710 * @param scaleX set the paint's scale in X for drawing/measuring text.
713 public void setTextScaleX(float scaleX) {
720 * Return the paint's horizontal skew factor for text. The default value
723 * @return the paint's skew factor in X for drawing text.
726 public float getTextSkewX() {
731 * Set the paint's horizontal skew factor for text. The default value
732 * is 0. For approximating oblique text, use values around -0.25.
734 * @param skewX set the paint's skew factor in X for drawing text.
737 public void setTextSkewX(float skewX) {
744 public float getFontSpacing() {
745 return super.getFontSpacing();
749 * Return the distance above (negative) the baseline (ascent) based on the
750 * current typeface and text size.
752 * @return the distance above (negative) the baseline (ascent) based on the
753 * current typeface and text size.
756 public float ascent() {
757 if (mFonts.size() > 0) {
758 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
759 // Android expects negative ascent so we invert the value from Java.
760 return - javaMetrics.getAscent();
767 * Return the distance below (positive) the baseline (descent) based on the
768 * current typeface and text size.
770 * @return the distance below (positive) the baseline (descent) based on
771 * the current typeface and text size.
774 public float descent() {
775 if (mFonts.size() > 0) {
776 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
777 return javaMetrics.getDescent();
784 * Return the width of the text.
786 * @param text The text to measure
787 * @param index The index of the first character to start measuring
788 * @param count THe number of characters to measure, beginning with start
789 * @return The width of the text
792 public float measureText(char[] text, int index, int count) {
793 // WARNING: the logic in this method is similar to Canvas.drawText.
794 // Any change to this method should be reflected in Canvas.drawText
795 if (mFonts.size() > 0) {
796 FontInfo mainFont = mFonts.get(0);
798 int lastIndex = index + count;
800 while (i < lastIndex) {
801 // always start with the main font.
802 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
805 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
806 } else if (upTo > 0) {
807 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
809 // don't call continue at this point. Since it is certain the main font
810 // cannot display the font a index upTo (now ==i), we move on to the
811 // fallback fonts directly.
814 // no char supported, attempt to read the next char(s) with the
815 // fallback font. In this case we only test the first character
816 // and then go back to test with the main font.
817 // Special test for 2-char characters.
818 boolean foundFont = false;
819 for (int f = 1 ; f < mFonts.size() ; f++) {
820 FontInfo fontInfo = mFonts.get(f);
822 // need to check that the font can display the character. We test
823 // differently if the char is a high surrogate.
824 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
825 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
827 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
835 // in case no font can display the char, measure it with the main font.
836 if (foundFont == false) {
837 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
838 total += mainFont.mMetrics.charsWidth(text, i, size);
848 * Return the width of the text.
850 * @param text The text to measure
851 * @param start The index of the first character to start measuring
852 * @param end 1 beyond the index of the last character to measure
853 * @return The width of the text
856 public float measureText(String text, int start, int end) {
857 return measureText(text.toCharArray(), start, end - start);
861 * Return the width of the text.
863 * @param text The text to measure
864 * @return The width of the text
867 public float measureText(String text) {
868 return measureText(text.toCharArray(), 0, text.length());
872 * re-implement to call SpannableStringBuilder.measureText with a Paint object
873 * instead of an _Original_Paint
876 public float measureText(CharSequence text, int start, int end) {
877 if (text instanceof String) {
878 return measureText((String)text, start, end);
880 if (text instanceof SpannedString ||
881 text instanceof SpannableString) {
882 return measureText(text.toString(), start, end);
884 if (text instanceof SpannableStringBuilder) {
885 return ((SpannableStringBuilder)text).measureText(start, end, this);
888 char[] buf = TemporaryBuffer.obtain(end - start);
889 TextUtils.getChars(text, start, end, buf, 0);
890 float result = measureText(buf, 0, end - start);
891 TemporaryBuffer.recycle(buf);
896 * Measure the text, stopping early if the measured width exceeds maxWidth.
897 * Return the number of chars that were measured, and if measuredWidth is
898 * not null, return in it the actual width measured.
900 * @param text The text to measure
901 * @param index The offset into text to begin measuring at
902 * @param count The number of maximum number of entries to measure. If count
903 * is negative, then the characters before index are measured
904 * in reverse order. This allows for measuring the end of
906 * @param maxWidth The maximum width to accumulate.
907 * @param measuredWidth Optional. If not null, returns the actual width
909 * @return The number of chars that were measured. Will always be <=
913 public int breakText(char[] text, int index, int count,
914 float maxWidth, float[] measuredWidth) {
915 int inc = count > 0 ? 1 : -1;
917 int measureIndex = 0;
918 float measureAcc = 0;
919 for (int i = index ; i != index + count ; i += inc, measureIndex++) {
929 // measure from start to end
930 float res = measureText(text, start, end - start + 1);
932 if (measuredWidth != null) {
933 measuredWidth[measureIndex] = res;
937 if (res > maxWidth) {
938 // we should not return this char index, but since it's 0-based and we need
939 // to return a count, we simply return measureIndex;
949 * Measure the text, stopping early if the measured width exceeds maxWidth.
950 * Return the number of chars that were measured, and if measuredWidth is
951 * not null, return in it the actual width measured.
953 * @param text The text to measure
954 * @param measureForwards If true, measure forwards, starting at index.
955 * Otherwise, measure backwards, starting with the
956 * last character in the string.
957 * @param maxWidth The maximum width to accumulate.
958 * @param measuredWidth Optional. If not null, returns the actual width
960 * @return The number of chars that were measured. Will always be <=
964 public int breakText(String text, boolean measureForwards,
965 float maxWidth, float[] measuredWidth) {
966 return breakText(text,
967 0 /* start */, text.length() /* end */,
968 measureForwards, maxWidth, measuredWidth);
972 * Measure the text, stopping early if the measured width exceeds maxWidth.
973 * Return the number of chars that were measured, and if measuredWidth is
974 * not null, return in it the actual width measured.
976 * @param text The text to measure
977 * @param start The offset into text to begin measuring at
978 * @param end The end of the text slice to measure.
979 * @param measureForwards If true, measure forwards, starting at start.
980 * Otherwise, measure backwards, starting with end.
981 * @param maxWidth The maximum width to accumulate.
982 * @param measuredWidth Optional. If not null, returns the actual width
984 * @return The number of chars that were measured. Will always be <=
988 public int breakText(CharSequence text, int start, int end, boolean measureForwards,
989 float maxWidth, float[] measuredWidth) {
990 char[] buf = new char[end - start];
993 TextUtils.getChars(text, start, end, buf, 0);
995 if (measureForwards) {
996 result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
998 result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
1005 * Return the advance widths for the characters in the string.
1007 * @param text The text to measure
1008 * @param index The index of the first char to to measure
1009 * @param count The number of chars starting with index to measure
1010 * @param widths array to receive the advance widths of the characters.
1011 * Must be at least a large as count.
1012 * @return the actual number of widths returned.
1015 public int getTextWidths(char[] text, int index, int count,
1017 if (mFonts.size() > 0) {
1018 if ((index | count) < 0 || index + count > text.length
1019 || count > widths.length) {
1020 throw new ArrayIndexOutOfBoundsException();
1023 // FIXME: handle multi-char characters.
1024 // Need to figure out if the lengths of the width array takes into account
1025 // multi-char characters.
1026 for (int i = 0; i < count; i++) {
1027 char c = text[i + index];
1028 boolean found = false;
1029 for (FontInfo info : mFonts) {
1030 if (info.mFont.canDisplay(c)) {
1031 widths[i] = info.mMetrics.charWidth(c);
1037 if (found == false) {
1050 * Return the advance widths for the characters in the string.
1052 * @param text The text to measure
1053 * @param start The index of the first char to to measure
1054 * @param end The end of the text slice to measure
1055 * @param widths array to receive the advance widths of the characters.
1056 * Must be at least a large as the text.
1057 * @return the number of unichars in the specified text.
1060 public int getTextWidths(String text, int start, int end, float[] widths) {
1061 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1062 throw new IndexOutOfBoundsException();
1064 if (end - start > widths.length) {
1065 throw new ArrayIndexOutOfBoundsException();
1068 return getTextWidths(text.toCharArray(), start, end - start, widths);
1072 * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
1073 * instead of an _Original_Paint
1076 public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
1077 if (text instanceof String) {
1078 return getTextWidths((String)text, start, end, widths);
1080 if (text instanceof SpannedString || text instanceof SpannableString) {
1081 return getTextWidths(text.toString(), start, end, widths);
1083 if (text instanceof SpannableStringBuilder) {
1084 return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
1087 char[] buf = TemporaryBuffer.obtain(end - start);
1088 TextUtils.getChars(text, start, end, buf, 0);
1089 int result = getTextWidths(buf, 0, end - start, widths);
1090 TemporaryBuffer.recycle(buf);
1095 public int getTextWidths(String text, float[] widths) {
1096 return super.getTextWidths(text, widths);
1100 * Return the path (outline) for the specified text.
1101 * Note: just like Canvas.drawText, this will respect the Align setting in
1104 * @param text The text to retrieve the path from
1105 * @param index The index of the first character in text
1106 * @param count The number of characterss starting with index
1107 * @param x The x coordinate of the text's origin
1108 * @param y The y coordinate of the text's origin
1109 * @param path The path to receive the data describing the text. Must
1110 * be allocated by the caller.
1113 public void getTextPath(char[] text, int index, int count,
1114 float x, float y, Path path) {
1116 // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
1118 if ((index | count) < 0 || index + count > text.length) {
1119 throw new ArrayIndexOutOfBoundsException();
1122 // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
1124 throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
1128 * Return the path (outline) for the specified text.
1129 * Note: just like Canvas.drawText, this will respect the Align setting
1132 * @param text The text to retrieve the path from
1133 * @param start The first character in the text
1134 * @param end 1 past the last charcter in the text
1135 * @param x The x coordinate of the text's origin
1136 * @param y The y coordinate of the text's origin
1137 * @param path The path to receive the data describing the text. Must
1138 * be allocated by the caller.
1141 public void getTextPath(String text, int start, int end,
1142 float x, float y, Path path) {
1143 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1144 throw new IndexOutOfBoundsException();
1147 getTextPath(text.toCharArray(), start, end - start, x, y, path);
1151 * Return in bounds (allocated by the caller) the smallest rectangle that
1152 * encloses all of the characters, with an implied origin at (0,0).
1154 * @param text String to measure and return its bounds
1155 * @param start Index of the first char in the string to measure
1156 * @param end 1 past the last char in the string measure
1157 * @param bounds Returns the unioned bounds of all the text. Must be
1158 * allocated by the caller.
1161 public void getTextBounds(String text, int start, int end, Rect bounds) {
1162 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1163 throw new IndexOutOfBoundsException();
1165 if (bounds == null) {
1166 throw new NullPointerException("need bounds Rect");
1169 getTextBounds(text.toCharArray(), start, end - start, bounds);
1173 * Return in bounds (allocated by the caller) the smallest rectangle that
1174 * encloses all of the characters, with an implied origin at (0,0).
1176 * @param text Array of chars to measure and return their unioned bounds
1177 * @param index Index of the first char in the array to measure
1178 * @param count The number of chars, beginning at index, to measure
1179 * @param bounds Returns the unioned bounds of all the text. Must be
1180 * allocated by the caller.
1183 public void getTextBounds(char[] text, int index, int count, Rect bounds) {
1185 if (mFonts.size() > 0) {
1186 if ((index | count) < 0 || index + count > text.length) {
1187 throw new ArrayIndexOutOfBoundsException();
1189 if (bounds == null) {
1190 throw new NullPointerException("need bounds Rect");
1193 FontInfo mainInfo = mFonts.get(0);
1195 Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
1196 bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
1200 public static void finalizer(int foo) {