• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 package android.graphics;
18 
19 import com.android.ide.common.rendering.api.LayoutLog;
20 import com.android.layoutlib.bridge.Bridge;
21 import com.android.layoutlib.bridge.impl.DelegateManager;
22 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.graphics.FontFamily_Delegate.FontVariant;
27 import android.graphics.Paint.FontMetrics;
28 import android.graphics.Paint.FontMetricsInt;
29 import android.text.TextUtils;
30 
31 import java.awt.BasicStroke;
32 import java.awt.Font;
33 import java.awt.Shape;
34 import java.awt.Stroke;
35 import java.awt.Toolkit;
36 import java.awt.geom.AffineTransform;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.Locale;
41 
42 import libcore.util.NativeAllocationRegistry_Delegate;
43 
44 /**
45  * Delegate implementing the native methods of android.graphics.Paint
46  *
47  * Through the layoutlib_create tool, the original native methods of Paint have been replaced
48  * by calls to methods of the same name in this delegate class.
49  *
50  * This class behaves like the original native implementation, but in Java, keeping previously
51  * native data into its own objects and mapping them to int that are sent back and forth between
52  * it and the original Paint class.
53  *
54  * @see DelegateManager
55  *
56  */
57 public class Paint_Delegate {
58 
59     /**
60      * Class associating a {@link Font} and its {@link java.awt.FontMetrics}.
61      */
62     /*package*/ static final class FontInfo {
63         Font mFont;
64         java.awt.FontMetrics mMetrics;
65     }
66 
67     // ---- delegate manager ----
68     private static final DelegateManager<Paint_Delegate> sManager =
69             new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
70     private static long sFinalizer = -1;
71 
72     // ---- delegate helper data ----
73 
74     // This list can contain null elements.
75     private List<FontInfo> mFonts;
76 
77     // ---- delegate data ----
78     private int mFlags;
79     private int mColor;
80     private int mStyle;
81     private int mCap;
82     private int mJoin;
83     private int mTextAlign;
84     private Typeface_Delegate mTypeface;
85     private float mStrokeWidth;
86     private float mStrokeMiter;
87     private float mTextSize;
88     private float mTextScaleX;
89     private float mTextSkewX;
90     private int mHintingMode = Paint.HINTING_ON;
91     private int mHyphenEdit;
92     private float mLetterSpacing;  // not used in actual text rendering.
93     // Variant of the font. A paint's variant can only be compact or elegant.
94     private FontVariant mFontVariant = FontVariant.COMPACT;
95 
96     private Xfermode_Delegate mXfermode;
97     private ColorFilter_Delegate mColorFilter;
98     private Shader_Delegate mShader;
99     private PathEffect_Delegate mPathEffect;
100     private MaskFilter_Delegate mMaskFilter;
101     private Rasterizer_Delegate mRasterizer;
102 
103     private Locale mLocale = Locale.getDefault();
104 
105     // Used only to assert invariants.
106     public long mNativeTypeface;
107 
108     // ---- Public Helper methods ----
109 
110     @Nullable
getDelegate(long native_paint)111     public static Paint_Delegate getDelegate(long native_paint) {
112         return sManager.getDelegate(native_paint);
113     }
114 
115     /**
116      * Returns the list of {@link Font} objects.
117      */
getFonts()118     public List<FontInfo> getFonts() {
119         return mFonts;
120     }
121 
isAntiAliased()122     public boolean isAntiAliased() {
123         return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
124     }
125 
isFilterBitmap()126     public boolean isFilterBitmap() {
127         return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
128     }
129 
getStyle()130     public int getStyle() {
131         return mStyle;
132     }
133 
getColor()134     public int getColor() {
135         return mColor;
136     }
137 
getAlpha()138     public int getAlpha() {
139         return mColor >>> 24;
140     }
141 
setAlpha(int alpha)142     public void setAlpha(int alpha) {
143         mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
144     }
145 
getTextAlign()146     public int getTextAlign() {
147         return mTextAlign;
148     }
149 
getStrokeWidth()150     public float getStrokeWidth() {
151         return mStrokeWidth;
152     }
153 
154     /**
155      * returns the value of stroke miter needed by the java api.
156      */
getJavaStrokeMiter()157     public float getJavaStrokeMiter() {
158         return mStrokeMiter;
159     }
160 
getJavaCap()161     public int getJavaCap() {
162         switch (Paint.sCapArray[mCap]) {
163             case BUTT:
164                 return BasicStroke.CAP_BUTT;
165             case ROUND:
166                 return BasicStroke.CAP_ROUND;
167             default:
168             case SQUARE:
169                 return BasicStroke.CAP_SQUARE;
170         }
171     }
172 
getJavaJoin()173     public int getJavaJoin() {
174         switch (Paint.sJoinArray[mJoin]) {
175             default:
176             case MITER:
177                 return BasicStroke.JOIN_MITER;
178             case ROUND:
179                 return BasicStroke.JOIN_ROUND;
180             case BEVEL:
181                 return BasicStroke.JOIN_BEVEL;
182         }
183     }
184 
getJavaStroke()185     public Stroke getJavaStroke() {
186         if (mPathEffect != null) {
187             if (mPathEffect.isSupported()) {
188                 Stroke stroke = mPathEffect.getStroke(this);
189                 assert stroke != null;
190                 if (stroke != null) {
191                     return stroke;
192                 }
193             } else {
194                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
195                         mPathEffect.getSupportMessage(),
196                         null, null /*data*/);
197             }
198         }
199 
200         // if no custom stroke as been set, set the default one.
201         return new BasicStroke(
202                     getStrokeWidth(),
203                     getJavaCap(),
204                     getJavaJoin(),
205                     getJavaStrokeMiter());
206     }
207 
208     /**
209      * Returns the {@link Xfermode} delegate or null if none have been set
210      *
211      * @return the delegate or null.
212      */
getXfermode()213     public Xfermode_Delegate getXfermode() {
214         return mXfermode;
215     }
216 
217     /**
218      * Returns the {@link ColorFilter} delegate or null if none have been set
219      *
220      * @return the delegate or null.
221      */
getColorFilter()222     public ColorFilter_Delegate getColorFilter() {
223         return mColorFilter;
224     }
225 
setColorFilter(long colorFilterPtr)226     public void setColorFilter(long colorFilterPtr) {
227         mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
228     }
229 
setShader(long shaderPtr)230     public void setShader(long shaderPtr) {
231         mShader = Shader_Delegate.getDelegate(shaderPtr);
232     }
233 
234     /**
235      * Returns the {@link Shader} delegate or null if none have been set
236      *
237      * @return the delegate or null.
238      */
getShader()239     public Shader_Delegate getShader() {
240         return mShader;
241     }
242 
243     /**
244      * Returns the {@link MaskFilter} delegate or null if none have been set
245      *
246      * @return the delegate or null.
247      */
getMaskFilter()248     public MaskFilter_Delegate getMaskFilter() {
249         return mMaskFilter;
250     }
251 
252     /**
253      * Returns the {@link Rasterizer} delegate or null if none have been set
254      *
255      * @return the delegate or null.
256      */
getRasterizer()257     public Rasterizer_Delegate getRasterizer() {
258         return mRasterizer;
259     }
260 
261     // ---- native methods ----
262 
263     @LayoutlibDelegate
nGetFlags(Paint thisPaint, long nativePaint)264     /*package*/ static int nGetFlags(Paint thisPaint, long nativePaint) {
265         // get the delegate from the native int.
266         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
267         if (delegate == null) {
268             return 0;
269         }
270 
271         return delegate.mFlags;
272     }
273 
274 
275 
276     @LayoutlibDelegate
nSetFlags(Paint thisPaint, long nativePaint, int flags)277     /*package*/ static void nSetFlags(Paint thisPaint, long nativePaint, int flags) {
278         // get the delegate from the native int.
279         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
280         if (delegate == null) {
281             return;
282         }
283 
284         delegate.mFlags = flags;
285     }
286 
287     @LayoutlibDelegate
nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter)288     /*package*/ static void nSetFilterBitmap(Paint thisPaint, long nativePaint, boolean filter) {
289         setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter);
290     }
291 
292     @LayoutlibDelegate
nGetHinting(Paint thisPaint, long nativePaint)293     /*package*/ static int nGetHinting(Paint thisPaint, long nativePaint) {
294         // get the delegate from the native int.
295         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
296         if (delegate == null) {
297             return Paint.HINTING_ON;
298         }
299 
300         return delegate.mHintingMode;
301     }
302 
303     @LayoutlibDelegate
nSetHinting(Paint thisPaint, long nativePaint, int mode)304     /*package*/ static void nSetHinting(Paint thisPaint, long nativePaint, int mode) {
305         // get the delegate from the native int.
306         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
307         if (delegate == null) {
308             return;
309         }
310 
311         delegate.mHintingMode = mode;
312     }
313 
314     @LayoutlibDelegate
nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa)315     /*package*/ static void nSetAntiAlias(Paint thisPaint, long nativePaint, boolean aa) {
316         setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa);
317     }
318 
319     @LayoutlibDelegate
nSetSubpixelText(Paint thisPaint, long nativePaint, boolean subpixelText)320     /*package*/ static void nSetSubpixelText(Paint thisPaint, long nativePaint,
321             boolean subpixelText) {
322         setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
323     }
324 
325     @LayoutlibDelegate
nSetUnderlineText(Paint thisPaint, long nativePaint, boolean underlineText)326     /*package*/ static void nSetUnderlineText(Paint thisPaint, long nativePaint,
327             boolean underlineText) {
328         setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
329     }
330 
331     @LayoutlibDelegate
nSetStrikeThruText(Paint thisPaint, long nativePaint, boolean strikeThruText)332     /*package*/ static void nSetStrikeThruText(Paint thisPaint, long nativePaint,
333             boolean strikeThruText) {
334         setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
335     }
336 
337     @LayoutlibDelegate
nSetFakeBoldText(Paint thisPaint, long nativePaint, boolean fakeBoldText)338     /*package*/ static void nSetFakeBoldText(Paint thisPaint, long nativePaint,
339             boolean fakeBoldText) {
340         setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
341     }
342 
343     @LayoutlibDelegate
nSetDither(Paint thisPaint, long nativePaint, boolean dither)344     /*package*/ static void nSetDither(Paint thisPaint, long nativePaint, boolean dither) {
345         setFlag(nativePaint, Paint.DITHER_FLAG, dither);
346     }
347 
348     @LayoutlibDelegate
nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText)349     /*package*/ static void nSetLinearText(Paint thisPaint, long nativePaint, boolean linearText) {
350         setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText);
351     }
352 
353     @LayoutlibDelegate
nGetColor(Paint thisPaint, long nativePaint)354     /*package*/ static int nGetColor(Paint thisPaint, long nativePaint) {
355         // get the delegate from the native int.
356         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
357         if (delegate == null) {
358             return 0;
359         }
360 
361         return delegate.mColor;
362     }
363 
364     @LayoutlibDelegate
nSetColor(Paint thisPaint, long nativePaint, int color)365     /*package*/ static void nSetColor(Paint thisPaint, long nativePaint, int color) {
366         // get the delegate from the native int.
367         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
368         if (delegate == null) {
369             return;
370         }
371 
372         delegate.mColor = color;
373     }
374 
375     @LayoutlibDelegate
nGetAlpha(Paint thisPaint, long nativePaint)376     /*package*/ static int nGetAlpha(Paint thisPaint, long nativePaint) {
377         // get the delegate from the native int.
378         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
379         if (delegate == null) {
380             return 0;
381         }
382 
383         return delegate.getAlpha();
384     }
385 
386     @LayoutlibDelegate
nSetAlpha(Paint thisPaint, long nativePaint, int a)387     /*package*/ static void nSetAlpha(Paint thisPaint, long nativePaint, int a) {
388         // get the delegate from the native int.
389         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
390         if (delegate == null) {
391             return;
392         }
393 
394         delegate.setAlpha(a);
395     }
396 
397     @LayoutlibDelegate
nGetStrokeWidth(Paint thisPaint, long nativePaint)398     /*package*/ static float nGetStrokeWidth(Paint thisPaint, long nativePaint) {
399         // get the delegate from the native int.
400         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
401         if (delegate == null) {
402             return 1.f;
403         }
404 
405         return delegate.mStrokeWidth;
406     }
407 
408     @LayoutlibDelegate
nSetStrokeWidth(Paint thisPaint, long nativePaint, float width)409     /*package*/ static void nSetStrokeWidth(Paint thisPaint, long nativePaint, float width) {
410         // get the delegate from the native int.
411         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
412         if (delegate == null) {
413             return;
414         }
415 
416         delegate.mStrokeWidth = width;
417     }
418 
419     @LayoutlibDelegate
nGetStrokeMiter(Paint thisPaint, long nativePaint)420     /*package*/ static float nGetStrokeMiter(Paint thisPaint, long nativePaint) {
421         // get the delegate from the native int.
422         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
423         if (delegate == null) {
424             return 1.f;
425         }
426 
427         return delegate.mStrokeMiter;
428     }
429 
430     @LayoutlibDelegate
nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter)431     /*package*/ static void nSetStrokeMiter(Paint thisPaint, long nativePaint, float miter) {
432         // get the delegate from the native int.
433         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
434         if (delegate == null) {
435             return;
436         }
437 
438         delegate.mStrokeMiter = miter;
439     }
440 
441     @LayoutlibDelegate
nSetShadowLayer(long paint, float radius, float dx, float dy, int color)442     /*package*/ static void nSetShadowLayer(long paint, float radius, float dx, float dy,
443             int color) {
444         // FIXME
445         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
446                 "Paint.setShadowLayer is not supported.", null, null /*data*/);
447     }
448 
449     @LayoutlibDelegate
nHasShadowLayer(long paint)450     /*package*/ static boolean nHasShadowLayer(long paint) {
451         // FIXME
452         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
453                 "Paint.hasShadowLayer is not supported.", null, null /*data*/);
454         return false;
455     }
456 
457     @LayoutlibDelegate
nIsElegantTextHeight(Paint thisPaint, long nativePaint)458     /*package*/ static boolean nIsElegantTextHeight(Paint thisPaint, long nativePaint) {
459         // get the delegate from the native int.
460         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
461         return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
462     }
463 
464     @LayoutlibDelegate
nSetElegantTextHeight(Paint thisPaint, long nativePaint, boolean elegant)465     /*package*/ static void nSetElegantTextHeight(Paint thisPaint, long nativePaint,
466             boolean elegant) {
467         // get the delegate from the native int.
468         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
469         if (delegate == null) {
470             return;
471         }
472 
473         delegate.mFontVariant = elegant ? FontVariant.ELEGANT : FontVariant.COMPACT;
474     }
475 
476     @LayoutlibDelegate
nGetTextSize(Paint thisPaint, long nativePaint)477     /*package*/ static float nGetTextSize(Paint thisPaint, long nativePaint) {
478         // get the delegate from the native int.
479         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
480         if (delegate == null) {
481             return 1.f;
482         }
483 
484         return delegate.mTextSize;
485     }
486 
487     @LayoutlibDelegate
nSetTextSize(Paint thisPaint, long nativePaint, float textSize)488     /*package*/ static void nSetTextSize(Paint thisPaint, long nativePaint, float textSize) {
489         // get the delegate from the native int.
490         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
491         if (delegate == null) {
492             return;
493         }
494 
495         if (delegate.mTextSize != textSize) {
496             delegate.mTextSize = textSize;
497             delegate.updateFontObject();
498         }
499     }
500 
501     @LayoutlibDelegate
nGetTextScaleX(Paint thisPaint, long nativePaint)502     /*package*/ static float nGetTextScaleX(Paint thisPaint, long nativePaint) {
503         // get the delegate from the native int.
504         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
505         if (delegate == null) {
506             return 1.f;
507         }
508 
509         return delegate.mTextScaleX;
510     }
511 
512     @LayoutlibDelegate
nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX)513     /*package*/ static void nSetTextScaleX(Paint thisPaint, long nativePaint, float scaleX) {
514         // get the delegate from the native int.
515         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
516         if (delegate == null) {
517             return;
518         }
519 
520         if (delegate.mTextScaleX != scaleX) {
521             delegate.mTextScaleX = scaleX;
522             delegate.updateFontObject();
523         }
524     }
525 
526     @LayoutlibDelegate
nGetTextSkewX(Paint thisPaint, long nativePaint)527     /*package*/ static float nGetTextSkewX(Paint thisPaint, long nativePaint) {
528         // get the delegate from the native int.
529         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
530         if (delegate == null) {
531             return 1.f;
532         }
533 
534         return delegate.mTextSkewX;
535     }
536 
537     @LayoutlibDelegate
nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX)538     /*package*/ static void nSetTextSkewX(Paint thisPaint, long nativePaint, float skewX) {
539         // get the delegate from the native int.
540         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
541         if (delegate == null) {
542             return;
543         }
544 
545         if (delegate.mTextSkewX != skewX) {
546             delegate.mTextSkewX = skewX;
547             delegate.updateFontObject();
548         }
549     }
550 
551     @LayoutlibDelegate
nAscent(Paint thisPaint, long nativePaint, long nativeTypeface)552     /*package*/ static float nAscent(Paint thisPaint, long nativePaint, long nativeTypeface) {
553         // get the delegate
554         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
555         if (delegate == null) {
556             return 0;
557         }
558 
559         if (delegate.mFonts.size() > 0) {
560             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
561             // Android expects negative ascent so we invert the value from Java.
562             return - javaMetrics.getAscent();
563         }
564 
565         return 0;
566     }
567 
568     @LayoutlibDelegate
nDescent(Paint thisPaint, long nativePaint, long nativeTypeface)569     /*package*/ static float nDescent(Paint thisPaint, long nativePaint, long nativeTypeface) {
570         // get the delegate
571         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
572         if (delegate == null) {
573             return 0;
574         }
575 
576         if (delegate.mFonts.size() > 0) {
577             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
578             return javaMetrics.getDescent();
579         }
580 
581         return 0;
582 
583     }
584 
585     @LayoutlibDelegate
nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface, FontMetrics metrics)586     /*package*/ static float nGetFontMetrics(Paint thisPaint, long nativePaint, long nativeTypeface,
587             FontMetrics metrics) {
588         // get the delegate
589         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
590         if (delegate == null) {
591             return 0;
592         }
593 
594         return delegate.getFontMetrics(metrics);
595     }
596 
597     @LayoutlibDelegate
nGetFontMetricsInt(Paint thisPaint, long nativePaint, long nativeTypeface, FontMetricsInt fmi)598     /*package*/ static int nGetFontMetricsInt(Paint thisPaint, long nativePaint,
599             long nativeTypeface, FontMetricsInt fmi) {
600         // get the delegate
601         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
602         if (delegate == null) {
603             return 0;
604         }
605 
606         if (delegate.mFonts.size() > 0) {
607             java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
608             if (fmi != null) {
609                 // Android expects negative ascent so we invert the value from Java.
610                 fmi.top = - javaMetrics.getMaxAscent();
611                 fmi.ascent = - javaMetrics.getAscent();
612                 fmi.descent = javaMetrics.getDescent();
613                 fmi.bottom = javaMetrics.getMaxDescent();
614                 fmi.leading = javaMetrics.getLeading();
615             }
616 
617             return javaMetrics.getHeight();
618         }
619 
620         return 0;
621     }
622 
623     @LayoutlibDelegate
nBreakText(long nativePaint, long nativeTypeface, char[] text, int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth)624     /*package*/ static int nBreakText(long nativePaint, long nativeTypeface, char[] text,
625             int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
626 
627         // get the delegate
628         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
629         if (delegate == null) {
630             return 0;
631         }
632 
633         int inc = count > 0 ? 1 : -1;
634 
635         int measureIndex = 0;
636         for (int i = index; i != index + count; i += inc, measureIndex++) {
637             int start, end;
638             if (i < index) {
639                 start = i;
640                 end = index;
641             } else {
642                 start = index;
643                 end = i;
644             }
645 
646             // measure from start to end
647             RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags);
648             float res = bounds.right - bounds.left;
649 
650             if (measuredWidth != null) {
651                 measuredWidth[measureIndex] = res;
652             }
653 
654             if (res > maxWidth) {
655                 // we should not return this char index, but since it's 0-based
656                 // and we need to return a count, we simply return measureIndex;
657                 return measureIndex;
658             }
659 
660         }
661 
662         return measureIndex;
663     }
664 
665     @LayoutlibDelegate
nBreakText(long nativePaint, long nativeTypeface, String text, boolean measureForwards, float maxWidth, int bidiFlags, float[] measuredWidth)666     /*package*/ static int nBreakText(long nativePaint, long nativeTypeface, String text,
667             boolean measureForwards,
668             float maxWidth, int bidiFlags, float[] measuredWidth) {
669         return nBreakText(nativePaint, nativeTypeface, text.toCharArray(), 0, text.length(),
670                 maxWidth, bidiFlags, measuredWidth);
671     }
672 
673     @LayoutlibDelegate
nInit()674     /*package*/ static long nInit() {
675         Paint_Delegate newDelegate = new Paint_Delegate();
676         return sManager.addNewDelegate(newDelegate);
677     }
678 
679     @LayoutlibDelegate
nInitWithPaint(long paint)680     /*package*/ static long nInitWithPaint(long paint) {
681         // get the delegate from the native int.
682         Paint_Delegate delegate = sManager.getDelegate(paint);
683         if (delegate == null) {
684             return 0;
685         }
686 
687         Paint_Delegate newDelegate = new Paint_Delegate(delegate);
688         return sManager.addNewDelegate(newDelegate);
689     }
690 
691     @LayoutlibDelegate
nReset(long native_object)692     /*package*/ static void nReset(long native_object) {
693         // get the delegate from the native int.
694         Paint_Delegate delegate = sManager.getDelegate(native_object);
695         if (delegate == null) {
696             return;
697         }
698 
699         delegate.reset();
700     }
701 
702     @LayoutlibDelegate
nSet(long native_dst, long native_src)703     /*package*/ static void nSet(long native_dst, long native_src) {
704         // get the delegate from the native int.
705         Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
706         if (delegate_dst == null) {
707             return;
708         }
709 
710         // get the delegate from the native int.
711         Paint_Delegate delegate_src = sManager.getDelegate(native_src);
712         if (delegate_src == null) {
713             return;
714         }
715 
716         delegate_dst.set(delegate_src);
717     }
718 
719     @LayoutlibDelegate
nGetStyle(long native_object)720     /*package*/ static int nGetStyle(long native_object) {
721         // get the delegate from the native int.
722         Paint_Delegate delegate = sManager.getDelegate(native_object);
723         if (delegate == null) {
724             return 0;
725         }
726 
727         return delegate.mStyle;
728     }
729 
730     @LayoutlibDelegate
nSetStyle(long native_object, int style)731     /*package*/ static void nSetStyle(long native_object, int style) {
732         // get the delegate from the native int.
733         Paint_Delegate delegate = sManager.getDelegate(native_object);
734         if (delegate == null) {
735             return;
736         }
737 
738         delegate.mStyle = style;
739     }
740 
741     @LayoutlibDelegate
nGetStrokeCap(long native_object)742     /*package*/ static int nGetStrokeCap(long native_object) {
743         // get the delegate from the native int.
744         Paint_Delegate delegate = sManager.getDelegate(native_object);
745         if (delegate == null) {
746             return 0;
747         }
748 
749         return delegate.mCap;
750     }
751 
752     @LayoutlibDelegate
nSetStrokeCap(long native_object, int cap)753     /*package*/ static void nSetStrokeCap(long native_object, int cap) {
754         // get the delegate from the native int.
755         Paint_Delegate delegate = sManager.getDelegate(native_object);
756         if (delegate == null) {
757             return;
758         }
759 
760         delegate.mCap = cap;
761     }
762 
763     @LayoutlibDelegate
nGetStrokeJoin(long native_object)764     /*package*/ static int nGetStrokeJoin(long native_object) {
765         // get the delegate from the native int.
766         Paint_Delegate delegate = sManager.getDelegate(native_object);
767         if (delegate == null) {
768             return 0;
769         }
770 
771         return delegate.mJoin;
772     }
773 
774     @LayoutlibDelegate
nSetStrokeJoin(long native_object, int join)775     /*package*/ static void nSetStrokeJoin(long native_object, int join) {
776         // get the delegate from the native int.
777         Paint_Delegate delegate = sManager.getDelegate(native_object);
778         if (delegate == null) {
779             return;
780         }
781 
782         delegate.mJoin = join;
783     }
784 
785     @LayoutlibDelegate
nGetFillPath(long native_object, long src, long dst)786     /*package*/ static boolean nGetFillPath(long native_object, long src, long dst) {
787         Paint_Delegate paint = sManager.getDelegate(native_object);
788         if (paint == null) {
789             return false;
790         }
791 
792         Path_Delegate srcPath = Path_Delegate.getDelegate(src);
793         if (srcPath == null) {
794             return true;
795         }
796 
797         Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
798         if (dstPath == null) {
799             return true;
800         }
801 
802         Stroke stroke = paint.getJavaStroke();
803         Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
804 
805         dstPath.setJavaShape(strokeShape);
806 
807         // FIXME figure out the return value?
808         return true;
809     }
810 
811     @LayoutlibDelegate
nSetShader(long native_object, long shader)812     /*package*/ static long nSetShader(long native_object, long shader) {
813         // get the delegate from the native int.
814         Paint_Delegate delegate = sManager.getDelegate(native_object);
815         if (delegate == null) {
816             return shader;
817         }
818 
819         delegate.mShader = Shader_Delegate.getDelegate(shader);
820 
821         return shader;
822     }
823 
824     @LayoutlibDelegate
nSetColorFilter(long native_object, long filter)825     /*package*/ static long nSetColorFilter(long native_object, long filter) {
826         // get the delegate from the native int.
827         Paint_Delegate delegate = sManager.getDelegate(native_object);
828         if (delegate == null) {
829             return filter;
830         }
831 
832         delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);
833 
834         // Log warning if it's not supported.
835         if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) {
836             Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
837                     delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
838         }
839 
840         return filter;
841     }
842 
843     @LayoutlibDelegate
nSetXfermode(long native_object, long xfermode)844     /*package*/ static long nSetXfermode(long native_object, long xfermode) {
845         // get the delegate from the native int.
846         Paint_Delegate delegate = sManager.getDelegate(native_object);
847         if (delegate == null) {
848             return xfermode;
849         }
850 
851         delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
852 
853         return xfermode;
854     }
855 
856     @LayoutlibDelegate
nSetPathEffect(long native_object, long effect)857     /*package*/ static long nSetPathEffect(long native_object, long effect) {
858         // get the delegate from the native int.
859         Paint_Delegate delegate = sManager.getDelegate(native_object);
860         if (delegate == null) {
861             return effect;
862         }
863 
864         delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
865 
866         return effect;
867     }
868 
869     @LayoutlibDelegate
nSetMaskFilter(long native_object, long maskfilter)870     /*package*/ static long nSetMaskFilter(long native_object, long maskfilter) {
871         // get the delegate from the native int.
872         Paint_Delegate delegate = sManager.getDelegate(native_object);
873         if (delegate == null) {
874             return maskfilter;
875         }
876 
877         delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
878 
879         // since none of those are supported, display a fidelity warning right away
880         if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) {
881             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
882                     delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
883         }
884 
885         return maskfilter;
886     }
887 
888     @LayoutlibDelegate
nSetTypeface(long native_object, long typeface)889     /*package*/ static long nSetTypeface(long native_object, long typeface) {
890         // get the delegate from the native int.
891         Paint_Delegate delegate = sManager.getDelegate(native_object);
892         if (delegate == null) {
893             return 0;
894         }
895 
896         Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface);
897         if (delegate.mTypeface != typefaceDelegate || delegate.mNativeTypeface != typeface) {
898             delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
899             delegate.mNativeTypeface = typeface;
900             delegate.updateFontObject();
901         }
902         return typeface;
903     }
904 
905     @LayoutlibDelegate
nSetRasterizer(long native_object, long rasterizer)906     /*package*/ static long nSetRasterizer(long native_object, long rasterizer) {
907         // get the delegate from the native int.
908         Paint_Delegate delegate = sManager.getDelegate(native_object);
909         if (delegate == null) {
910             return rasterizer;
911         }
912 
913         delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
914 
915         // since none of those are supported, display a fidelity warning right away
916         if (delegate.mRasterizer != null && !delegate.mRasterizer.isSupported()) {
917             Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
918                     delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
919         }
920 
921         return rasterizer;
922     }
923 
924     @LayoutlibDelegate
nGetTextAlign(long native_object)925     /*package*/ static int nGetTextAlign(long native_object) {
926         // get the delegate from the native int.
927         Paint_Delegate delegate = sManager.getDelegate(native_object);
928         if (delegate == null) {
929             return 0;
930         }
931 
932         return delegate.mTextAlign;
933     }
934 
935     @LayoutlibDelegate
nSetTextAlign(long native_object, int align)936     /*package*/ static void nSetTextAlign(long native_object, int align) {
937         // get the delegate from the native int.
938         Paint_Delegate delegate = sManager.getDelegate(native_object);
939         if (delegate == null) {
940             return;
941         }
942 
943         delegate.mTextAlign = align;
944     }
945 
946     @LayoutlibDelegate
nSetTextLocales(long native_object, String locale)947     /*package*/ static int nSetTextLocales(long native_object, String locale) {
948         // get the delegate from the native int.
949         Paint_Delegate delegate = sManager.getDelegate(native_object);
950         if (delegate == null) {
951             return 0;
952         }
953 
954         delegate.setTextLocale(locale);
955         return 0;
956     }
957 
958     @LayoutlibDelegate
nSetTextLocalesByMinikinLangListId(long paintPtr, int mMinikinLangListId)959     /*package*/ static void nSetTextLocalesByMinikinLangListId(long paintPtr,
960             int mMinikinLangListId) {
961         // FIXME
962     }
963 
964     @LayoutlibDelegate
nGetTextAdvances(long native_object, long native_typeface, char[] text, int index, int count, int contextIndex, int contextCount, int bidiFlags, float[] advances, int advancesIndex)965     /*package*/ static float nGetTextAdvances(long native_object, long native_typeface,
966             char[] text, int index, int count, int contextIndex, int contextCount,
967             int bidiFlags, float[] advances, int advancesIndex) {
968 
969         if (advances != null)
970             for (int i = advancesIndex; i< advancesIndex+count; i++)
971                 advances[i]=0;
972         // get the delegate from the native int.
973         Paint_Delegate delegate = sManager.getDelegate(native_object);
974         if (delegate == null) {
975             return 0.f;
976         }
977 
978         // native_typeface is passed here since Framework's old implementation did not have the
979         // typeface object associated with the Paint. Since, we follow the new framework way,
980         // we store the typeface with the paint and use it directly.
981         assert (native_typeface == delegate.mNativeTypeface);
982 
983         RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, bidiFlags);
984         return bounds.right - bounds.left;
985     }
986 
987     @LayoutlibDelegate
nGetTextAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex)988     /*package*/ static float nGetTextAdvances(long native_object, long native_typeface,
989             String text, int start, int end, int contextStart, int contextEnd,
990             int bidiFlags, float[] advances, int advancesIndex) {
991         // FIXME: support contextStart and contextEnd
992         int count = end - start;
993         char[] buffer = TemporaryBuffer.obtain(count);
994         TextUtils.getChars(text, start, end, buffer, 0);
995 
996         return nGetTextAdvances(native_object, native_typeface, buffer, 0, count,
997                 contextStart, contextEnd - contextStart, bidiFlags, advances, advancesIndex);
998     }
999 
1000     @LayoutlibDelegate
nGetTextRunCursor(Paint thisPaint, long native_object, char[] text, int contextStart, int contextLength, int flags, int offset, int cursorOpt)1001     /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, char[] text,
1002             int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
1003         // FIXME
1004         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1005                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
1006         return 0;
1007     }
1008 
1009     @LayoutlibDelegate
nGetTextRunCursor(Paint thisPaint, long native_object, String text, int contextStart, int contextEnd, int flags, int offset, int cursorOpt)1010     /*package*/ static int nGetTextRunCursor(Paint thisPaint, long native_object, String text,
1011             int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
1012         // FIXME
1013         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1014                 "Paint.getTextRunCursor is not supported.", null, null /*data*/);
1015         return 0;
1016     }
1017 
1018     @LayoutlibDelegate
nGetTextPath(long native_object, long native_typeface, int bidiFlags, char[] text, int index, int count, float x, float y, long path)1019     /*package*/ static void nGetTextPath(long native_object, long native_typeface,
1020             int bidiFlags, char[] text, int index, int count, float x, float y, long path) {
1021         // FIXME
1022         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1023                 "Paint.getTextPath is not supported.", null, null /*data*/);
1024     }
1025 
1026     @LayoutlibDelegate
nGetTextPath(long native_object, long native_typeface, int bidiFlags, String text, int start, int end, float x, float y, long path)1027     /*package*/ static void nGetTextPath(long native_object, long native_typeface,
1028             int bidiFlags, String text, int start, int end, float x, float y, long path) {
1029         // FIXME
1030         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
1031                 "Paint.getTextPath is not supported.", null, null /*data*/);
1032     }
1033 
1034     @LayoutlibDelegate
nGetStringBounds(long nativePaint, long native_typeface, String text, int start, int end, int bidiFlags, Rect bounds)1035     /*package*/ static void nGetStringBounds(long nativePaint, long native_typeface,
1036             String text, int start, int end, int bidiFlags, Rect bounds) {
1037         nGetCharArrayBounds(nativePaint, native_typeface, text.toCharArray(), start,
1038                 end - start, bidiFlags, bounds);
1039     }
1040 
1041     @LayoutlibDelegate
nGetCharArrayBounds(long nativePaint, long native_typeface, char[] text, int index, int count, int bidiFlags, Rect bounds)1042     /*package*/ static void nGetCharArrayBounds(long nativePaint, long native_typeface,
1043             char[] text, int index, int count, int bidiFlags, Rect bounds) {
1044 
1045         // get the delegate from the native int.
1046         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1047         if (delegate == null) {
1048             return;
1049         }
1050 
1051         // assert that the typeface passed is actually the one that we had stored.
1052         assert (native_typeface == delegate.mNativeTypeface);
1053 
1054         delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds);
1055     }
1056 
1057     @LayoutlibDelegate
nGetNativeFinalizer()1058     /*package*/ static long nGetNativeFinalizer() {
1059         synchronized (Paint_Delegate.class) {
1060             if (sFinalizer == -1) {
1061                 sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
1062                         sManager::removeJavaReferenceFor);
1063             }
1064         }
1065         return sFinalizer;
1066     }
1067 
1068     @LayoutlibDelegate
nGetLetterSpacing(long nativePaint)1069     /*package*/ static float nGetLetterSpacing(long nativePaint) {
1070         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1071         if (delegate == null) {
1072             return 0;
1073         }
1074         return delegate.mLetterSpacing;
1075     }
1076 
1077     @LayoutlibDelegate
nSetLetterSpacing(long nativePaint, float letterSpacing)1078     /*package*/ static void nSetLetterSpacing(long nativePaint, float letterSpacing) {
1079         Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
1080                 "Paint.setLetterSpacing() not supported.", null, null);
1081         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1082         if (delegate == null) {
1083             return;
1084         }
1085         delegate.mLetterSpacing = letterSpacing;
1086     }
1087 
1088     @LayoutlibDelegate
nSetFontFeatureSettings(long nativePaint, String settings)1089     /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) {
1090         Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
1091                 "Paint.setFontFeatureSettings() not supported.", null, null);
1092     }
1093 
1094     @LayoutlibDelegate
nGetHyphenEdit(long nativePaint)1095     /*package*/ static int nGetHyphenEdit(long nativePaint) {
1096         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1097         if (delegate == null) {
1098             return 0;
1099         }
1100         return delegate.mHyphenEdit;
1101     }
1102 
1103     @LayoutlibDelegate
nSetHyphenEdit(long nativePaint, int hyphen)1104     /*package*/ static void nSetHyphenEdit(long nativePaint, int hyphen) {
1105         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1106         if (delegate == null) {
1107             return;
1108         }
1109         delegate.mHyphenEdit = hyphen;
1110     }
1111 
1112     @LayoutlibDelegate
nHasGlyph(long nativePaint, long nativeTypeface, int bidiFlags, String string)1113     /*package*/ static boolean nHasGlyph(long nativePaint, long nativeTypeface, int bidiFlags,
1114             String string) {
1115         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1116         if (delegate == null) {
1117             return false;
1118         }
1119         if (string.length() == 0) {
1120             return false;
1121         }
1122         if (string.length() > 1) {
1123             Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
1124                     "Paint.hasGlyph() is not supported for ligatures.", null, null);
1125             return false;
1126         }
1127         assert nativeTypeface == delegate.mNativeTypeface;
1128         Typeface_Delegate typeface_delegate = Typeface_Delegate.getDelegate(nativeTypeface);
1129 
1130         char c = string.charAt(0);
1131         for (Font font : typeface_delegate.getFonts(delegate.mFontVariant)) {
1132             if (font.canDisplay(c)) {
1133                 return true;
1134             }
1135         }
1136         return false;
1137     }
1138 
1139 
1140     @LayoutlibDelegate
nGetRunAdvance(long nativePaint, long nativeTypeface, @NonNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset)1141     /*package*/ static float nGetRunAdvance(long nativePaint, long nativeTypeface,
1142             @NonNull char[] text, int start, int end, int contextStart, int contextEnd,
1143             boolean isRtl, int offset) {
1144         int count = end - start;
1145         float[] advances = new float[count];
1146         int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
1147         nGetTextAdvances(nativePaint, nativeTypeface, text, start, count,
1148                 contextStart, contextEnd - contextStart, bidiFlags, advances, 0);
1149         int startOffset = offset - start;  // offset from start.
1150         float sum = 0;
1151         for (int i = 0; i < startOffset; i++) {
1152             sum += advances[i];
1153         }
1154         return sum;
1155     }
1156 
1157     @LayoutlibDelegate
nGetOffsetForAdvance(long nativePaint, long nativeTypeface, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)1158     /*package*/ static int nGetOffsetForAdvance(long nativePaint, long nativeTypeface,
1159             char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl,
1160             float advance) {
1161         int count = end - start;
1162         float[] advances = new float[count];
1163         int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
1164         nGetTextAdvances(nativePaint, nativeTypeface, text, start, count,
1165                 contextStart, contextEnd - contextStart, bidiFlags, advances, 0);
1166         float sum = 0;
1167         int i;
1168         for (i = 0; i < count && sum < advance; i++) {
1169             sum += advances[i];
1170         }
1171         float distanceToI = sum - advance;
1172         float distanceToIMinus1 = advance - (sum - advances[i]);
1173         return distanceToI > distanceToIMinus1 ? i : i - 1;
1174     }
1175 
1176     // ---- Private delegate/helper methods ----
1177 
Paint_Delegate()1178     /*package*/ Paint_Delegate() {
1179         reset();
1180     }
1181 
Paint_Delegate(Paint_Delegate paint)1182     private Paint_Delegate(Paint_Delegate paint) {
1183         set(paint);
1184     }
1185 
set(Paint_Delegate paint)1186     private void set(Paint_Delegate paint) {
1187         mFlags = paint.mFlags;
1188         mColor = paint.mColor;
1189         mStyle = paint.mStyle;
1190         mCap = paint.mCap;
1191         mJoin = paint.mJoin;
1192         mTextAlign = paint.mTextAlign;
1193 
1194         boolean needsFontUpdate = false;
1195         if (mTypeface != paint.mTypeface || mNativeTypeface != paint.mNativeTypeface) {
1196             mTypeface = paint.mTypeface;
1197             mNativeTypeface = paint.mNativeTypeface;
1198             needsFontUpdate = true;
1199         }
1200 
1201         if (mTextSize != paint.mTextSize) {
1202             mTextSize = paint.mTextSize;
1203             needsFontUpdate = true;
1204         }
1205 
1206         if (mTextScaleX != paint.mTextScaleX) {
1207             mTextScaleX = paint.mTextScaleX;
1208             needsFontUpdate = true;
1209         }
1210 
1211         if (mTextSkewX != paint.mTextSkewX) {
1212             mTextSkewX = paint.mTextSkewX;
1213             needsFontUpdate = true;
1214         }
1215 
1216         mStrokeWidth = paint.mStrokeWidth;
1217         mStrokeMiter = paint.mStrokeMiter;
1218         mXfermode = paint.mXfermode;
1219         mColorFilter = paint.mColorFilter;
1220         mShader = paint.mShader;
1221         mPathEffect = paint.mPathEffect;
1222         mMaskFilter = paint.mMaskFilter;
1223         mRasterizer = paint.mRasterizer;
1224         mHintingMode = paint.mHintingMode;
1225 
1226         if (needsFontUpdate) {
1227             updateFontObject();
1228         }
1229     }
1230 
reset()1231     private void reset() {
1232         mFlags = Paint.HIDDEN_DEFAULT_PAINT_FLAGS;
1233         mColor = 0xFF000000;
1234         mStyle = Paint.Style.FILL.nativeInt;
1235         mCap = Paint.Cap.BUTT.nativeInt;
1236         mJoin = Paint.Join.MITER.nativeInt;
1237         mTextAlign = 0;
1238         mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
1239         mNativeTypeface = 0;
1240         mStrokeWidth = 1.f;
1241         mStrokeMiter = 4.f;
1242         mTextSize = 20.f;
1243         mTextScaleX = 1.f;
1244         mTextSkewX = 0.f;
1245         mXfermode = null;
1246         mColorFilter = null;
1247         mShader = null;
1248         mPathEffect = null;
1249         mMaskFilter = null;
1250         mRasterizer = null;
1251         updateFontObject();
1252         mHintingMode = Paint.HINTING_ON;
1253     }
1254 
1255     /**
1256      * Update the {@link Font} object from the typeface, text size and scaling
1257      */
1258     @SuppressWarnings("deprecation")
updateFontObject()1259     private void updateFontObject() {
1260         if (mTypeface != null) {
1261             // Get the fonts from the TypeFace object.
1262             List<Font> fonts = mTypeface.getFonts(mFontVariant);
1263 
1264             if (fonts.isEmpty()) {
1265                 mFonts = Collections.emptyList();
1266                 return;
1267             }
1268 
1269             // create new font objects as well as FontMetrics, based on the current text size
1270             // and skew info.
1271             int nFonts = fonts.size();
1272             ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(nFonts);
1273             //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
1274             for (int i = 0; i < nFonts; i++) {
1275                 Font font = fonts.get(i);
1276                 if (font == null) {
1277                     // If the font is null, add null to infoList. When rendering the text, if this
1278                     // null is reached, a warning will be logged.
1279                     infoList.add(null);
1280                     continue;
1281                 }
1282                 FontInfo info = new FontInfo();
1283                 info.mFont = font.deriveFont(mTextSize);
1284                 if (mTextScaleX != 1.0 || mTextSkewX != 0) {
1285                     // TODO: support skew
1286                     info.mFont = info.mFont.deriveFont(new AffineTransform(
1287                             mTextScaleX, mTextSkewX, 0, 1, 0, 0));
1288                 }
1289                 // The metrics here don't have anti-aliasing set.
1290                 info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
1291 
1292                 infoList.add(info);
1293             }
1294 
1295             mFonts = Collections.unmodifiableList(infoList);
1296         }
1297     }
1298 
measureText(char[] text, int index, int count, float[] advances, int advancesIndex, int bidiFlags)1299     /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
1300             int advancesIndex, int bidiFlags) {
1301         return new BidiRenderer(null, this, text)
1302                 .renderText(index, index + count, bidiFlags, advances, advancesIndex, false);
1303     }
1304 
measureText(char[] text, int index, int count, float[] advances, int advancesIndex, boolean isRtl)1305     /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
1306             int advancesIndex, boolean isRtl) {
1307         return new BidiRenderer(null, this, text)
1308                 .renderText(index, index + count, isRtl, advances, advancesIndex, false);
1309     }
1310 
getFontMetrics(FontMetrics metrics)1311     private float getFontMetrics(FontMetrics metrics) {
1312         if (mFonts.size() > 0) {
1313             java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
1314             if (metrics != null) {
1315                 // Android expects negative ascent so we invert the value from Java.
1316                 metrics.top = - javaMetrics.getMaxAscent();
1317                 metrics.ascent = - javaMetrics.getAscent();
1318                 metrics.descent = javaMetrics.getDescent();
1319                 metrics.bottom = javaMetrics.getMaxDescent();
1320                 metrics.leading = javaMetrics.getLeading();
1321             }
1322 
1323             return javaMetrics.getHeight();
1324         }
1325 
1326         return 0;
1327     }
1328 
setTextLocale(String locale)1329     private void setTextLocale(String locale) {
1330         mLocale = new Locale(locale);
1331     }
1332 
setFlag(long nativePaint, int flagMask, boolean flagValue)1333     private static void setFlag(long nativePaint, int flagMask, boolean flagValue) {
1334         // get the delegate from the native int.
1335         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
1336         if (delegate == null) {
1337             return;
1338         }
1339 
1340         if (flagValue) {
1341             delegate.mFlags |= flagMask;
1342         } else {
1343             delegate.mFlags &= ~flagMask;
1344         }
1345     }
1346 }
1347