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;
25 import java.awt.Toolkit;
26 import java.awt.font.FontRenderContext;
27 import java.awt.geom.AffineTransform;
28 import java.awt.geom.Rectangle2D;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
34 * A paint implementation overridden by the LayoutLib bridge.
36 public class Paint extends _Original_Paint {
38 private int mColor = 0xFFFFFFFF;
39 private float mStrokeWidth = 1.f;
40 private float mTextSize = 20;
41 private float mScaleX = 1;
42 private float mSkewX = 0;
43 private Align mAlign = Align.LEFT;
44 private Style mStyle = Style.FILL;
45 private float mStrokeMiter = 4.0f;
46 private Cap mCap = Cap.BUTT;
47 private Join mJoin = Join.MITER;
48 private int mFlags = 0;
51 * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
53 public static final class FontInfo {
55 java.awt.FontMetrics mMetrics;
58 private List<FontInfo> mFonts;
59 private final FontRenderContext mFontContext = new FontRenderContext(
60 new AffineTransform(), true, true);
62 @SuppressWarnings("hiding")
63 public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
64 @SuppressWarnings("hiding")
65 public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG;
66 @SuppressWarnings("hiding")
67 public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG;
68 @SuppressWarnings("hiding")
69 public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG;
70 @SuppressWarnings("hiding")
71 public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
72 @SuppressWarnings("hiding")
73 public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
74 @SuppressWarnings("hiding")
75 public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG;
76 @SuppressWarnings("hiding")
77 public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG;
78 @SuppressWarnings("hiding")
79 public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
81 public static class FontMetrics extends _Original_Paint.FontMetrics {
84 public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
88 * The Style specifies if the primitive being drawn is filled,
89 * stroked, or both (in the same color). The default is FILL.
93 * Geometry and text drawn with this style will be filled, ignoring all
94 * stroke-related settings in the paint.
98 * Geometry and text drawn with this style will be stroked, respecting
99 * the stroke-related fields on the paint.
103 * Geometry and text drawn with this style will be both filled and
104 * stroked at the same time, respecting the stroke-related fields on
109 Style(int nativeInt) {
110 this.nativeInt = nativeInt;
116 * The Cap specifies the treatment for the beginning and ending of
117 * stroked lines and paths. The default is BUTT.
121 * The stroke ends with the path, and does not project beyond it.
125 * The stroke projects out as a square, with the center at the end
130 * The stroke projects out as a semicircle, with the center at the
135 private Cap(int nativeInt) {
136 this.nativeInt = nativeInt;
142 * The Join specifies the treatment where lines and curve segments
143 * join on a stroked path. The default is MITER.
147 * The outer edges of a join meet at a sharp angle
151 * The outer edges of a join meet in a circular arc.
155 * The outer edges of a join meet with a straight line
159 private Join(int nativeInt) {
160 this.nativeInt = nativeInt;
166 * Align specifies how drawText aligns its text relative to the
167 * [x,y] coordinates. The default is LEFT.
171 * The text is drawn to the right of the x,y origin
175 * The text is drawn centered horizontally on the x,y origin
179 * The text is drawn to the left of the x,y origin
183 private Align(int nativeInt) {
184 this.nativeInt = nativeInt;
193 public Paint(int flags) {
194 setFlags(flags | DEFAULT_PAINT_FLAGS);
198 public Paint(Paint paint) {
204 public void finalize() throws Throwable {
209 public void reset() {
214 * Returns the list of {@link Font} objects. The first item is the main font, the rest
215 * are fall backs for characters not present in the main font.
217 public List<FontInfo> getFonts() {
221 private void initFont() {
222 mTypeface = Typeface.DEFAULT;
227 * Update the {@link Font} object from the typeface, text size and scaling
229 @SuppressWarnings("deprecation")
230 private void updateFontObject() {
231 if (mTypeface != null) {
232 // Get the fonts from the TypeFace object.
233 List<Font> fonts = mTypeface.getFonts();
235 // create new font objects as well as FontMetrics, based on the current text size
237 ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
238 for (Font font : fonts) {
239 FontInfo info = new FontInfo();
240 info.mFont = font.deriveFont(mTextSize);
241 if (mScaleX != 1.0 || mSkewX != 0) {
242 // TODO: support skew
243 info.mFont = info.mFont.deriveFont(new AffineTransform(
244 mScaleX, mSkewX, 0, 0, 1, 0));
246 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
251 mFonts = Collections.unmodifiableList(infoList);
255 //----------------------------------------
257 public void set(Paint src) {
260 mTextSize = src.mTextSize;
261 mScaleX = src.mScaleX;
272 public void setCompatibilityScaling(float factor) {
273 super.setCompatibilityScaling(factor);
277 public int getFlags() {
282 public void setFlags(int flags) {
287 public boolean isAntiAlias() {
288 return super.isAntiAlias();
292 public boolean isDither() {
293 return super.isDither();
297 public boolean isLinearText() {
298 return super.isLinearText();
302 public boolean isStrikeThruText() {
303 return super.isStrikeThruText();
307 public boolean isUnderlineText() {
308 return super.isUnderlineText();
312 public boolean isFakeBoldText() {
313 return super.isFakeBoldText();
317 public boolean isSubpixelText() {
318 return super.isSubpixelText();
322 public boolean isFilterBitmap() {
323 return super.isFilterBitmap();
327 * Return the font's recommended interline spacing, given the Paint's
328 * settings for typeface, textSize, etc. If metrics is not null, return the
329 * fontmetric values in it.
331 * @param metrics If this object is not null, its fields are filled with
332 * the appropriate values given the paint's text attributes.
333 * @return the font's recommended interline spacing.
335 public float getFontMetrics(FontMetrics metrics) {
336 if (mFonts.size() > 0) {
337 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
338 if (metrics != null) {
339 // Android expects negative ascent so we invert the value from Java.
340 metrics.top = - javaMetrics.getMaxAscent();
341 metrics.ascent = - javaMetrics.getAscent();
342 metrics.descent = javaMetrics.getDescent();
343 metrics.bottom = javaMetrics.getMaxDescent();
344 metrics.leading = javaMetrics.getLeading();
347 return javaMetrics.getHeight();
353 public int getFontMetricsInt(FontMetricsInt 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();
372 * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
374 public FontMetrics getFontMetrics() {
375 FontMetrics fm = new FontMetrics();
381 * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
383 public FontMetricsInt getFontMetricsInt() {
384 FontMetricsInt fm = new FontMetricsInt();
385 getFontMetricsInt(fm);
392 public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
393 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
397 public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
398 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
402 public Typeface setTypeface(Typeface typeface) {
403 if (typeface != null) {
404 mTypeface = typeface;
406 mTypeface = Typeface.DEFAULT;
415 public Typeface getTypeface() {
416 return super.getTypeface();
420 public int getColor() {
425 public void setColor(int color) {
430 public void setARGB(int a, int r, int g, int b) {
431 super.setARGB(a, r, g, b);
435 public void setAlpha(int alpha) {
436 mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
440 public int getAlpha() {
441 return mColor >>> 24;
445 * Set or clear the shader object.
447 * Pass null to clear any previous shader.
448 * As a convenience, the parameter passed is also returned.
450 * @param shader May be null. the new shader to be installed in the paint
454 public Shader setShader(Shader shader) {
455 return mShader = shader;
459 public Shader getShader() {
460 return super.getShader();
464 * Set or clear the paint's colorfilter, returning the parameter.
466 * @param filter May be null. The new filter to be installed in the paint
470 public ColorFilter setColorFilter(ColorFilter filter) {
471 mColorFilter = filter;
476 public ColorFilter getColorFilter() {
477 return super.getColorFilter();
481 * Set or clear the xfermode object.
483 * Pass null to clear any previous xfermode.
484 * As a convenience, the parameter passed is also returned.
486 * @param xfermode May be null. The xfermode to be installed in the paint
490 public Xfermode setXfermode(Xfermode xfermode) {
491 return mXfermode = xfermode;
495 public Xfermode getXfermode() {
496 return super.getXfermode();
500 public Rasterizer setRasterizer(Rasterizer rasterizer) {
501 mRasterizer = rasterizer;
506 public Rasterizer getRasterizer() {
507 return super.getRasterizer();
511 public void setShadowLayer(float radius, float dx, float dy, int color) {
512 // TODO Auto-generated method stub
516 public void clearShadowLayer() {
517 super.clearShadowLayer();
520 public void setTextAlign(Align align) {
525 public void setTextAlign(android.graphics._Original_Paint.Align align) {
526 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
529 public Align getTextAlign() {
533 public void setStyle(Style style) {
538 public void setStyle(android.graphics._Original_Paint.Style style) {
539 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
542 public Style getStyle() {
547 public void setDither(boolean dither) {
548 mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
552 public void setAntiAlias(boolean aa) {
553 mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
557 public void setFakeBoldText(boolean flag) {
558 mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
562 public void setLinearText(boolean flag) {
563 mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
567 public void setSubpixelText(boolean flag) {
568 mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
572 public void setUnderlineText(boolean flag) {
573 mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
577 public void setStrikeThruText(boolean flag) {
578 mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
582 public void setFilterBitmap(boolean flag) {
583 mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
587 public float getStrokeWidth() {
592 public void setStrokeWidth(float width) {
593 mStrokeWidth = width;
597 public float getStrokeMiter() {
602 public void setStrokeMiter(float miter) {
603 mStrokeMiter = miter;
607 public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
608 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
611 public void setStrokeCap(Cap cap) {
615 public Cap getStrokeCap() {
620 public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
621 throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
624 public void setStrokeJoin(Join join) {
628 public Join getStrokeJoin() {
633 public boolean getFillPath(Path src, Path dst) {
634 return super.getFillPath(src, dst);
638 public PathEffect setPathEffect(PathEffect effect) {
639 mPathEffect = effect;
644 public PathEffect getPathEffect() {
645 return super.getPathEffect();
649 public MaskFilter setMaskFilter(MaskFilter maskfilter) {
650 mMaskFilter = maskfilter;
655 public MaskFilter getMaskFilter() {
656 return super.getMaskFilter();
660 * Return the paint's text size.
662 * @return the paint's text size.
665 public float getTextSize() {
670 * Set the paint's text size. This value must be > 0
672 * @param textSize set the paint's text size.
675 public void setTextSize(float textSize) {
676 mTextSize = textSize;
682 * Return the paint's horizontal scale factor for text. The default value
685 * @return the paint's scale factor in X for drawing/measuring text
688 public float getTextScaleX() {
693 * Set the paint's horizontal scale factor for text. The default value
694 * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
695 * stretch the text narrower.
697 * @param scaleX set the paint's scale in X for drawing/measuring text.
700 public void setTextScaleX(float scaleX) {
707 * Return the paint's horizontal skew factor for text. The default value
710 * @return the paint's skew factor in X for drawing text.
713 public float getTextSkewX() {
718 * Set the paint's horizontal skew factor for text. The default value
719 * is 0. For approximating oblique text, use values around -0.25.
721 * @param skewX set the paint's skew factor in X for drawing text.
724 public void setTextSkewX(float skewX) {
731 public float getFontSpacing() {
732 return super.getFontSpacing();
736 * Return the distance above (negative) the baseline (ascent) based on the
737 * current typeface and text size.
739 * @return the distance above (negative) the baseline (ascent) based on the
740 * current typeface and text size.
743 public float ascent() {
744 if (mFonts.size() > 0) {
745 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
746 // Android expects negative ascent so we invert the value from Java.
747 return - javaMetrics.getAscent();
754 * Return the distance below (positive) the baseline (descent) based on the
755 * current typeface and text size.
757 * @return the distance below (positive) the baseline (descent) based on
758 * the current typeface and text size.
761 public float descent() {
762 if (mFonts.size() > 0) {
763 java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
764 return javaMetrics.getDescent();
771 * Return the width of the text.
773 * @param text The text to measure
774 * @param index The index of the first character to start measuring
775 * @param count THe number of characters to measure, beginning with start
776 * @return The width of the text
779 public float measureText(char[] text, int index, int count) {
780 // WARNING: the logic in this method is similar to Canvas.drawText.
781 // Any change to this method should be reflected in Canvas.drawText
782 if (mFonts.size() > 0) {
783 FontInfo mainFont = mFonts.get(0);
785 int lastIndex = index + count;
787 while (i < lastIndex) {
788 // always start with the main font.
789 int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
792 return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
793 } else if (upTo > 0) {
794 total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
796 // don't call continue at this point. Since it is certain the main font
797 // cannot display the font a index upTo (now ==i), we move on to the
798 // fallback fonts directly.
801 // no char supported, attempt to read the next char(s) with the
802 // fallback font. In this case we only test the first character
803 // and then go back to test with the main font.
804 // Special test for 2-char characters.
805 boolean foundFont = false;
806 for (int f = 1 ; f < mFonts.size() ; f++) {
807 FontInfo fontInfo = mFonts.get(f);
809 // need to check that the font can display the character. We test
810 // differently if the char is a high surrogate.
811 int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
812 upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
814 total += fontInfo.mMetrics.charsWidth(text, i, charCount);
822 // in case no font can display the char, measure it with the main font.
823 if (foundFont == false) {
824 int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
825 total += mainFont.mMetrics.charsWidth(text, i, size);
835 * Return the width of the text.
837 * @param text The text to measure
838 * @param start The index of the first character to start measuring
839 * @param end 1 beyond the index of the last character to measure
840 * @return The width of the text
843 public float measureText(String text, int start, int end) {
844 return measureText(text.toCharArray(), start, end - start);
848 * Return the width of the text.
850 * @param text The text to measure
851 * @return The width of the text
854 public float measureText(String text) {
855 return measureText(text.toCharArray(), 0, text.length());
859 * re-implement to call SpannableStringBuilder.measureText with a Paint object
860 * instead of an _Original_Paint
863 public float measureText(CharSequence text, int start, int end) {
864 if (text instanceof String) {
865 return measureText((String)text, start, end);
867 if (text instanceof SpannedString ||
868 text instanceof SpannableString) {
869 return measureText(text.toString(), start, end);
871 if (text instanceof SpannableStringBuilder) {
872 return ((SpannableStringBuilder)text).measureText(start, end, this);
875 char[] buf = TemporaryBuffer.obtain(end - start);
876 TextUtils.getChars(text, start, end, buf, 0);
877 float result = measureText(buf, 0, end - start);
878 TemporaryBuffer.recycle(buf);
883 * Measure the text, stopping early if the measured width exceeds maxWidth.
884 * Return the number of chars that were measured, and if measuredWidth is
885 * not null, return in it the actual width measured.
887 * @param text The text to measure
888 * @param index The offset into text to begin measuring at
889 * @param count The number of maximum number of entries to measure. If count
890 * is negative, then the characters before index are measured
891 * in reverse order. This allows for measuring the end of
893 * @param maxWidth The maximum width to accumulate.
894 * @param measuredWidth Optional. If not null, returns the actual width
896 * @return The number of chars that were measured. Will always be <=
900 public int breakText(char[] text, int index, int count,
901 float maxWidth, float[] measuredWidth) {
902 int inc = count > 0 ? 1 : -1;
904 int measureIndex = 0;
905 float measureAcc = 0;
906 for (int i = index ; i != index + count ; i += inc, measureIndex++) {
916 // measure from start to end
917 float res = measureText(text, start, end - start + 1);
919 if (measuredWidth != null) {
920 measuredWidth[measureIndex] = res;
924 if (res > maxWidth) {
925 // we should not return this char index, but since it's 0-based and we need
926 // to return a count, we simply return measureIndex;
936 * Measure the text, stopping early if the measured width exceeds maxWidth.
937 * Return the number of chars that were measured, and if measuredWidth is
938 * not null, return in it the actual width measured.
940 * @param text The text to measure
941 * @param measureForwards If true, measure forwards, starting at index.
942 * Otherwise, measure backwards, starting with the
943 * last character in the string.
944 * @param maxWidth The maximum width to accumulate.
945 * @param measuredWidth Optional. If not null, returns the actual width
947 * @return The number of chars that were measured. Will always be <=
951 public int breakText(String text, boolean measureForwards,
952 float maxWidth, float[] measuredWidth) {
953 return breakText(text,
954 0 /* start */, text.length() /* end */,
955 measureForwards, maxWidth, measuredWidth);
959 * Measure the text, stopping early if the measured width exceeds maxWidth.
960 * Return the number of chars that were measured, and if measuredWidth is
961 * not null, return in it the actual width measured.
963 * @param text The text to measure
964 * @param start The offset into text to begin measuring at
965 * @param end The end of the text slice to measure.
966 * @param measureForwards If true, measure forwards, starting at start.
967 * Otherwise, measure backwards, starting with end.
968 * @param maxWidth The maximum width to accumulate.
969 * @param measuredWidth Optional. If not null, returns the actual width
971 * @return The number of chars that were measured. Will always be <=
975 public int breakText(CharSequence text, int start, int end, boolean measureForwards,
976 float maxWidth, float[] measuredWidth) {
977 char[] buf = new char[end - start];
980 TextUtils.getChars(text, start, end, buf, 0);
982 if (measureForwards) {
983 result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
985 result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
992 * Return the advance widths for the characters in the string.
994 * @param text The text to measure
995 * @param index The index of the first char to to measure
996 * @param count The number of chars starting with index to measure
997 * @param widths array to receive the advance widths of the characters.
998 * Must be at least a large as count.
999 * @return the actual number of widths returned.
1002 public int getTextWidths(char[] text, int index, int count,
1004 if (mFonts.size() > 0) {
1005 if ((index | count) < 0 || index + count > text.length
1006 || count > widths.length) {
1007 throw new ArrayIndexOutOfBoundsException();
1010 // FIXME: handle multi-char characters.
1011 // Need to figure out if the lengths of the width array takes into account
1012 // multi-char characters.
1013 for (int i = 0; i < count; i++) {
1014 char c = text[i + index];
1015 boolean found = false;
1016 for (FontInfo info : mFonts) {
1017 if (info.mFont.canDisplay(c)) {
1018 widths[i] = info.mMetrics.charWidth(c);
1024 if (found == false) {
1037 * Return the advance widths for the characters in the string.
1039 * @param text The text to measure
1040 * @param start The index of the first char to to measure
1041 * @param end The end of the text slice to measure
1042 * @param widths array to receive the advance widths of the characters.
1043 * Must be at least a large as the text.
1044 * @return the number of unichars in the specified text.
1047 public int getTextWidths(String text, int start, int end, float[] widths) {
1048 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1049 throw new IndexOutOfBoundsException();
1051 if (end - start > widths.length) {
1052 throw new ArrayIndexOutOfBoundsException();
1055 return getTextWidths(text.toCharArray(), start, end - start, widths);
1059 * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
1060 * instead of an _Original_Paint
1063 public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
1064 if (text instanceof String) {
1065 return getTextWidths((String)text, start, end, widths);
1067 if (text instanceof SpannedString || text instanceof SpannableString) {
1068 return getTextWidths(text.toString(), start, end, widths);
1070 if (text instanceof SpannableStringBuilder) {
1071 return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
1074 char[] buf = TemporaryBuffer.obtain(end - start);
1075 TextUtils.getChars(text, start, end, buf, 0);
1076 int result = getTextWidths(buf, 0, end - start, widths);
1077 TemporaryBuffer.recycle(buf);
1082 public int getTextWidths(String text, float[] widths) {
1083 return super.getTextWidths(text, widths);
1087 * Return the path (outline) for the specified text.
1088 * Note: just like Canvas.drawText, this will respect the Align setting in
1091 * @param text The text to retrieve the path from
1092 * @param index The index of the first character in text
1093 * @param count The number of characterss starting with index
1094 * @param x The x coordinate of the text's origin
1095 * @param y The y coordinate of the text's origin
1096 * @param path The path to receive the data describing the text. Must
1097 * be allocated by the caller.
1100 public void getTextPath(char[] text, int index, int count,
1101 float x, float y, Path path) {
1103 // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
1105 if ((index | count) < 0 || index + count > text.length) {
1106 throw new ArrayIndexOutOfBoundsException();
1109 // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
1111 throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
1115 * Return the path (outline) for the specified text.
1116 * Note: just like Canvas.drawText, this will respect the Align setting
1119 * @param text The text to retrieve the path from
1120 * @param start The first character in the text
1121 * @param end 1 past the last charcter in the text
1122 * @param x The x coordinate of the text's origin
1123 * @param y The y coordinate of the text's origin
1124 * @param path The path to receive the data describing the text. Must
1125 * be allocated by the caller.
1128 public void getTextPath(String text, int start, int end,
1129 float x, float y, Path path) {
1130 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1131 throw new IndexOutOfBoundsException();
1134 getTextPath(text.toCharArray(), start, end - start, x, y, path);
1138 * Return in bounds (allocated by the caller) the smallest rectangle that
1139 * encloses all of the characters, with an implied origin at (0,0).
1141 * @param text String to measure and return its bounds
1142 * @param start Index of the first char in the string to measure
1143 * @param end 1 past the last char in the string measure
1144 * @param bounds Returns the unioned bounds of all the text. Must be
1145 * allocated by the caller.
1148 public void getTextBounds(String text, int start, int end, Rect bounds) {
1149 if ((start | end | (end - start) | (text.length() - end)) < 0) {
1150 throw new IndexOutOfBoundsException();
1152 if (bounds == null) {
1153 throw new NullPointerException("need bounds Rect");
1156 getTextBounds(text.toCharArray(), start, end - start, bounds);
1160 * Return in bounds (allocated by the caller) the smallest rectangle that
1161 * encloses all of the characters, with an implied origin at (0,0).
1163 * @param text Array of chars to measure and return their unioned bounds
1164 * @param index Index of the first char in the array to measure
1165 * @param count The number of chars, beginning at index, to measure
1166 * @param bounds Returns the unioned bounds of all the text. Must be
1167 * allocated by the caller.
1170 public void getTextBounds(char[] text, int index, int count, Rect bounds) {
1172 if (mFonts.size() > 0) {
1173 if ((index | count) < 0 || index + count > text.length) {
1174 throw new ArrayIndexOutOfBoundsException();
1176 if (bounds == null) {
1177 throw new NullPointerException("need bounds Rect");
1180 FontInfo mainInfo = mFonts.get(0);
1182 Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
1183 bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
1187 public static void finalizer(int foo) {