NinePatchDrawable.java revision a426445dfdab43886dd894f2ba8a1d55bfcbb278
1/*
2 * Copyright (C) 2006 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
17package android.graphics.drawable;
18
19import android.annotation.NonNull;
20import android.content.res.ColorStateList;
21import android.content.res.Resources;
22import android.content.res.Resources.Theme;
23import android.content.res.TypedArray;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
26import android.graphics.Canvas;
27import android.graphics.ColorFilter;
28import android.graphics.Insets;
29import android.graphics.NinePatch;
30import android.graphics.Outline;
31import android.graphics.Paint;
32import android.graphics.PixelFormat;
33import android.graphics.PorterDuff;
34import android.graphics.PorterDuff.Mode;
35import android.graphics.PorterDuffColorFilter;
36import android.graphics.Rect;
37import android.graphics.Region;
38import android.util.AttributeSet;
39import android.util.DisplayMetrics;
40import android.util.LayoutDirection;
41import android.util.TypedValue;
42
43import com.android.internal.R;
44
45import org.xmlpull.v1.XmlPullParser;
46import org.xmlpull.v1.XmlPullParserException;
47
48import java.io.IOException;
49import java.io.InputStream;
50
51/**
52 *
53 * A resizeable bitmap, with stretchable areas that you define. This type of image
54 * is defined in a .png file with a special format.
55 *
56 * <div class="special reference">
57 * <h3>Developer Guides</h3>
58 * <p>For more information about how to use a NinePatchDrawable, read the
59 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">
60 * Canvas and Drawables</a> developer guide. For information about creating a NinePatch image
61 * file using the draw9patch tool, see the
62 * <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-patch</a> tool guide.</p></div>
63 */
64public class NinePatchDrawable extends Drawable {
65    // dithering helps a lot, and is pretty cheap, so default is true
66    private static final boolean DEFAULT_DITHER = false;
67    private NinePatchState mNinePatchState;
68    private NinePatch mNinePatch;
69    private PorterDuffColorFilter mTintFilter;
70    private Rect mPadding;
71    private Insets mOpticalInsets = Insets.NONE;
72    private Paint mPaint;
73    private boolean mMutated;
74
75    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
76
77    // These are scaled to match the target density.
78    private int mBitmapWidth = -1;
79    private int mBitmapHeight = -1;
80
81    NinePatchDrawable() {
82        mNinePatchState = new NinePatchState();
83    }
84
85    /**
86     * Create drawable from raw nine-patch data, not dealing with density.
87     * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
88     * to ensure that the drawable has correctly set its target density.
89     */
90    @Deprecated
91    public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
92        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null, null);
93    }
94
95    /**
96     * Create drawable from raw nine-patch data, setting initial target density
97     * based on the display metrics of the resources.
98     */
99    public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
100            Rect padding, String srcName) {
101        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res, null);
102        mNinePatchState.mTargetDensity = mTargetDensity;
103    }
104
105    /**
106     * Create drawable from raw nine-patch data, setting initial target density
107     * based on the display metrics of the resources.
108     *
109     * @hide
110     */
111    public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
112            Rect padding, Rect opticalInsets, String srcName) {
113        this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
114                res, null);
115        mNinePatchState.mTargetDensity = mTargetDensity;
116    }
117
118    /**
119     * Create drawable from existing nine-patch, not dealing with density.
120     * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
121     * to ensure that the drawable has correctly set its target density.
122     */
123    @Deprecated
124    public NinePatchDrawable(NinePatch patch) {
125        this(new NinePatchState(patch, new Rect()), null, null);
126    }
127
128    /**
129     * Create drawable from existing nine-patch, setting initial target density
130     * based on the display metrics of the resources.
131     */
132    public NinePatchDrawable(Resources res, NinePatch patch) {
133        this(new NinePatchState(patch, new Rect()), res, null);
134        mNinePatchState.mTargetDensity = mTargetDensity;
135    }
136
137    /**
138     * Set the density scale at which this drawable will be rendered. This
139     * method assumes the drawable will be rendered at the same density as the
140     * specified canvas.
141     *
142     * @param canvas The Canvas from which the density scale must be obtained.
143     *
144     * @see android.graphics.Bitmap#setDensity(int)
145     * @see android.graphics.Bitmap#getDensity()
146     */
147    public void setTargetDensity(Canvas canvas) {
148        setTargetDensity(canvas.getDensity());
149    }
150
151    /**
152     * Set the density scale at which this drawable will be rendered.
153     *
154     * @param metrics The DisplayMetrics indicating the density scale for this drawable.
155     *
156     * @see android.graphics.Bitmap#setDensity(int)
157     * @see android.graphics.Bitmap#getDensity()
158     */
159    public void setTargetDensity(DisplayMetrics metrics) {
160        setTargetDensity(metrics.densityDpi);
161    }
162
163    /**
164     * Set the density at which this drawable will be rendered.
165     *
166     * @param density The density scale for this drawable.
167     *
168     * @see android.graphics.Bitmap#setDensity(int)
169     * @see android.graphics.Bitmap#getDensity()
170     */
171    public void setTargetDensity(int density) {
172        if (density != mTargetDensity) {
173            mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
174            if (mNinePatch != null) {
175                computeBitmapSize();
176            }
177            invalidateSelf();
178        }
179    }
180
181    private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) {
182        int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity);
183        int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity);
184        int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity);
185        int bottom = Bitmap.scaleFromDensity(insets.bottom, sdensity, tdensity);
186        return Insets.of(left, top, right, bottom);
187    }
188
189    private void computeBitmapSize() {
190        final int sdensity = mNinePatch.getDensity();
191        final int tdensity = mTargetDensity;
192        if (sdensity == tdensity) {
193            mBitmapWidth = mNinePatch.getWidth();
194            mBitmapHeight = mNinePatch.getHeight();
195            mOpticalInsets = mNinePatchState.mOpticalInsets;
196        } else {
197            mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity);
198            mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), sdensity, tdensity);
199            if (mNinePatchState.mPadding != null && mPadding != null) {
200                Rect dest = mPadding;
201                Rect src = mNinePatchState.mPadding;
202                if (dest == src) {
203                    mPadding = dest = new Rect(src);
204                }
205                dest.left = Bitmap.scaleFromDensity(src.left, sdensity, tdensity);
206                dest.top = Bitmap.scaleFromDensity(src.top, sdensity, tdensity);
207                dest.right = Bitmap.scaleFromDensity(src.right, sdensity, tdensity);
208                dest.bottom = Bitmap.scaleFromDensity(src.bottom, sdensity, tdensity);
209            }
210            mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity);
211        }
212    }
213
214    private void setNinePatch(NinePatch ninePatch) {
215        if (mNinePatch != ninePatch) {
216            mNinePatch = ninePatch;
217            if (ninePatch != null) {
218                computeBitmapSize();
219            } else {
220                mBitmapWidth = mBitmapHeight = -1;
221                mOpticalInsets = Insets.NONE;
222            }
223            invalidateSelf();
224        }
225    }
226
227    @Override
228    public void draw(Canvas canvas) {
229        final Rect bounds = getBounds();
230
231        final boolean clearColorFilter;
232        if (mTintFilter != null && getPaint().getColorFilter() == null) {
233            mPaint.setColorFilter(mTintFilter);
234            clearColorFilter = true;
235        } else {
236            clearColorFilter = false;
237        }
238
239        final boolean needsMirroring = needsMirroring();
240        if (needsMirroring) {
241            // Mirror the 9patch
242            canvas.translate(bounds.right - bounds.left, 0);
243            canvas.scale(-1.0f, 1.0f);
244        }
245
246        final int restoreAlpha;
247        if (mNinePatchState.mBaseAlpha != 1.0f) {
248            restoreAlpha = mPaint.getAlpha();
249            mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f));
250        } else {
251            restoreAlpha = -1;
252        }
253
254        mNinePatch.draw(canvas, bounds, mPaint);
255
256        if (clearColorFilter) {
257            mPaint.setColorFilter(null);
258        }
259
260        if (restoreAlpha >= 0) {
261            mPaint.setAlpha(restoreAlpha);
262        }
263    }
264
265    @Override
266    public int getChangingConfigurations() {
267        return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
268    }
269
270    @Override
271    public boolean getPadding(Rect padding) {
272        final Rect scaledPadding = mPadding;
273        if (scaledPadding != null) {
274            if (needsMirroring()) {
275                padding.set(scaledPadding.right, scaledPadding.top,
276                        scaledPadding.left, scaledPadding.bottom);
277            } else {
278                padding.set(scaledPadding);
279            }
280            return (padding.left | padding.top | padding.right | padding.bottom) != 0;
281        }
282        return false;
283    }
284
285    @Override
286    public void getOutline(@NonNull Outline outline) {
287        final Rect bounds = getBounds();
288        if (bounds.isEmpty()) return;
289
290        if (mNinePatchState != null) {
291            NinePatch.InsetStruct insets = mNinePatchState.getBitmap().getNinePatchInsets();
292            if (insets != null) {
293                final Rect outlineInsets = insets.outlineRect;
294                outline.setRoundRect(bounds.left + outlineInsets.left,
295                        bounds.top + outlineInsets.top,
296                        bounds.right - outlineInsets.right,
297                        bounds.bottom - outlineInsets.bottom,
298                        insets.outlineRadius);
299                outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
300                return;
301            }
302        }
303        super.getOutline(outline);
304    }
305
306    /**
307     * @hide
308     */
309    @Override
310    public Insets getOpticalInsets() {
311        if (needsMirroring()) {
312            return Insets.of(mOpticalInsets.right, mOpticalInsets.top,
313                    mOpticalInsets.left, mOpticalInsets.bottom);
314        } else {
315            return mOpticalInsets;
316        }
317    }
318
319    @Override
320    public void setAlpha(int alpha) {
321        if (mPaint == null && alpha == 0xFF) {
322            // Fast common case -- leave at normal alpha.
323            return;
324        }
325        getPaint().setAlpha(alpha);
326        invalidateSelf();
327    }
328
329    @Override
330    public int getAlpha() {
331        if (mPaint == null) {
332            // Fast common case -- normal alpha.
333            return 0xFF;
334        }
335        return getPaint().getAlpha();
336    }
337
338    @Override
339    public void setColorFilter(ColorFilter cf) {
340        if (mPaint == null && cf == null) {
341            // Fast common case -- leave at no color filter.
342            return;
343        }
344        getPaint().setColorFilter(cf);
345        invalidateSelf();
346    }
347
348    @Override
349    public void setTintList(ColorStateList tint) {
350        mNinePatchState.mTint = tint;
351        mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
352        invalidateSelf();
353    }
354
355    @Override
356    public void setTintMode(PorterDuff.Mode tintMode) {
357        mNinePatchState.mTintMode = tintMode;
358        mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
359        invalidateSelf();
360    }
361
362    @Override
363    public void setDither(boolean dither) {
364        //noinspection PointlessBooleanExpression
365        if (mPaint == null && dither == DEFAULT_DITHER) {
366            // Fast common case -- leave at default dither.
367            return;
368        }
369
370        getPaint().setDither(dither);
371        invalidateSelf();
372    }
373
374    @Override
375    public void setAutoMirrored(boolean mirrored) {
376        mNinePatchState.mAutoMirrored = mirrored;
377    }
378
379    private boolean needsMirroring() {
380        return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
381    }
382
383    @Override
384    public boolean isAutoMirrored() {
385        return mNinePatchState.mAutoMirrored;
386    }
387
388    @Override
389    public void setFilterBitmap(boolean filter) {
390        getPaint().setFilterBitmap(filter);
391        invalidateSelf();
392    }
393
394    @Override
395    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
396            throws XmlPullParserException, IOException {
397        super.inflate(r, parser, attrs, theme);
398
399        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
400        updateStateFromTypedArray(a);
401        a.recycle();
402    }
403
404    /**
405     * Updates the constant state from the values in the typed array.
406     */
407    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
408        final Resources r = a.getResources();
409        final NinePatchState state = mNinePatchState;
410
411        // Account for any configuration changes.
412        state.mChangingConfigurations |= a.getChangingConfigurations();
413
414        // Extract the theme attributes, if any.
415        state.mThemeAttrs = a.extractThemeAttrs();
416
417        state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither);
418
419        final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
420        if (srcResId != 0) {
421            final BitmapFactory.Options options = new BitmapFactory.Options();
422            options.inDither = !state.mDither;
423            options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
424
425            final Rect padding = new Rect();
426            final Rect opticalInsets = new Rect();
427            Bitmap bitmap = null;
428
429            try {
430                final TypedValue value = new TypedValue();
431                final InputStream is = r.openRawResource(srcResId, value);
432
433                bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
434
435                is.close();
436            } catch (IOException e) {
437                // Ignore
438            }
439
440            if (bitmap == null) {
441                throw new XmlPullParserException(a.getPositionDescription() +
442                        ": <nine-patch> requires a valid src attribute");
443            } else if (bitmap.getNinePatchChunk() == null) {
444                throw new XmlPullParserException(a.getPositionDescription() +
445                        ": <nine-patch> requires a valid 9-patch source image");
446            }
447
448            // Hey, now might be a good time to actually load optical bounds!
449            bitmap.getOpticalInsets(opticalInsets);
450
451            // Sanity check for valid padding when we have optical insets.
452            if (padding.left < opticalInsets.left) {
453                padding.left = opticalInsets.left;
454                padding.right = opticalInsets.right;
455            }
456            if (padding.top < opticalInsets.top) {
457                padding.top = opticalInsets.top;
458                padding.bottom = opticalInsets.bottom;
459            }
460
461            state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
462            state.mPadding = padding;
463            state.mOpticalInsets = Insets.of(opticalInsets);
464        }
465
466        state.mAutoMirrored = a.getBoolean(
467                R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored);
468        state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha);
469
470        final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
471        if (tintMode != -1) {
472            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
473        }
474
475        final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
476        if (tint != null) {
477            state.mTint = tint;
478        }
479
480        // Update local properties.
481        initializeWithState(state, r);
482
483        // Push density applied by setNinePatchState into state.
484        state.mTargetDensity = mTargetDensity;
485    }
486
487    @Override
488    public void applyTheme(Theme t) {
489        super.applyTheme(t);
490
491        final NinePatchState state = mNinePatchState;
492        if (state == null || state.mThemeAttrs == null) {
493            return;
494        }
495
496        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
497        try {
498            updateStateFromTypedArray(a);
499        } catch (XmlPullParserException e) {
500            throw new RuntimeException(e);
501        } finally {
502            a.recycle();
503        }
504    }
505
506    @Override
507    public boolean canApplyTheme() {
508        return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
509    }
510
511    public Paint getPaint() {
512        if (mPaint == null) {
513            mPaint = new Paint();
514            mPaint.setDither(DEFAULT_DITHER);
515        }
516        return mPaint;
517    }
518
519    /**
520     * Retrieves the width of the source .png file (before resizing).
521     */
522    @Override
523    public int getIntrinsicWidth() {
524        return mBitmapWidth;
525    }
526
527    /**
528     * Retrieves the height of the source .png file (before resizing).
529     */
530    @Override
531    public int getIntrinsicHeight() {
532        return mBitmapHeight;
533    }
534
535    @Override
536    public int getMinimumWidth() {
537        return mBitmapWidth;
538    }
539
540    @Override
541    public int getMinimumHeight() {
542        return mBitmapHeight;
543    }
544
545    /**
546     * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat}
547     * value of OPAQUE or TRANSLUCENT.
548     */
549    @Override
550    public int getOpacity() {
551        return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ?
552                PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
553    }
554
555    @Override
556    public Region getTransparentRegion() {
557        return mNinePatch.getTransparentRegion(getBounds());
558    }
559
560    @Override
561    public ConstantState getConstantState() {
562        mNinePatchState.mChangingConfigurations = getChangingConfigurations();
563        return mNinePatchState;
564    }
565
566    @Override
567    public Drawable mutate() {
568        if (!mMutated && super.mutate() == this) {
569            mNinePatchState = new NinePatchState(mNinePatchState);
570            mNinePatch = mNinePatchState.mNinePatch;
571            mMutated = true;
572        }
573        return this;
574    }
575
576    @Override
577    protected boolean onStateChange(int[] stateSet) {
578        final NinePatchState state = mNinePatchState;
579        if (state.mTint != null && state.mTintMode != null) {
580            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
581            return true;
582        }
583
584        return false;
585    }
586
587    @Override
588    public boolean isStateful() {
589        final NinePatchState s = mNinePatchState;
590        return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
591    }
592
593    final static class NinePatchState extends ConstantState {
594        // Values loaded during inflation.
595        int[] mThemeAttrs = null;
596        NinePatch mNinePatch = null;
597        ColorStateList mTint = null;
598        Mode mTintMode = Mode.SRC_IN;
599        Rect mPadding = null;
600        Insets mOpticalInsets = Insets.NONE;
601        float mBaseAlpha = 1.0f;
602        boolean mDither = DEFAULT_DITHER;
603        int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
604        boolean mAutoMirrored = false;
605
606        int mChangingConfigurations;
607
608        NinePatchState() {
609            // Empty constructor.
610        }
611
612        NinePatchState(NinePatch ninePatch, Rect padding) {
613            this(ninePatch, padding, null, DEFAULT_DITHER, false);
614        }
615
616        NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) {
617            this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false);
618        }
619
620        NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets, boolean dither,
621                boolean autoMirror) {
622            mNinePatch = ninePatch;
623            mPadding = padding;
624            mOpticalInsets = Insets.of(opticalInsets);
625            mDither = dither;
626            mAutoMirrored = autoMirror;
627
628            // Sanity check for valid padding when we have optical insets.
629            if (mPadding.left < mOpticalInsets.left) {
630                mPadding.left = mOpticalInsets.left;
631                mPadding.right = mOpticalInsets.right;
632            }
633            if (mPadding.top < mOpticalInsets.top) {
634                mPadding.top = mOpticalInsets.top;
635                mPadding.bottom = mOpticalInsets.bottom;
636            }
637        }
638
639        // Copy constructor
640
641        NinePatchState(NinePatchState state) {
642            // We don't deep-copy any fields because they are all immutable.
643            mNinePatch = state.mNinePatch;
644            mTint = state.mTint;
645            mTintMode = state.mTintMode;
646            mThemeAttrs = state.mThemeAttrs;
647            mPadding = state.mPadding;
648            mOpticalInsets = state.mOpticalInsets;
649            mBaseAlpha = state.mBaseAlpha;
650            mDither = state.mDither;
651            mChangingConfigurations = state.mChangingConfigurations;
652            mTargetDensity = state.mTargetDensity;
653            mAutoMirrored = state.mAutoMirrored;
654        }
655
656        @Override
657        public boolean canApplyTheme() {
658            return mThemeAttrs != null;
659        }
660
661        @Override
662        public Bitmap getBitmap() {
663            return mNinePatch.getBitmap();
664        }
665
666        @Override
667        public Drawable newDrawable() {
668            return new NinePatchDrawable(this, null, null);
669        }
670
671        @Override
672        public Drawable newDrawable(Resources res) {
673            return new NinePatchDrawable(this, res, null);
674        }
675
676        @Override
677        public Drawable newDrawable(Resources res, Theme theme) {
678            return new NinePatchDrawable(this, res, theme);
679        }
680
681        @Override
682        public int getChangingConfigurations() {
683            return mChangingConfigurations;
684        }
685    }
686
687    /**
688     * The one constructor to rule them all. This is called by all public
689     * constructors to set the state and initialize local properties.
690     */
691    private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
692        if (theme != null && state.canApplyTheme()) {
693            // If we need to apply a theme, implicitly mutate.
694            mNinePatchState = new NinePatchState(state);
695            applyTheme(theme);
696        } else {
697            mNinePatchState = state;
698        }
699
700        initializeWithState(state, res);
701    }
702
703    /**
704     * Initializes local dynamic properties from state.
705     */
706    private void initializeWithState(NinePatchState state, Resources res) {
707        if (res != null) {
708            mTargetDensity = res.getDisplayMetrics().densityDpi;
709        } else {
710            mTargetDensity = state.mTargetDensity;
711        }
712
713        // If we can, avoid calling any methods that initialize Paint.
714        if (state.mDither != DEFAULT_DITHER) {
715            setDither(state.mDither);
716        }
717
718        // Make a local copy of the padding.
719        if (state.mPadding != null) {
720            mPadding = new Rect(state.mPadding);
721        }
722
723        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
724        setNinePatch(state.mNinePatch);
725    }
726}
727