bool Label::multilineTextWrapByWord()
{
    int textLen = getStringLength();
    int lineIndex = 0;
    float nextWordX = 0.f;
    float nextWordY = 0.f;
    float longestLine = 0.f;
    float letterRight = 0.f;

    auto contentScaleFactor = CC_CONTENT_SCALE_FACTOR();  
    float highestY = 0.f;
    float lowestY = 0.f;
    FontLetterDefinition letterDef;
    Vec2 letterPosition;
    
    for (int index = 0; index < textLen; )
    {
        auto character = _utf16Text[index];
        if (character == '\n')
        {
            _linesWidth.push_back(letterRight);
            letterRight = 0.f;
            lineIndex++;
            nextWordX = 0.f;
            nextWordY -= _lineHeight;
            recordPlaceholderInfo(index, character);
            index++;
            continue;
        }

        auto wordLen = getFirstWordLen(_utf16Text, index, textLen);
        float wordHighestY = highestY;;
        float wordLowestY = lowestY;
        float wordRight = letterRight;
        float nextLetterX = nextWordX;
        bool newLine = false;
        for (int tmp = 0; tmp < wordLen;++tmp)
        {
            int letterIndex = index + tmp;
            character = _utf16Text[letterIndex];
            if (_fontAtlas->getLetterDefinitionForChar(character, letterDef) == false)
            {
                recordPlaceholderInfo(letterIndex, character);
                CCLOG("LabelTextFormatter error:can't find letter definition in font file for letter: %c", character);
                continue;
            }

            auto letterX = (nextLetterX + letterDef.offsetX) / contentScaleFactor;
            if (_maxLineWidth > 0.f && nextWordX > 0.f && letterX + letterDef.width > _maxLineWidth)
            {
                _linesWidth.push_back(letterRight);
                letterRight = 0.f;
                lineIndex++;
                nextWordX = 0.f;
                nextWordY -= _lineHeight;
                newLine = true;
                break;
            }
            else
            {
                letterPosition.x = letterX;
            }
            letterPosition.y = (nextWordY - letterDef.offsetY) / contentScaleFactor;
            recordLetterInfo(letterPosition, character, letterIndex, lineIndex);

            if (_horizontalKernings && letterIndex < textLen - 1)
                nextLetterX += _horizontalKernings[letterIndex + 1];
            nextLetterX += letterDef.xAdvance + _additionalKerning;

            wordRight = letterPosition.x + letterDef.width;

            if (wordHighestY < letterPosition.y)
                wordHighestY = letterPosition.y;
            if (wordLowestY > letterPosition.y - letterDef.height)
                wordLowestY = letterPosition.y - letterDef.height;
        }
        
        if (newLine)
        {
            continue;
        }

        nextWordX = nextLetterX;
        letterRight = wordRight;
        if (highestY < wordHighestY)
            highestY = wordHighestY;
        if (lowestY > wordLowestY)
            lowestY = wordLowestY;
        if (longestLine < letterRight)
            longestLine = letterRight;

        index += wordLen;
    }

    _linesWidth.push_back(letterRight);

    _numberOfLines = lineIndex + 1;
    _textDesiredHeight = (_numberOfLines * _lineHeight) / contentScaleFactor;
    Size contentSize(_labelWidth, _labelHeight);
    if (_labelWidth <= 0.f)
        contentSize.width = longestLine;
    if (_labelHeight <= 0.f)
        contentSize.height = _textDesiredHeight;
    setContentSize(contentSize);

    _tailoredTopY = contentSize.height;
    _tailoredBottomY = 0.f;
    if (highestY > 0.f)
        _tailoredTopY = contentSize.height + highestY;
    if (lowestY < -_textDesiredHeight)
        _tailoredBottomY = _textDesiredHeight + lowestY;

    return true;
}
bool Label::multilineTextWrap(const std::function<int(const std::u16string&, int, int)>& nextTokenLen)
{
    int textLen = getStringLength();
    int lineIndex = 0;
    float nextTokenX = 0.f;
    float nextTokenY = 0.f;
    float longestLine = 0.f;
    float letterRight = 0.f;

    auto contentScaleFactor = CC_CONTENT_SCALE_FACTOR();
    float lineSpacing = _lineSpacing * contentScaleFactor;
    float highestY = 0.f;
    float lowestY = 0.f;
    FontLetterDefinition letterDef;
    Vec2 letterPosition;
    bool nextChangeSize = true;

    this->updateBMFontScale();

    for (int index = 0; index < textLen; )
    {
        auto character = _utf16Text[index];
        if (character == (char16_t)TextFormatter::NewLine)
        {
            _linesWidth.push_back(letterRight);
            letterRight = 0.f;
            lineIndex++;
            nextTokenX = 0.f;
            nextTokenY -= _lineHeight*_bmfontScale + lineSpacing;
            recordPlaceholderInfo(index, character);
            index++;
            continue;
        }

        auto tokenLen = nextTokenLen(_utf16Text, index, textLen);
        float tokenHighestY = highestY;;
        float tokenLowestY = lowestY;
        float tokenRight = letterRight;
        float nextLetterX = nextTokenX;
        bool newLine = false;
        for (int tmp = 0; tmp < tokenLen;++tmp)
        {
            int letterIndex = index + tmp;
            character = _utf16Text[letterIndex];
            if (character == (char16_t)TextFormatter::CarriageReturn)
            {
                recordPlaceholderInfo(letterIndex, character);
                continue;
            }
            // \b - Next char not change x position
            if (character == (char16_t)TextFormatter::NextCharNoChangeX)
            {
                nextChangeSize = false;
                recordPlaceholderInfo(letterIndex, character);
                continue;
            }
            if (_fontAtlas->getLetterDefinitionForChar(character, letterDef) == false)
            {
                recordPlaceholderInfo(letterIndex, character);
                CCLOG("LabelTextFormatter error:can't find letter definition in font file for letter: %c", character);
                continue;
            }

            auto letterX = (nextLetterX + letterDef.offsetX * _bmfontScale) / contentScaleFactor;
            if (_enableWrap && _maxLineWidth > 0.f && nextTokenX > 0.f && letterX + letterDef.width * _bmfontScale > _maxLineWidth
                && !StringUtils::isUnicodeSpace(character) && nextChangeSize)
            {
                _linesWidth.push_back(letterRight);
                letterRight = 0.f;
                lineIndex++;
                nextTokenX = 0.f;
                nextTokenY -= (_lineHeight*_bmfontScale + lineSpacing);
                newLine = true;
                break;
            }
            else
            {
                letterPosition.x = letterX;
            }
            letterPosition.y = (nextTokenY - letterDef.offsetY * _bmfontScale) / contentScaleFactor;
            recordLetterInfo(letterPosition, character, letterIndex, lineIndex);

            if (nextChangeSize)
            {
                if (_horizontalKernings && letterIndex < textLen - 1)
                    nextLetterX += _horizontalKernings[letterIndex + 1];
                nextLetterX += letterDef.xAdvance * _bmfontScale + _additionalKerning;

                tokenRight = nextLetterX / contentScaleFactor;
            }
            nextChangeSize = true;

            if (tokenHighestY < letterPosition.y)
                tokenHighestY = letterPosition.y;
            if (tokenLowestY > letterPosition.y - letterDef.height * _bmfontScale)
                tokenLowestY = letterPosition.y - letterDef.height * _bmfontScale;
        }

        if (newLine)
        {
            continue;
        }

        nextTokenX = nextLetterX;
        letterRight = tokenRight;
        if (highestY < tokenHighestY)
            highestY = tokenHighestY;
        if (lowestY > tokenLowestY)
            lowestY = tokenLowestY;
        if (longestLine < letterRight)
            longestLine = letterRight;

        index += tokenLen;
    }

    _linesWidth.push_back(letterRight);

    _numberOfLines = lineIndex + 1;
    _textDesiredHeight = (_numberOfLines * _lineHeight * _bmfontScale) / contentScaleFactor;
    if (_numberOfLines > 1)
        _textDesiredHeight += (_numberOfLines - 1) * _lineSpacing;
    Size contentSize(_labelWidth, _labelHeight);
    if (_labelWidth <= 0.f)
        contentSize.width = longestLine;
    if (_labelHeight <= 0.f)
        contentSize.height = _textDesiredHeight;
    setContentSize(contentSize);

    _tailoredTopY = contentSize.height;
    _tailoredBottomY = 0.f;
    if (highestY > 0.f)
        _tailoredTopY = contentSize.height + highestY;
    if (lowestY < -_textDesiredHeight)
        _tailoredBottomY = _textDesiredHeight + lowestY;

    return true;
}