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