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