public int getOffsetAfter()

in shell/platform/android/io/flutter/plugin/editing/FlutterTextUtils.java [197:318]


  public int getOffsetAfter(CharSequence text, int offset) {
    final int len = text.length();

    if (offset >= len - 1) {
      return len;
    }

    int codePoint = Character.codePointAt(text, offset);
    int nextCharCount = Character.charCount(codePoint);
    int nextOffset = offset + nextCharCount;

    if (nextOffset == 0) {
      return 0;
    }

    // Line Feed
    if (codePoint == LINE_FEED) {
      codePoint = Character.codePointAt(text, nextOffset);
      if (codePoint == CARRIAGE_RETURN) {
        ++nextCharCount;
      }
      return offset + nextCharCount;
    }

    // Flags
    if (isRegionalIndicatorSymbol(codePoint)) {
      if (nextOffset >= len - 1
          || !isRegionalIndicatorSymbol(Character.codePointAt(text, nextOffset))) {
        return offset + nextCharCount;
      }
      // In this case there are at least two regional indicator symbols ahead of
      // offset. If those two regional indicator symbols are a pair that
      // represent a region together, the next offset should be after both of
      // them.
      int regionalIndicatorSymbolCount = 0;
      int regionOffset = offset;
      while (regionOffset > 0
          && isRegionalIndicatorSymbol(Character.codePointBefore(text, offset))) {
        regionOffset -= Character.charCount(Character.codePointBefore(text, offset));
        regionalIndicatorSymbolCount++;
      }
      if (regionalIndicatorSymbolCount % 2 == 0) {
        nextCharCount += 2;
      }
      return offset + nextCharCount;
    }

    // Keycaps
    if (isKeycapBase(codePoint)) {
      nextCharCount += Character.charCount(codePoint);
    }
    if (codePoint == COMBINING_ENCLOSING_KEYCAP) {
      codePoint = Character.codePointBefore(text, nextOffset);
      nextOffset += Character.charCount(codePoint);
      if (nextOffset < len && isVariationSelector(codePoint)) {
        int tmpCodePoint = Character.codePointAt(text, nextOffset);
        if (isKeycapBase(tmpCodePoint)) {
          nextCharCount += Character.charCount(codePoint) + Character.charCount(tmpCodePoint);
        }
      } else if (isKeycapBase(codePoint)) {
        nextCharCount += Character.charCount(codePoint);
      }
      return offset + nextCharCount;
    }

    if (isEmoji(codePoint)) {
      boolean isZwj = false;
      int lastSeenVariantSelectorCharCount = 0;
      do {
        if (isZwj) {
          nextCharCount += Character.charCount(codePoint) + lastSeenVariantSelectorCharCount + 1;
          isZwj = false;
        }
        lastSeenVariantSelectorCharCount = 0;
        if (isEmojiModifier(codePoint)) {
          break;
        }

        if (nextOffset < len) {
          codePoint = Character.codePointAt(text, nextOffset);
          nextOffset += Character.charCount(codePoint);
          if (codePoint == COMBINING_ENCLOSING_KEYCAP) {
            codePoint = Character.codePointBefore(text, nextOffset);
            nextOffset += Character.charCount(codePoint);
            if (nextOffset < len && isVariationSelector(codePoint)) {
              int tmpCodePoint = Character.codePointAt(text, nextOffset);
              if (isKeycapBase(tmpCodePoint)) {
                nextCharCount += Character.charCount(codePoint) + Character.charCount(tmpCodePoint);
              }
            } else if (isKeycapBase(codePoint)) {
              nextCharCount += Character.charCount(codePoint);
            }
            return offset + nextCharCount;
          }
          if (isEmojiModifier(codePoint)) {
            nextCharCount += lastSeenVariantSelectorCharCount + Character.charCount(codePoint);
            break;
          }
          if (isVariationSelector(codePoint)) {
            nextCharCount += lastSeenVariantSelectorCharCount + Character.charCount(codePoint);
            break;
          }
          if (codePoint == ZERO_WIDTH_JOINER) {
            isZwj = true;
            codePoint = Character.codePointAt(text, nextOffset);
            nextOffset += Character.charCount(codePoint);
            if (nextOffset < len && isVariationSelector(codePoint)) {
              codePoint = Character.codePointAt(text, nextOffset);
              lastSeenVariantSelectorCharCount = Character.charCount(codePoint);
              nextOffset += Character.charCount(codePoint);
            }
          }
        }

        if (nextOffset >= len) {
          break;
        }
      } while (isZwj && isEmoji(codePoint));
    }

    return offset + nextCharCount;
  }