Пример #1
0
void FontCollection::itemize(const uint16_t* string,
                             size_t string_size,
                             FontStyle style,
                             vector<Run>* result) const {
  const uint32_t langListId = style.getLanguageListId();
  int variant = style.getVariant();
  const FontFamily* lastFamily = nullptr;
  Run* run = NULL;

  if (string_size == 0) {
    return;
  }

  const uint32_t kEndOfString = 0xFFFFFFFF;

  uint32_t nextCh = 0;
  uint32_t prevCh = 0;
  size_t nextUtf16Pos = 0;
  size_t readLength = 0;
  U16_NEXT(string, readLength, string_size, nextCh);

  do {
    const uint32_t ch = nextCh;
    const size_t utf16Pos = nextUtf16Pos;
    nextUtf16Pos = readLength;
    if (readLength < string_size) {
      U16_NEXT(string, readLength, string_size, nextCh);
    } else {
      nextCh = kEndOfString;
    }

    bool shouldContinueRun = false;
    if (lastFamily != nullptr) {
      if (isStickyWhitelisted(ch)) {
        // Continue using existing font as long as it has coverage and is
        // whitelisted
        shouldContinueRun = lastFamily->getCoverage().get(ch);
      } else if (ch == SOFT_HYPHEN || isVariationSelector(ch)) {
        // Always continue if the character is the soft hyphen or a variation
        // selector.
        shouldContinueRun = true;
      }
    }

    if (!shouldContinueRun) {
      const std::shared_ptr<FontFamily>& family = getFamilyForChar(
          ch, isVariationSelector(nextCh) ? nextCh : 0, langListId, variant);
      if (utf16Pos == 0 || family.get() != lastFamily) {
        size_t start = utf16Pos;
        // Workaround for combining marks and emoji modifiers until we implement
        // per-cluster font selection: if a combining mark or an emoji modifier
        // is found in a different font that also supports the previous
        // character, attach previous character to the new run. U+20E3 COMBINING
        // ENCLOSING KEYCAP, used in emoji, is handled properly by this since
        // it's a combining mark too.
        if (utf16Pos != 0 &&
            ((U_GET_GC_MASK(ch) & U_GC_M_MASK) != 0 ||
             (isEmojiModifier(ch) && isEmojiBase(prevCh))) &&
            family != nullptr && family->getCoverage().get(prevCh)) {
          const size_t prevChLength = U16_LENGTH(prevCh);
          run->end -= prevChLength;
          if (run->start == run->end) {
            result->pop_back();
          }
          start -= prevChLength;
        }
        result->push_back(
            {family->getClosestMatch(style), static_cast<int>(start), 0});
        run = &result->back();
        lastFamily = family.get();
      }
    }
    prevCh = ch;
    run->end = nextUtf16Pos;  // exclusive
  } while (nextCh != kEndOfString);
}