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