content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.graphics.drawable;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.UnsupportedAppUsage;
  import android.content.pm.ActivityInfo.Config;
  import android.content.res.ColorStateList;
  import android.content.res.Resources;
  import android.content.res.Resources.Theme;
  import android.content.res.TypedArray;
  import android.graphics.Bitmap;
  import android.graphics.BlendMode;
  import android.graphics.BlendModeColorFilter;
  import android.graphics.Canvas;
  import android.graphics.ColorFilter;
  import android.graphics.ImageDecoder;
  import android.graphics.Insets;
  import android.graphics.NinePatch;
  import android.graphics.Outline;
  import android.graphics.Paint;
  import android.graphics.PixelFormat;
  import android.graphics.Rect;
  import android.graphics.Region;
  import android.util.AttributeSet;
  import android.util.DisplayMetrics;
  import android.util.LayoutDirection;
  import android.util.TypedValue;
  
  import com.android.internal.R;
  
  import org.xmlpull.v1.XmlPullParser;
  import org.xmlpull.v1.XmlPullParserException;
  
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   *
   * A resizeable bitmap, with stretchable areas that you define. This type of image
   * is defined in a .png file with a special format.
   *
   * <div class="special reference">
   * <h3>Developer Guides</h3>
   * <p>For more information about how to use a NinePatchDrawable, read the
   * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">
   * Canvas and Drawables</a> developer guide. For information about creating a NinePatch image
   * file using the draw9patch tool, see the
   * <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-patch</a> tool guide.</p></div>
   */
  public class NinePatchDrawable extends Drawable {
      // dithering helps a lot, and is pretty cheap, so default is true
      private static final boolean DEFAULT_DITHER = false;
  
      /** Temporary rect used for density scaling. */
      private Rect mTempRect;
  
      @UnsupportedAppUsage
      private NinePatchState mNinePatchState;
      private BlendModeColorFilter mBlendModeFilter;
      private Rect mPadding;
      private Insets mOpticalInsets = Insets.NONE;
      private Rect mOutlineInsets;
      private float mOutlineRadius;
      private Paint mPaint;
      private boolean mMutated;
  
      private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
  
      // These are scaled to match the target density.
      private int mBitmapWidth = -1;
      private int mBitmapHeight = -1;
  
      NinePatchDrawable() {
          mNinePatchState = new NinePatchState();
      }
  
      /**
       * Create drawable from raw nine-patch data, not dealing with density.
       *
       * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)}
       *             to ensure that the drawable has correctly set its target density.
       */
      @Deprecated
      public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
          this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
      }
  
      /**
       * Create drawable from raw nine-patch data, setting initial target density
       * based on the display metrics of the resources.
       */
      public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
              Rect padding, String srcName) {
          this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
      }
  
      /**
       * Create drawable from raw nine-patch data, setting initial target density
       * based on the display metrics of the resources.
       *
       * @hide
       */
      public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
              Rect padding, Rect opticalInsets, String srcName) {
          this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets),
                  res);
      }
  
      /**
       * Create drawable from existing nine-patch, not dealing with density.
       *
       * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
       *             to ensure that the drawable has correctly set its target
       *             density.
       */
      @Deprecated
      public NinePatchDrawable(@NonNull NinePatch patch) {
          this(new NinePatchState(patch, new Rect()), null);
      }
  
      /**
       * Create drawable from existing nine-patch, setting initial target density
       * based on the display metrics of the resources.
       */
      public NinePatchDrawable(@Nullable Resources res, @NonNull NinePatch patch) {
          this(new NinePatchState(patch, new Rect()), res);
      }
  
      /**
       * Set the density scale at which this drawable will be rendered. This
       * method assumes the drawable will be rendered at the same density as the
       * specified canvas.
       *
       * @param canvas The Canvas from which the density scale must be obtained.
       *
       * @see android.graphics.Bitmap#setDensity(int)
       * @see android.graphics.Bitmap#getDensity()
       */
      public void setTargetDensity(@NonNull Canvas canvas) {
          setTargetDensity(canvas.getDensity());
      }
  
      /**
       * Set the density scale at which this drawable will be rendered.
       *
       * @param metrics The DisplayMetrics indicating the density scale for this drawable.
       *
       * @see android.graphics.Bitmap#setDensity(int)
       * @see android.graphics.Bitmap#getDensity()
       */
      public void setTargetDensity(@NonNull DisplayMetrics metrics) {
          setTargetDensity(metrics.densityDpi);
      }
  
      /**
       * Set the density at which this drawable will be rendered.
       *
       * @param density The density scale for this drawable.
       *
       * @see android.graphics.Bitmap#setDensity(int)
       * @see android.graphics.Bitmap#getDensity()
       */
      public void setTargetDensity(int density) {
          if (density == 0) {
              density = DisplayMetrics.DENSITY_DEFAULT;
          }
  
          if (mTargetDensity != density) {
              mTargetDensity = density;
  
              computeBitmapSize();
              invalidateSelf();
          }
      }
  
      @Override
      public void draw(Canvas canvas) {
          final NinePatchState state = mNinePatchState;
  
          Rect bounds = getBounds();
          int restoreToCount = -1;
  
          final boolean clearColorFilter;
          if (mBlendModeFilter != null && getPaint().getColorFilter() == null) {
              mPaint.setColorFilter(mBlendModeFilter);
              clearColorFilter = true;
          } else {
              clearColorFilter = false;
          }
  
          final int restoreAlpha;
          if (state.mBaseAlpha != 1.0f) {
              restoreAlpha = getPaint().getAlpha();
              mPaint.setAlpha((int) (restoreAlpha * state.mBaseAlpha + 0.5f));
          } else {
              restoreAlpha = -1;
          }
  
          final boolean needsDensityScaling = canvas.getDensity() == 0
                  && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
          if (needsDensityScaling) {
              restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
  
              // Apply density scaling.
              final float scale = mTargetDensity / (float) state.mNinePatch.getDensity();
              final float px = bounds.left;
              final float py = bounds.top;
              canvas.scale(scale, scale, px, py);
  
              if (mTempRect == null) {
                  mTempRect = new Rect();
              }
  
              // Scale the bounds to match.
              final Rect scaledBounds = mTempRect;
              scaledBounds.left = bounds.left;
              scaledBounds.top = bounds.top;
              scaledBounds.right = bounds.left + Math.round(bounds.width() / scale);
              scaledBounds.bottom = bounds.top + Math.round(bounds.height() / scale);
              bounds = scaledBounds;
          }
  
          final boolean needsMirroring = needsMirroring();
          if (needsMirroring) {
              restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
  
              // Mirror the 9patch.
              final float cx = (bounds.left + bounds.right) / 2.0f;
              final float cy = (bounds.top + bounds.bottom) / 2.0f;
              canvas.scale(-1.0f, 1.0f, cx, cy);
          }
  
          state.mNinePatch.draw(canvas, bounds, mPaint);
  
          if (restoreToCount >= 0) {
              canvas.restoreToCount(restoreToCount);
          }
  
          if (clearColorFilter) {
              mPaint.setColorFilter(null);
          }
  
          if (restoreAlpha >= 0) {
              mPaint.setAlpha(restoreAlpha);
          }
      }
  
      @Override
      public @Config int getChangingConfigurations() {
          return super.getChangingConfigurations() | mNinePatchState.getChangingConfigurations();
      }
  
      @Override
      public boolean getPadding(@NonNull Rect padding) {
          if (mPadding != null) {
              padding.set(mPadding);
              return (padding.left | padding.top | padding.right | padding.bottom) != 0;
          } else {
              return super.getPadding(padding);
          }
      }
  
      @Override
      public void getOutline(@NonNull Outline outline) {
          final Rect bounds = getBounds();
          if (bounds.isEmpty()) {
              return;
          }
  
          if (mNinePatchState != null && mOutlineInsets != null) {
              final NinePatch.InsetStruct insets =
                      mNinePatchState.mNinePatch.getBitmap().getNinePatchInsets();
              if (insets != null) {
                  outline.setRoundRect(bounds.left + mOutlineInsets.left,
                          bounds.top + mOutlineInsets.top,
                          bounds.right - mOutlineInsets.right,
                          bounds.bottom - mOutlineInsets.bottom,
                          mOutlineRadius);
                  outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f));
                  return;
              }
          }
  
          super.getOutline(outline);
      }
  
      @Override
      public Insets getOpticalInsets() {
          final Insets opticalInsets = mOpticalInsets;
          if (needsMirroring()) {
              return Insets.of(opticalInsets.right, opticalInsets.top,
                      opticalInsets.left, opticalInsets.bottom);
          } else {
              return opticalInsets;
          }
      }
  
      @Override
      public void setAlpha(int alpha) {
          if (mPaint == null && alpha == 0xFF) {
              // Fast common case -- leave at normal alpha.
              return;
          }
          getPaint().setAlpha(alpha);
          invalidateSelf();
      }
  
      @Override
      public int getAlpha() {
          if (mPaint == null) {
              // Fast common case -- normal alpha.
              return 0xFF;
          }
          return getPaint().getAlpha();
      }
  
      @Override
      public void setColorFilter(@Nullable ColorFilter colorFilter) {
          if (mPaint == null && colorFilter == null) {
              // Fast common case -- leave at no color filter.
              return;
          }
          getPaint().setColorFilter(colorFilter);
          invalidateSelf();
      }
  
      @Override
      public void setTintList(@Nullable ColorStateList tint) {
          mNinePatchState.mTint = tint;
          mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, tint,
                  mNinePatchState.mBlendMode);
          invalidateSelf();
      }
  
      @Override
      public void setTintBlendMode(@Nullable BlendMode blendMode) {
          mNinePatchState.mBlendMode = blendMode;
          mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, mNinePatchState.mTint,
                  blendMode);
          invalidateSelf();
      }
  
      @Override
      public void setDither(boolean dither) {
          //noinspection PointlessBooleanExpression
          if (mPaint == null && dither == DEFAULT_DITHER) {
              // Fast common case -- leave at default dither.
              return;
          }
  
          getPaint().setDither(dither);
          invalidateSelf();
      }
  
      @Override
      public void setAutoMirrored(boolean mirrored) {
          mNinePatchState.mAutoMirrored = mirrored;
      }
  
      private boolean needsMirroring() {
          return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
      }
  
      @Override
      public boolean isAutoMirrored() {
          return mNinePatchState.mAutoMirrored;
      }
  
      @Override
      public void setFilterBitmap(boolean filter) {
          getPaint().setFilterBitmap(filter);
          invalidateSelf();
      }
  
      @Override
      public boolean isFilterBitmap() {
          return mPaint != null && getPaint().isFilterBitmap();
      }
  
      @Override
      public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
              throws XmlPullParserException, IOException {
          super.inflate(r, parser, attrs, theme);
  
          final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
          updateStateFromTypedArray(a);
          a.recycle();
  
          updateLocalState(r);
      }
  
      /**
       * Updates the constant state from the values in the typed array.
       */
      private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
          final Resources r = a.getResources();
          final NinePatchState state = mNinePatchState;
  
          // Account for any configuration changes.
          state.mChangingConfigurations |= a.getChangingConfigurations();
  
          // Extract the theme attributes, if any.
          state.mThemeAttrs = a.extractThemeAttrs();
  
          state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither);
  
          final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
          if (srcResId != 0) {
              final Rect padding = new Rect();
              final Rect opticalInsets = new Rect();
              Bitmap bitmap = null;
  
              try {
                  final TypedValue value = new TypedValue();
                  final InputStream is = r.openRawResource(srcResId, value);
  
                  int density = Bitmap.DENSITY_NONE;
                  if (value.density == TypedValue.DENSITY_DEFAULT) {
                      density = DisplayMetrics.DENSITY_DEFAULT;
                  } else if (value.density != TypedValue.DENSITY_NONE) {
                      density = value.density;
                  }
                  ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
                  bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
                      decoder.setOutPaddingRect(padding);
                      decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
                  });
  
                  is.close();
              } catch (IOException e) {
                  // Ignore
              }
  
              if (bitmap == null) {
                  throw new XmlPullParserException(a.getPositionDescription() +
                          ": <nine-patch> requires a valid src attribute");
              } else if (bitmap.getNinePatchChunk() == null) {
                  throw new XmlPullParserException(a.getPositionDescription() +
                          ": <nine-patch> requires a valid 9-patch source image");
              }
  
              bitmap.getOpticalInsets(opticalInsets);
  
              state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
              state.mPadding = padding;
              state.mOpticalInsets = Insets.of(opticalInsets);
          }
  
          state.mAutoMirrored = a.getBoolean(
                  R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored);
          state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha);
  
          final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
          if (tintMode != -1) {
              state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
          }
  
          final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
          if (tint != null) {
              state.mTint = tint;
          }
      }
  
      @Override
      public void applyTheme(@NonNull Theme t) {
          super.applyTheme(t);
  
          final NinePatchState state = mNinePatchState;
          if (state == null) {
              return;
          }
  
          if (state.mThemeAttrs != null) {
              final TypedArray a = t.resolveAttributes(
                      state.mThemeAttrs, R.styleable.NinePatchDrawable);
              try {
                  updateStateFromTypedArray(a);
              } catch (XmlPullParserException e) {
                  rethrowAsRuntimeException(e);
              } finally {
                  a.recycle();
              }
          }
  
          if (state.mTint != null && state.mTint.canApplyTheme()) {
              state.mTint = state.mTint.obtainForTheme(t);
          }
  
          updateLocalState(t.getResources());
      }
  
      @Override
      public boolean canApplyTheme() {
          return mNinePatchState != null && mNinePatchState.canApplyTheme();
      }
  
      @NonNull
      public Paint getPaint() {
          if (mPaint == null) {
              mPaint = new Paint();
              mPaint.setDither(DEFAULT_DITHER);
          }
          return mPaint;
      }
  
      @Override
      public int getIntrinsicWidth() {
          return mBitmapWidth;
      }
  
      @Override
      public int getIntrinsicHeight() {
          return mBitmapHeight;
      }
  
      @Override
      public int getOpacity() {
          return mNinePatchState.mNinePatch.hasAlpha()
                  || (mPaint != null && mPaint.getAlpha() < 255) ?
                          PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
      }
  
      @Override
      public Region getTransparentRegion() {
          return mNinePatchState.mNinePatch.getTransparentRegion(getBounds());
      }
  
      @Override
      public ConstantState getConstantState() {
          mNinePatchState.mChangingConfigurations = getChangingConfigurations();
          return mNinePatchState;
      }
  
      @Override
      public Drawable mutate() {
          if (!mMutated && super.mutate() == this) {
              mNinePatchState = new NinePatchState(mNinePatchState);
              mMutated = true;
          }
          return this;
      }
  
      /**
       * @hide
       */
      public void clearMutated() {
          super.clearMutated();
          mMutated = false;
      }
  
      @Override
      protected boolean onStateChange(int[] stateSet) {
          final NinePatchState state = mNinePatchState;
          if (state.mTint != null && state.mBlendMode != null) {
              mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, state.mTint,
                      state.mBlendMode);
              return true;
          }
  
          return false;
      }
  
      @Override
      public boolean isStateful() {
          final NinePatchState s = mNinePatchState;
          return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
      }
  
      /** @hide */
      @Override
      public boolean hasFocusStateSpecified() {
          return mNinePatchState.mTint != null && mNinePatchState.mTint.hasFocusStateSpecified();
      }
  
      final static class NinePatchState extends ConstantState {
          @Config int mChangingConfigurations;
  
          // Values loaded during inflation.
          @UnsupportedAppUsage
          NinePatch mNinePatch = null;
          ColorStateList mTint = null;
          BlendMode mBlendMode = DEFAULT_BLEND_MODE;
          Rect mPadding = null;
          Insets mOpticalInsets = Insets.NONE;
          float mBaseAlpha = 1.0f;
          boolean mDither = DEFAULT_DITHER;
          boolean mAutoMirrored = false;
  
          int[] mThemeAttrs;
  
          NinePatchState() {
              // Empty constructor.
          }
  
          NinePatchState(@NonNull NinePatch ninePatch, @Nullable Rect padding) {
              this(ninePatch, padding, null, DEFAULT_DITHER, false);
          }
  
          NinePatchState(@NonNull NinePatch ninePatch, @Nullable Rect padding,
                  @Nullable Rect opticalInsets) {
              this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false);
          }
  
          NinePatchState(@NonNull NinePatch ninePatch, @Nullable Rect padding,
                  @Nullable Rect opticalInsets, boolean dither, boolean autoMirror) {
              mNinePatch = ninePatch;
              mPadding = padding;
              mOpticalInsets = Insets.of(opticalInsets);
              mDither = dither;
              mAutoMirrored = autoMirror;
          }
  
          NinePatchState(@NonNull NinePatchState orig) {
              mChangingConfigurations = orig.mChangingConfigurations;
              mNinePatch = orig.mNinePatch;
              mTint = orig.mTint;
              mBlendMode = orig.mBlendMode;
              mPadding = orig.mPadding;
              mOpticalInsets = orig.mOpticalInsets;
              mBaseAlpha = orig.mBaseAlpha;
              mDither = orig.mDither;
              mAutoMirrored = orig.mAutoMirrored;
              mThemeAttrs = orig.mThemeAttrs;
          }
  
          @Override
          public boolean canApplyTheme() {
              return mThemeAttrs != null
                      || (mTint != null && mTint.canApplyTheme())
                      || super.canApplyTheme();
          }
  
          @Override
          public Drawable newDrawable() {
              return new NinePatchDrawable(this, null);
          }
  
          @Override
          public Drawable newDrawable(Resources res) {
              return new NinePatchDrawable(this, res);
          }
  
          @Override
          public @Config int getChangingConfigurations() {
              return mChangingConfigurations
                      | (mTint != null ? mTint.getChangingConfigurations() : 0);
          }
      }
  
      private void computeBitmapSize() {
          final NinePatch ninePatch = mNinePatchState.mNinePatch;
          if (ninePatch == null) {
              return;
          }
  
          final int targetDensity = mTargetDensity;
          final int sourceDensity = ninePatch.getDensity() == Bitmap.DENSITY_NONE ?
              targetDensity : ninePatch.getDensity();
  
          final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
          if (sourceOpticalInsets != Insets.NONE) {
              final int left = Drawable.scaleFromDensity(
                      sourceOpticalInsets.left, sourceDensity, targetDensity, true);
              final int top = Drawable.scaleFromDensity(
                      sourceOpticalInsets.top, sourceDensity, targetDensity, true);
              final int right = Drawable.scaleFromDensity(
                      sourceOpticalInsets.right, sourceDensity, targetDensity, true);
              final int bottom = Drawable.scaleFromDensity(
                      sourceOpticalInsets.bottom, sourceDensity, targetDensity, true);
              mOpticalInsets = Insets.of(left, top, right, bottom);
          } else {
              mOpticalInsets = Insets.NONE;
          }
  
          final Rect sourcePadding = mNinePatchState.mPadding;
          if (sourcePadding != null) {
              if (mPadding == null) {
                  mPadding = new Rect();
              }
              mPadding.left = Drawable.scaleFromDensity(
                      sourcePadding.left, sourceDensity, targetDensity, true);
              mPadding.top = Drawable.scaleFromDensity(
                      sourcePadding.top, sourceDensity, targetDensity, true);
              mPadding.right = Drawable.scaleFromDensity(
                      sourcePadding.right, sourceDensity, targetDensity, true);
              mPadding.bottom = Drawable.scaleFromDensity(
                      sourcePadding.bottom, sourceDensity, targetDensity, true);
          } else {
              mPadding = null;
          }
  
          mBitmapHeight = Drawable.scaleFromDensity(
                  ninePatch.getHeight(), sourceDensity, targetDensity, true);
          mBitmapWidth = Drawable.scaleFromDensity(
                  ninePatch.getWidth(), sourceDensity, targetDensity, true);
  
          final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets();
          if (insets != null) {
              Rect outlineRect = insets.outlineRect;
              mOutlineInsets = NinePatch.InsetStruct.scaleInsets(outlineRect.left, outlineRect.top,
                      outlineRect.right, outlineRect.bottom, targetDensity / (float) sourceDensity);
              mOutlineRadius = Drawable.scaleFromDensity(
                      insets.outlineRadius, sourceDensity, targetDensity);
          } else {
              mOutlineInsets = null;
          }
      }
  
      /**
       * The one constructor to rule them all. This is called by all public
       * constructors to set the state and initialize local properties.
       *
       * @param state constant state to assign to the new drawable
       */
      private NinePatchDrawable(@NonNull NinePatchState state, @Nullable Resources res) {
          mNinePatchState = state;
  
          updateLocalState(res);
      }
  
      /**
       * Initializes local dynamic properties from state.
       */
      private void updateLocalState(@Nullable Resources res) {
          final NinePatchState state = mNinePatchState;
  
          // If we can, avoid calling any methods that initialize Paint.
          if (state.mDither != DEFAULT_DITHER) {
              setDither(state.mDither);
          }
  
          // The nine-patch may have been created without a Resources object, in
          // which case we should try to match the density of the nine patch (if
          // available).
          if (res == null && state.mNinePatch != null) {
              mTargetDensity = state.mNinePatch.getDensity();
          } else {
              mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
          }
          mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, state.mTint, state.mBlendMode);
          computeBitmapSize();
      }
  }
  