/**
   * 用本函数代替{@link #setText(CharSequence)}
   *
   * @param cs
   */
  public void setMText(CharSequence cs) {
    text = cs;

    obList.clear();
    //	contentList.clear();

    ArrayList<IS> isList = new ArrayList<MTextView.IS>();
    useDefault = false;
    if (cs instanceof SpannableString) {
      SpannableString ss = (SpannableString) cs;
      ImageSpan[] imageSpans = ss.getSpans(0, ss.length(), ImageSpan.class);
      for (int i = 0; i < imageSpans.length; i++) {
        int s = ss.getSpanStart(imageSpans[i]);
        int e = ss.getSpanEnd(imageSpans[i]);
        IS iS = new IS();
        iS.is = imageSpans[i];
        iS.start = s;
        iS.end = e;
        isList.add(iS);
      }
    }

    String str = cs.toString();

    for (int i = 0, j = 0; i < cs.length(); ) {
      if (j < isList.size()) {
        IS is = isList.get(j);
        if (i < is.start) {
          Integer cp = str.codePointAt(i);
          // 支持增补字符
          if (Character.isSupplementaryCodePoint(cp)) {
            i += 2;
          } else {
            i++;
          }

          obList.add(new String(Character.toChars(cp)));

        } else if (i >= is.start) {
          obList.add(is.is);
          j++;
          i = is.end;
        }
      } else {
        Integer cp = str.codePointAt(i);
        if (Character.isSupplementaryCodePoint(cp)) {
          i += 2;
        } else {
          i++;
        }

        obList.add(new String(Character.toChars(cp)));
      }
    }

    requestLayout();
  }
        @Override
        public boolean onTouch(View v, MotionEvent event) {

          Layout layout = ((TextView) v).getLayout();

          int x = (int) event.getX();
          int y = (int) event.getY();
          int offset = 0;
          if (layout != null) {

            int line = layout.getLineForVertical(y);
            offset = layout.getOffsetForHorizontal(line, x);
          }

          TextView tv = (TextView) v;
          SpannableString value = SpannableString.valueOf(tv.getText());

          LinkMovementMethod.getInstance().onTouchEvent(tv, value, event);

          switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
              WeburlSpan[] urlSpans = value.getSpans(0, value.length(), WeburlSpan.class);
              boolean find = false;
              int findStart = 0;
              int findEnd = 0;
              for (WeburlSpan urlSpan : urlSpans) {
                int start = value.getSpanStart(urlSpan);
                int end = value.getSpanEnd(urlSpan);
                if (start <= offset && offset <= end) {
                  find = true;
                  findStart = start;
                  findEnd = end;

                  break;
                }
              }

              if (find) {
                BackgroundColorSpan bkcolor = new BackgroundColorSpan(0xff89660f);
                value.setSpan(bkcolor, findStart, findEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                ((TextView) v).setText(value);
              }

              return find;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
              BackgroundColorSpan[] backgroundColorSpans =
                  value.getSpans(0, value.length(), BackgroundColorSpan.class);
              for (BackgroundColorSpan bkcolor : backgroundColorSpans) {
                value.removeSpan(bkcolor);
                ((TextView) v).setText(value);
              }
              break;
          }

          return false;
        }
  @CalledByNative
  private void populateUnderlinesFromSpans(CharSequence text, long underlines) {
    Log.d(TAG, "populateUnderlinesFromSpans: text [%s], underlines [%d]", text, underlines);
    if (!(text instanceof SpannableString)) return;

    SpannableString spannableString = ((SpannableString) text);
    CharacterStyle spans[] = spannableString.getSpans(0, text.length(), CharacterStyle.class);
    for (CharacterStyle span : spans) {
      if (span instanceof BackgroundColorSpan) {
        nativeAppendBackgroundColorSpan(
            underlines,
            spannableString.getSpanStart(span),
            spannableString.getSpanEnd(span),
            ((BackgroundColorSpan) span).getBackgroundColor());
      } else if (span instanceof UnderlineSpan) {
        nativeAppendUnderlineSpan(
            underlines, spannableString.getSpanStart(span), spannableString.getSpanEnd(span));
      }
    }
  }
  private static SpannableString style(
      Context ctx,
      HashMap<String, ITypeface> fonts,
      SpannableString textSpanned,
      List<CharacterStyle> styles,
      HashMap<String, List<CharacterStyle>> stylesFor) {
    if (fonts == null || fonts.size() == 0) {
      fonts = FONTS;
    }

    int startIndex = -1;
    String fontKey = "";

    // remember the position of removed chars
    ArrayList<RemoveInfo> removed = new ArrayList<RemoveInfo>();

    // StringBuilder text = new StringBuilder(textSpanned.toString());
    StringBuilder text = new StringBuilder(textSpanned);

    // find the first "{"
    while ((startIndex = text.indexOf("{", startIndex + 1)) != -1) {
      // make sure we are still within the bounds of the text
      if (text.length() < startIndex + 5) {
        startIndex = -1;
        break;
      }
      // make sure the found text is a real fontKey
      if (!text.substring(startIndex + 4, startIndex + 5).equals("-")) {
        break;
      }
      // get the fontKey
      fontKey = text.substring(startIndex + 1, startIndex + 4);
      // check if the fontKey is a registeredFont
      if (fonts.containsKey(fontKey)) {
        break;
      }
    }
    if (startIndex == -1) {
      return new SpannableString(text);
    }

    // remember total removed chars
    int removedChars = 0;

    LinkedList<StyleContainer> styleContainers = new LinkedList<StyleContainer>();
    do {
      // get the information from the iconString
      int endIndex = text.substring(startIndex).indexOf("}") + startIndex + 1;
      String iconString = text.substring(startIndex + 1, endIndex - 1);
      iconString = iconString.replaceAll("-", "_");
      try {
        // get the correct character for this Font and Icon
        IIcon icon = fonts.get(fontKey).getIcon(iconString);
        // we can only add an icon which is a font
        if (icon != null) {
          char fontChar = icon.getCharacter();
          String iconValue = String.valueOf(fontChar);

          // get just the icon identifier
          text = text.replace(startIndex, endIndex, iconValue);

          // store some info about the removed chars
          removedChars = removedChars + (endIndex - startIndex);
          removed.add(new RemoveInfo(startIndex, (endIndex - startIndex - 1), removedChars));

          // add the current icon to the container
          styleContainers.add(
              new StyleContainer(startIndex, startIndex + 1, iconString, fonts.get(fontKey)));
        }
      } catch (IllegalArgumentException e) {
        Log.w(Iconics.TAG, "Wrong icon name: " + iconString);
      }

      // reset fontKey so we can react if we are at the end but haven't found any more matches
      fontKey = null;

      // check the rest of the text for matches
      while ((startIndex = text.indexOf("{", startIndex + 1)) != -1) {
        // make sure we are still within the bounds
        if (text.length() < startIndex + 5) {
          startIndex = -1;
          break;
        }
        // check if the 5. char is a "-"
        if (text.substring(startIndex + 4, startIndex + 5).equals("-")) {
          // get the fontKey
          fontKey = text.substring(startIndex + 1, startIndex + 4);
          // check if the fontKey is registered
          if (fonts.containsKey(fontKey)) {
            break;
          }
        }
      }
    } while (startIndex != -1 && fontKey != null);

    SpannableString sb = new SpannableString(text);

    // reapply all previous styles
    for (StyleSpan span : textSpanned.getSpans(0, textSpanned.length(), StyleSpan.class)) {
      int spanStart = newSpanPoint(textSpanned.getSpanStart(span), removed);
      int spanEnd = newSpanPoint(textSpanned.getSpanEnd(span), removed);
      if (spanStart >= 0 && spanEnd > 0) {
        sb.setSpan(span, spanStart, spanEnd, textSpanned.getSpanFlags(span));
      }
    }

    // set all the icons and styles
    for (StyleContainer styleContainer : styleContainers) {
      sb.setSpan(
          new IconicsTypefaceSpan("sans-serif", styleContainer.getFont().getTypeface(ctx)),
          styleContainer.getStartIndex(),
          styleContainer.getEndIndex(),
          Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

      if (stylesFor.containsKey(styleContainer.getIcon())) {
        for (CharacterStyle style : stylesFor.get(styleContainer.getIcon())) {
          sb.setSpan(
              CharacterStyle.wrap(style),
              styleContainer.getStartIndex(),
              styleContainer.getEndIndex(),
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      } else if (styles != null) {
        for (CharacterStyle style : styles) {
          sb.setSpan(
              CharacterStyle.wrap(style),
              styleContainer.getStartIndex(),
              styleContainer.getEndIndex(),
              Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
      }
    }

    // sb = applyKerning(sb, 1);

    return sb;
  }