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