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.text.style;
  
  import android.annotation.NonNull;
  import android.annotation.Px;
  import android.graphics.Canvas;
  import android.graphics.Paint;
  import android.graphics.drawable.Drawable;
  import android.text.Layout;
  import android.text.Spanned;
  
  /**
   * A span which adds a drawable and a padding to the paragraph it's attached to.
   * <p>
   * If the height of the drawable is bigger than the height of the line it's attached to then the
   * line height is increased to fit the drawable. <code>DrawableMarginSpan</code> allows setting a
   * padding between the drawable and the text. The default value is 0. The span must be set from the
   * beginning of the text, otherwise either the span won't be rendered or it will be rendered
   * incorrectly.
   * <p>
   * For example, a drawable and a padding of 20px can be added like this:
   * <pre>{@code SpannableString string = new SpannableString("Text with a drawable.");
   * string.setSpan(new DrawableMarginSpan(drawable, 20), 0, string.length(),
   * Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
   * <img src="{@docRoot}reference/android/images/text/style/drawablemarginspan.png" />
   * <figcaption>Text with a drawable and a padding.</figcaption>
   * <p>
   *
   * @see IconMarginSpan for working with a {@link android.graphics.Bitmap} instead of
   * a {@link Drawable}.
   */
  public class DrawableMarginSpan implements LeadingMarginSpan, LineHeightSpan {
      private static final int STANDARD_PAD_WIDTH = 0;
  
      @NonNull
      private final Drawable mDrawable;
      @Px
      private final int mPad;
  
      /**
       * Creates a {@link DrawableMarginSpan} from a {@link Drawable}. The pad width will be 0.
       *
       * @param drawable the drawable to be added
       */
      public DrawableMarginSpan(@NonNull Drawable drawable) {
          this(drawable, STANDARD_PAD_WIDTH);
      }
  
      /**
       * Creates a {@link DrawableMarginSpan} from a {@link Drawable} and a padding, in pixels.
       *
       * @param drawable the drawable to be added
       * @param pad      the distance between the drawable and the text
       */
      public DrawableMarginSpan(@NonNull Drawable drawable, int pad) {
          mDrawable = drawable;
          mPad = pad;
      }
  
      @Override
      public int getLeadingMargin(boolean first) {
          return mDrawable.getIntrinsicWidth() + mPad;
      }
  
      @Override
      public void drawLeadingMargin(@NonNull Canvas c, @NonNull Paint p, int x, int dir,
              int top, int baseline, int bottom,
              @NonNull CharSequence text, int start, int end,
              boolean first, @NonNull Layout layout) {
          int st = ((Spanned) text).getSpanStart(this);
          int ix = (int) x;
          int itop = (int) layout.getLineTop(layout.getLineForOffset(st));
  
          int dw = mDrawable.getIntrinsicWidth();
          int dh = mDrawable.getIntrinsicHeight();
  
          // XXX What to do about Paint?
          mDrawable.setBounds(ix, itop, ix + dw, itop + dh);
          mDrawable.draw(c);
      }
  
      @Override
      public void chooseHeight(@NonNull CharSequence text, int start, int end,
              int istartv, int v,
              @NonNull Paint.FontMetricsInt fm) {
          if (end == ((Spanned) text).getSpanEnd(this)) {
              int ht = mDrawable.getIntrinsicHeight();
  
              int need = ht - (v + fm.descent - fm.ascent - istartv);
              if (need > 0) {
                  fm.descent += need;
              }
  
              need = ht - (v + fm.bottom - fm.top - istartv);
              if (need > 0) {
                  fm.bottom += need;
              }
          }
      }
  }
  