public void init(
      @NonNull View view, @Nullable AttributeSet attrs, @NonNull TextPaint baseTextPaint) {
    final Context context = view.getContext();
    final int defColor = baseTextPaint.getColor();
    final int defPadding =
        context.getResources().getDimensionPixelSize(R.dimen.drag_direction_text_default_padding);
    final float minTextSize =
        context.getResources().getDimensionPixelSize(R.dimen.drag_direction_text_min_size);

    if (attrs == null) {
      for (DragDirection direction : DragDirection.values()) {
        final Text text = new Text(direction, view, minTextSize);
        text.init(baseTextPaint, null, DEF_SCALE, defColor, DEF_ALPHA, defPadding);
        texts.put(direction, text);
      }
      return;
    }
    final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DirectionText);
    final float scale = array.getFloat(R.styleable.DirectionText_directionTextScale, DEF_SCALE);
    final float alpha = array.getFloat(R.styleable.DirectionText_directionTextAlpha, DEF_ALPHA);
    final int color = array.getColor(R.styleable.DirectionText_directionTextColor, defColor);
    final int padding =
        array.getDimensionPixelSize(R.styleable.DirectionText_directionTextPadding, defPadding);
    for (DragDirection direction : DragDirection.values()) {
      final Text text = new Text(direction, view, minTextSize);
      text.init(baseTextPaint, array, scale, color, alpha, padding);
      texts.put(direction, text);
    }
    array.recycle();
  }
    @Override
    public void updateDrawState(TextPaint ds) {

      // Only dim the text in the basic state; not selected, focused or pressed
      int[] states = ds.drawableState;
      if (states != null) {
        int count = states.length;
        for (int i = 0; i < count; i++) {
          switch (states[i]) {
            case R.attr.state_pressed:
            case R.attr.state_selected:
            case R.attr.state_focused:
              // We can simply return, because the supplied text
              // paint is already configured with defaults.
              return;
          }
        }
      }

      int color = ds.getColor();
      color = Color.argb(mAlpha, Color.red(color), Color.green(color), Color.blue(color));
      ds.setColor(color);
    }
示例#3
0
  /**
   * Utility function for measuring and rendering text. The text must not include a tab or emoji.
   *
   * @param wp the working paint
   * @param start the start of the text
   * @param end the end of the text
   * @param runIsRtl true if the run is right-to-left
   * @param c the canvas, can be null if rendering is not needed
   * @param x the edge of the run closest to the leading margin
   * @param top the top of the line
   * @param y the baseline
   * @param bottom the bottom of the line
   * @param fmi receives metrics information, can be null
   * @param needWidth true if the width of the run is needed
   * @return the signed width of the run based on the run direction; only valid if needWidth is true
   */
  private float handleText(
      TextPaint wp,
      int start,
      int end,
      int contextStart,
      int contextEnd,
      boolean runIsRtl,
      Canvas c,
      float x,
      int top,
      int y,
      int bottom,
      FontMetricsInt fmi,
      boolean needWidth) {

    // Get metrics first (even for empty strings or "0" width runs)
    if (fmi != null) {
      /// M: new FontMetrics method for complex text support.
      expandMetricsFromPaint(fmi, wp, mText);
    }

    int runLen = end - start;
    // No need to do anything if the run width is "0"
    if (runLen == 0) {
      return 0f;
    }

    float ret = 0;

    int contextLen = contextEnd - contextStart;
    if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
      int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
      if (mCharsValid) {
        ret =
            wp.getTextRunAdvances(mChars, start, runLen, contextStart, contextLen, flags, null, 0);
      } else {
        int delta = mStart;
        ret =
            wp.getTextRunAdvances(
                mText,
                delta + start,
                delta + end,
                delta + contextStart,
                delta + contextEnd,
                flags,
                null,
                0);
      }
    }

    if (c != null) {
      if (runIsRtl) {
        x -= ret;
      }

      if (wp.bgColor != 0) {
        int previousColor = wp.getColor();
        Paint.Style previousStyle = wp.getStyle();

        wp.setColor(wp.bgColor);
        wp.setStyle(Paint.Style.FILL);
        c.drawRect(x, top, x + ret, bottom, wp);

        wp.setStyle(previousStyle);
        wp.setColor(previousColor);
      }

      if (wp.underlineColor != 0) {
        // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
        float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();

        int previousColor = wp.getColor();
        Paint.Style previousStyle = wp.getStyle();
        boolean previousAntiAlias = wp.isAntiAlias();

        wp.setStyle(Paint.Style.FILL);
        wp.setAntiAlias(true);

        wp.setColor(wp.underlineColor);
        c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp);

        wp.setStyle(previousStyle);
        wp.setColor(previousColor);
        wp.setAntiAlias(previousAntiAlias);
      }

      drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl, x, y + wp.baselineShift);
    }

    return runIsRtl ? -ret : ret;
  }
示例#4
0
  private void icUpdateGecko(boolean force) {

    // Skip if receiving a repeated request, or
    // if suppressing compositions during text selection.
    if ((!force && mIcUpdateSeqno == mLastIcUpdateSeqno) || mSuppressCompositions) {
      if (DEBUG) {
        Log.d(LOGTAG, "icUpdateGecko() skipped");
      }
      return;
    }
    mLastIcUpdateSeqno = mIcUpdateSeqno;
    mActionQueue.syncWithGecko();

    if (DEBUG) {
      Log.d(LOGTAG, "icUpdateGecko()");
    }

    final int selStart = mText.getSpanStart(Selection.SELECTION_START);
    final int selEnd = mText.getSpanEnd(Selection.SELECTION_END);
    int composingStart = mText.length();
    int composingEnd = 0;
    Object[] spans = mText.getSpans(0, composingStart, Object.class);

    for (Object span : spans) {
      if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
        composingStart = Math.min(composingStart, mText.getSpanStart(span));
        composingEnd = Math.max(composingEnd, mText.getSpanEnd(span));
      }
    }
    if (DEBUG) {
      Log.d(LOGTAG, " range = " + composingStart + "-" + composingEnd);
      Log.d(LOGTAG, " selection = " + selStart + "-" + selEnd);
    }
    if (composingStart >= composingEnd) {
      if (selStart >= 0 && selEnd >= 0) {
        onImeSetSelection(selStart, selEnd);
      } else {
        onImeRemoveComposition();
      }
      return;
    }

    if (selEnd >= composingStart && selEnd <= composingEnd) {
      onImeAddCompositionRange(
          selEnd - composingStart,
          selEnd - composingStart,
          IME_RANGE_CARETPOSITION,
          0,
          0,
          false,
          0,
          0,
          0);
    }
    int rangeStart = composingStart;
    TextPaint tp = new TextPaint();
    TextPaint emptyTp = new TextPaint();
    // set initial foreground color to 0, because we check for tp.getColor() == 0
    // below to decide whether to pass a foreground color to Gecko
    emptyTp.setColor(0);
    do {
      int rangeType, rangeStyles = 0, rangeLineStyle = IME_RANGE_LINE_NONE;
      boolean rangeBoldLine = false;
      int rangeForeColor = 0, rangeBackColor = 0, rangeLineColor = 0;
      int rangeEnd = mText.nextSpanTransition(rangeStart, composingEnd, Object.class);

      if (selStart > rangeStart && selStart < rangeEnd) {
        rangeEnd = selStart;
      } else if (selEnd > rangeStart && selEnd < rangeEnd) {
        rangeEnd = selEnd;
      }
      CharacterStyle[] styleSpans = mText.getSpans(rangeStart, rangeEnd, CharacterStyle.class);

      if (DEBUG) {
        Log.d(LOGTAG, " found " + styleSpans.length + " spans @ " + rangeStart + "-" + rangeEnd);
      }

      if (styleSpans.length == 0) {
        rangeType =
            (selStart == rangeStart && selEnd == rangeEnd)
                ? IME_RANGE_SELECTEDRAWTEXT
                : IME_RANGE_RAWINPUT;
      } else {
        rangeType =
            (selStart == rangeStart && selEnd == rangeEnd)
                ? IME_RANGE_SELECTEDCONVERTEDTEXT
                : IME_RANGE_CONVERTEDTEXT;
        tp.set(emptyTp);
        for (CharacterStyle span : styleSpans) {
          span.updateDrawState(tp);
        }
        int tpUnderlineColor = 0;
        float tpUnderlineThickness = 0.0f;

        // These TextPaint fields only exist on Android ICS+ and are not in the SDK.
        if (Versions.feature14Plus) {
          tpUnderlineColor = (Integer) getField(tp, "underlineColor", 0);
          tpUnderlineThickness = (Float) getField(tp, "underlineThickness", 0.0f);
        }
        if (tpUnderlineColor != 0) {
          rangeStyles |= IME_RANGE_UNDERLINE | IME_RANGE_LINECOLOR;
          rangeLineColor = tpUnderlineColor;
          // Approximately translate underline thickness to what Gecko understands
          if (tpUnderlineThickness <= 0.5f) {
            rangeLineStyle = IME_RANGE_LINE_DOTTED;
          } else {
            rangeLineStyle = IME_RANGE_LINE_SOLID;
            if (tpUnderlineThickness >= 2.0f) {
              rangeBoldLine = true;
            }
          }
        } else if (tp.isUnderlineText()) {
          rangeStyles |= IME_RANGE_UNDERLINE;
          rangeLineStyle = IME_RANGE_LINE_SOLID;
        }
        if (tp.getColor() != 0) {
          rangeStyles |= IME_RANGE_FORECOLOR;
          rangeForeColor = tp.getColor();
        }
        if (tp.bgColor != 0) {
          rangeStyles |= IME_RANGE_BACKCOLOR;
          rangeBackColor = tp.bgColor;
        }
      }
      onImeAddCompositionRange(
          rangeStart - composingStart,
          rangeEnd - composingStart,
          rangeType,
          rangeStyles,
          rangeLineStyle,
          rangeBoldLine,
          rangeForeColor,
          rangeBackColor,
          rangeLineColor);
      rangeStart = rangeEnd;

      if (DEBUG) {
        Log.d(
            LOGTAG,
            " added "
                + rangeType
                + " : "
                + Integer.toHexString(rangeStyles)
                + " : "
                + Integer.toHexString(rangeForeColor)
                + " : "
                + Integer.toHexString(rangeBackColor));
      }
    } while (rangeStart < composingEnd);

    onImeUpdateComposition(composingStart, composingEnd);
  }
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.translate(ProgramTableLayoutConstants.PADDING_SIDE, 0);

    TextPaint toUseForTimeAndTitle = ProgramTableLayoutConstants.NOT_EXPIRED_TITLE_PAINT;
    TextPaint toUseForGenreAndEpisode = ProgramTableLayoutConstants.NOT_EXPIRED_GENRE_EPISODE_PAINT;
    TextPaint toUseForPictureCopyright =
        ProgramTableLayoutConstants.NOT_EXPIRED_PICTURE_COPYRIGHT_PAINT;

    if (isExpired()) {
      toUseForTimeAndTitle = ProgramTableLayoutConstants.EXPIRED_TITLE_PAINT;
      toUseForGenreAndEpisode = ProgramTableLayoutConstants.EXPIRED_GENRE_EPISODE_PAINT;
      toUseForPictureCopyright = ProgramTableLayoutConstants.EXPIRED_PICTURE_COPYRIGHT_PAINT;
    }

    // draw start time
    canvas.drawText(
        mStartTimeString,
        0,
        ProgramTableLayoutConstants.BIG_MAX_FONT_HEIGHT
            - ProgramTableLayoutConstants.BIG_FONT_DESCEND,
        toUseForTimeAndTitle);

    canvas.translate(mStartTimeBounds.width() + ProgramTableLayoutConstants.TIME_TITLE_GAP, 0);

    String[] lines = mTitle.split("\n");

    // draw title
    for (int i = 0; i < lines.length; i++) {
      canvas.drawText(
          lines[i],
          0,
          (i + 1) * ProgramTableLayoutConstants.BIG_MAX_FONT_HEIGHT
              - ProgramTableLayoutConstants.BIG_FONT_DESCEND,
          toUseForTimeAndTitle);
    }

    canvas.translate(0, lines.length * ProgramTableLayoutConstants.BIG_MAX_FONT_HEIGHT);

    // draw picture copyright and picture
    if (mPictureCopyright != null && mPicture != null) {
      mPicture.draw(canvas);

      canvas.translate(0, mPicture.getBounds().height());

      lines = mPictureCopyright.split("\n");

      for (int i = 0; i < lines.length; i++) {
        canvas.drawText(
            lines[i],
            0,
            (i + 1) * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT
                - ProgramTableLayoutConstants.SUPER_SMALL_FONT_DESCEND,
            toUseForPictureCopyright);
      }

      canvas.translate(0, lines.length * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT);
    }

    // draw additonal infos
    if (mCategoriesString != null) {
      // lines = mInfoString.split("\n");

      final int oldColor = toUseForPictureCopyright.getColor();

      final String separator = ",";
      final float separatorWidth = toUseForPictureCopyright.measureText(separator);

      for (int i = 0; i < mCategoriesString.length; i++) {
        canvas.save();

        for (Iterator<ColorEntry> it = mCategoriesString[i].getEntries(); it.hasNext(); ) {
          ColorEntry entry = it.next();

          Integer color = entry.getColor();

          if (color != null && !isExpired()) {
            toUseForPictureCopyright.setColor(color.intValue());
          } else {
            toUseForPictureCopyright.setColor(oldColor);
          }

          canvas.drawText(
              entry.getText(),
              0,
              (i + 1) * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT
                  - ProgramTableLayoutConstants.SUPER_SMALL_FONT_DESCEND,
              toUseForPictureCopyright);

          canvas.translate(entry.measure(toUseForPictureCopyright), 0);

          if (entry.needsSeparator()) {
            toUseForPictureCopyright.setColor(oldColor);

            canvas.drawText(
                separator,
                0,
                (i + 1) * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT
                    - ProgramTableLayoutConstants.SUPER_SMALL_FONT_DESCEND,
                toUseForPictureCopyright);
            canvas.translate(separatorWidth, 0);
          }
        }

        canvas.restore();
        /*
        String first = lines[i].substring(0, lines[i].length()/2);
        String second = lines[i].substring(lines[i].length()/2);

        canvas.save();

        toUseForPictureCopyright.setColor(Color.BLUE);

        canvas.drawText(first, 0, (i+1) * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT - ProgramTableLayoutConstants.SUPER_SMALL_FONT_DESCEND, toUseForPictureCopyright);

        canvas.translate(toUseForPictureCopyright.measureText(first), 0);

        toUseForPictureCopyright.setColor(Color.RED);

        canvas.drawText(second, 0, (i+1) * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT - ProgramTableLayoutConstants.SUPER_SMALL_FONT_DESCEND, toUseForPictureCopyright);

        canvas.restore();*/
      }

      toUseForPictureCopyright.setColor(oldColor);

      canvas.translate(
          0, mCategoriesString.length * ProgramTableLayoutConstants.SUPER_SMALL_MAX_FONT_HEIGHT);
    }

    // draw genre
    if (mGenre != null) {
      lines = mGenre.split("\n");

      for (int i = 0; i < lines.length; i++) {
        canvas.drawText(
            lines[i],
            0,
            (i + 1) * ProgramTableLayoutConstants.SMALL_MAX_FONT_HEIGHT
                - ProgramTableLayoutConstants.SMALL_FONT_DESCEND,
            toUseForGenreAndEpisode);
      }

      canvas.translate(0, lines.length * ProgramTableLayoutConstants.SMALL_MAX_FONT_HEIGHT);
    }

    // draw episode title
    if (mEpisode != null) {
      lines = mEpisode.split("\n");

      for (int i = 0; i < lines.length; i++) {
        canvas.drawText(
            lines[i],
            0,
            (i + 1) * ProgramTableLayoutConstants.SMALL_MAX_FONT_HEIGHT
                - ProgramTableLayoutConstants.SMALL_FONT_DESCEND,
            toUseForGenreAndEpisode);
      }
    }
  }
  /**
   * Draws and/or measures a uniform run of text on a single line. No span of interest should start
   * or end in the middle of this run (if not drawing, character spans that don't affect metrics can
   * be ignored). Neither should the run direction change in the middle of the run.
   *
   * <p>
   *
   * <p>The x position is the leading edge of the text. In a right-to-left paragraph, this will be
   * to the right of the text to be drawn. Paint should not have an Align value other than LEFT or
   * positioning will isCancelled confused.
   *
   * <p>
   *
   * <p>On return, workPaint will reflect the original paint plus any modifications made by
   * character styles on the run.
   *
   * <p>
   *
   * <p>The returned width is signed and will be < 0 if the paragraph direction is right-to-left.
   */
  private static float drawUniformRun(
      Canvas canvas,
      Spanned text,
      int start,
      int end,
      int dir,
      boolean runIsRtl,
      float x,
      int top,
      int y,
      int bottom,
      Paint.FontMetricsInt fmi,
      TextPaint paint,
      TextPaint workPaint,
      boolean needWidth) {

    boolean haveWidth = false;
    float ret = 0;
    CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);

    ReplacementSpan replacement = null;

    // XXX: This shouldn't be modifying paint, only workPaint.
    // However, the members belonging to TextPaint should have default
    // values anyway.  Better to ensure this in the Layout constructor.
    paint.bgColor = 0;
    paint.baselineShift = 0;
    workPaint.set(paint);

    if (spans.length > 0) {
      for (CharacterStyle span : spans) {
        if (span instanceof ReplacementSpan) {
          replacement = (ReplacementSpan) span;
        } else {
          span.updateDrawState(workPaint);
        }
      }
    }

    if (replacement == null) {
      CharSequence tmp;
      int tmpstart, tmpend;

      if (runIsRtl) {
        tmp = TextUtils.getReverse(text, start, end);
        tmpstart = 0;
        // XXX: assumes getReverse doesn't change the length of the text
        tmpend = end - start;
      } else {
        tmp = text;
        tmpstart = start;
        tmpend = end;
      }

      if (fmi != null) {
        workPaint.getFontMetricsInt(fmi);
      }

      if (canvas != null) {
        if (workPaint.bgColor != 0) {
          int c = workPaint.getColor();
          Paint.Style s = workPaint.getStyle();
          workPaint.setColor(workPaint.bgColor);
          workPaint.setStyle(Paint.Style.FILL);

          if (!haveWidth) {
            ret = workPaint.measureText(tmp, tmpstart, tmpend);
            haveWidth = true;
          }

          if (dir == Layout.DIR_RIGHT_TO_LEFT) {
            canvas.drawRect(x - ret, top, x, bottom, workPaint);
          } else {
            canvas.drawRect(x, top, x + ret, bottom, workPaint);
          }

          workPaint.setStyle(s);
          workPaint.setColor(c);
        }

        if (dir == Layout.DIR_RIGHT_TO_LEFT) {
          if (!haveWidth) {
            ret = workPaint.measureText(tmp, tmpstart, tmpend);
            haveWidth = true;
          }

          canvas.drawText(tmp, tmpstart, tmpend, x - ret, y + workPaint.baselineShift, workPaint);
        } else {
          if (needWidth) {
            if (!haveWidth) {
              ret = workPaint.measureText(tmp, tmpstart, tmpend);
              haveWidth = true;
            }
          }

          canvas.drawText(tmp, tmpstart, tmpend, x, y + workPaint.baselineShift, workPaint);
        }
      } else {
        if (needWidth && !haveWidth) {
          ret = workPaint.measureText(tmp, tmpstart, tmpend);
          haveWidth = true;
        }
      }
    } else {
      ret = replacement.getSize(workPaint, text, start, end, fmi);

      if (canvas != null) {
        if (dir == Layout.DIR_RIGHT_TO_LEFT) {
          replacement.draw(canvas, text, start, end, x - ret, top, y, bottom, workPaint);
        } else {
          replacement.draw(canvas, text, start, end, x, top, y, bottom, workPaint);
        }
      }
    }

    if (dir == Layout.DIR_RIGHT_TO_LEFT) {
      return -ret;
    } else {
      return ret;
    }
  }
示例#7
0
 public int getTextColor() {
   return paint.getColor();
 }