Size * FontFreeType::getAdvancesForTextUTF16(unsigned short *pText, int &outNumLetters) { if (!pText) return 0; outNumLetters = cc_wcslen(pText); if (!outNumLetters) return 0; Size *pSizes = new Size[outNumLetters]; if (!pSizes) return 0; for (int c = 0; c<outNumLetters; ++c) { int advance = 0; int kerning = 0; advance = getAdvanceForChar(pText[c]) - getBearingXForChar(pText[c]); if ( c < (outNumLetters-1) ) kerning = getHorizontalKerningForChars(pText[c], pText[c+1]); pSizes[c].width = (advance + kerning); } return pSizes; }
unsigned short int * Font::trimUTF16Text(unsigned short int *text, int newBegin, int newEnd) const { if ( newBegin < 0 || newEnd <= 0 ) return 0; if ( newBegin >= newEnd ) return 0; if (newEnd >= cc_wcslen(text)) return 0; int newLenght = newEnd - newBegin + 2; unsigned short* trimmedString = new unsigned short[newLenght]; for(int c = 0; c < (newLenght - 1); ++c) { trimmedString[c] = text[newBegin + c]; } // last char trimmedString[newLenght-1] = 0x0000; // done return trimmedString; }
void Label::alignText() { if (_fontAtlas == nullptr) { return; } for (const auto& batchNode:_batchNodes) { batchNode->getTextureAtlas()->removeAllQuads(); } _fontAtlas->prepareLetterDefinitions(_currentUTF16String); auto textures = _fontAtlas->getTextures(); if (textures.size() > _batchNodes.size()) { for (auto index = _batchNodes.size(); index < textures.size(); ++index) { auto batchNode = SpriteBatchNode::createWithTexture(textures[index]); batchNode->setAnchorPoint(Point::ANCHOR_TOP_LEFT); batchNode->setPosition(Point::ZERO); Node::addChild(batchNode,0,Node::INVALID_TAG); _batchNodes.push_back(batchNode); } } LabelTextFormatter::createStringSprites(this); if(_maxLineWidth > 0 && _contentSize.width > _maxLineWidth && LabelTextFormatter::multilineText(this) ) LabelTextFormatter::createStringSprites(this); if(_labelWidth > 0 || (_currNumLines > 1 && _hAlignment != TextHAlignment::LEFT)) LabelTextFormatter::alignText(this); int strLen = cc_wcslen(_currentUTF16String); Rect uvRect; Sprite* letterSprite; for(const auto &child : _children) { int tag = child->getTag(); if(tag >= strLen) { SpriteBatchNode::removeChild(child, true); } else if(tag >= 0) { letterSprite = dynamic_cast<Sprite*>(child); if (letterSprite) { uvRect.size.height = _lettersInfo[tag].def.height; uvRect.size.width = _lettersInfo[tag].def.width; uvRect.origin.x = _lettersInfo[tag].def.U; uvRect.origin.y = _lettersInfo[tag].def.V; letterSprite->setTexture(textures[_lettersInfo[tag].def.textureID]); letterSprite->setTextureRect(uvRect); } } } updateQuads(); updateColor(); }
char * cc_utf16_to_utf8 (const unsigned short *str, int len, long *items_read, long *items_written) { if (str == NULL) return NULL; std::u16string utf16; int utf16Len = len < 0 ? cc_wcslen(str) : len; for (int i = 0; i < utf16Len; ++i) { utf16.push_back(str[i]); } char* ret = NULL; std::string outUtf8; bool succeed = StringUtils::UTF16ToUTF8(utf16, outUtf8); if (succeed) { ret = new char[outUtf8.length() + 1]; ret[outUtf8.length()] = '\0'; memcpy(ret, outUtf8.data(), outUtf8.length()); } return ret; }
void RSimpleHTMLParser::textHandler(void *ctx, const char *s, int len) { //CCLog("[Parser Text]%s", s); CCAssert(m_rCurrentElement, "[CCRich]: must specify a parent element!"); unsigned short* utf16str = cc_utf8_to_utf16(s); size_t utf16size = cc_wcslen(utf16str); if ( utf16size == 0 ) return; for ( size_t i = 0; i < utf16size; i++ ) { REleGlyph* ele = new REleGlyph(utf16str[i]); if ( ele->parse(this) ) { m_rCurrentElement->addChildren(ele); } else { CC_SAFE_DELETE(ele); } } CC_SAFE_DELETE_ARRAY(utf16str); }
unsigned short int * Font::getUTF16Text(const char *text, int &outNumLetters) const { unsigned short* utf16String = cc_utf8_to_utf16(text); if(!utf16String) return 0; outNumLetters = cc_wcslen(utf16String); return utf16String; }
std::vector<unsigned short> cc_utf16_vec_from_utf16_str(const unsigned short* str) { int len = cc_wcslen(str); std::vector<unsigned short> str_new; for (int i = 0; i < len; ++i) { str_new.push_back(str[i]); } return str_new; }
bool Label::setOriginalString(unsigned short *stringToSet) { if (_originalUTF16String) { delete [] _originalUTF16String; } int newStringLenght = cc_wcslen(stringToSet); _originalUTF16String = new unsigned short int [newStringLenght + 1]; memset(_originalUTF16String, 0, (newStringLenght + 1) * 2); memcpy(_originalUTF16String, stringToSet, (newStringLenght * 2)); _originalUTF16String[newStringLenght] = 0; return true; }
void Label::resetCurrentString() { if ((!_currentUTF16String) && (!_originalUTF16String)) return; // set the new string if (_currentUTF16String) { delete [] _currentUTF16String; _currentUTF16String = 0; } int stringLenght = cc_wcslen(_originalUTF16String); _currentUTF16String = new unsigned short int [stringLenght + 1]; memcpy(_currentUTF16String, _originalUTF16String, stringLenght * 2); _currentUTF16String[stringLenght] = 0; }
bool Label::setText(const char *stringToRender, float lineWidth, TextHAlignment alignment, bool lineBreakWithoutSpaces) { if (!_fontAtlas) return false; // carloX // reset the string resetCurrentString(); _width = lineWidth; _alignment = alignment; _lineBreakWithoutSpaces = lineBreakWithoutSpaces; // release all the sprites moveAllSpritesToCache(); // store locally common line height _commonLineHeight = _fontAtlas->getCommonLineHeight(); if (_commonLineHeight <= 0) return false; int numLetter = 0; unsigned short* utf16String = cc_utf8_to_utf16(stringToRender); if(!utf16String) return false; numLetter = cc_wcslen(utf16String); SpriteBatchNode::initWithTexture(&_fontAtlas->getTexture(0), numLetter); _cascadeColorEnabled = true; // setCurrentString(utf16String); setOriginalString(utf16String); // align text alignText(); // done here return true; }
void Label::computeStringNumLines() { int quantityOfLines = 1; unsigned int stringLen = _currentUTF16String ? cc_wcslen(_currentUTF16String) : -1; if (stringLen < 1) { _currNumLines = stringLen; return; } // count number of lines for (unsigned int i = 0; i < stringLen - 1; ++i) { if (_currentUTF16String[i] == '\n') { quantityOfLines++; } } _currNumLines = quantityOfLines; }
int Label::getStringLenght() const { return _currentUTF16String ? cc_wcslen(_currentUTF16String) : 0; }
int Font::getUTF16TextLenght(unsigned short int *text) const { return cc_wcslen(text); }
int Label::getStringLength() const { return _currentUTF16String ? cc_wcslen(_currentUTF16String) : (int)_originalUTF8String.length(); }
bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) { FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); if(fontTTf == nullptr) return false; int length = cc_wcslen(utf16String); float offsetAdjust = _letterPadding / 2; int bitmapWidth; int bitmapHeight; Rect tempRect; FontLetterDefinition tempDef; auto contentSize = Size(CacheTextureWidth,CacheTextureHeight); auto scaleFactor = CC_CONTENT_SCALE_FACTOR(); auto pixelFormat = fontTTf->getOutlineSize() > 0 ? Texture2D::PixelFormat::AI88 : Texture2D::PixelFormat::A8; bool existNewLetter = false; for (int i = 0; i < length; ++i) { auto outIterator = _fontLetterDefinitions.find(utf16String[i]); if (outIterator == _fontLetterDefinitions.end()) { existNewLetter = true; auto bitmap = fontTTf->getGlyphBitmap(utf16String[i],bitmapWidth,bitmapHeight,tempRect,tempDef.xAdvance); if (bitmap) { tempDef.validDefinition = true; tempDef.letteCharUTF16 = utf16String[i]; tempDef.width = tempRect.size.width + _letterPadding; tempDef.height = tempRect.size.height + _letterPadding; tempDef.offsetX = tempRect.origin.x + offsetAdjust; tempDef.offsetY = _fontAscender + tempRect.origin.y - offsetAdjust; if (_currentPageOrigX + tempDef.width > CacheTextureWidth) { _currentPageOrigY += _commonLineHeight; _currentPageOrigX = 0; if(_currentPageOrigY + _commonLineHeight >= CacheTextureHeight) { _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, CacheTextureWidth, CacheTextureHeight, contentSize ); _currentPageOrigY = 0; memset(_currentPageData, 0, _currentPageDataSize); _currentPage++; auto tex = new Texture2D; addTexture(tex,_currentPage); tex->release(); } } fontTTf->renderCharAt(_currentPageData,_currentPageOrigX,_currentPageOrigY,bitmap,bitmapWidth,bitmapHeight); tempDef.U = _currentPageOrigX; tempDef.V = _currentPageOrigY; tempDef.textureID = _currentPage; _currentPageOrigX += tempDef.width + 1; // take from pixels to points tempDef.width = tempDef.width / scaleFactor; tempDef.height = tempDef.height / scaleFactor; tempDef.U = tempDef.U / scaleFactor; tempDef.V = tempDef.V / scaleFactor; } else{ if(tempDef.xAdvance) tempDef.validDefinition = true; else tempDef.validDefinition = false; tempDef.letteCharUTF16 = utf16String[i]; tempDef.width = 0; tempDef.height = 0; tempDef.U = 0; tempDef.V = 0; tempDef.offsetX = 0; tempDef.offsetY = 0; tempDef.textureID = 0; _currentPageOrigX += 1; } _fontLetterDefinitions[tempDef.letteCharUTF16] = tempDef; } } if(existNewLetter) { _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, CacheTextureWidth, CacheTextureHeight, contentSize ); } return true; }
void UITextArea::createFontChars() { int nextFontPositionX = 0; int nextFontPositionY = 0; //unsigned short prev = -1; int kerningAmount = 0; CCSize tmpSize = CCSizeZero; int longestLine = 0; unsigned int totalHeight = 0; unsigned int quantityOfLines = 1; if (!m_sString) return; unsigned int stringLen = cc_wcslen(m_sString); if (stringLen == 0) { return; } for (unsigned int i = 0; i < stringLen - 1; ++i) { unsigned short c = m_sString[i]; if (c == '\n') { quantityOfLines++; } } totalHeight = m_pConfiguration->m_nCommonHeight * quantityOfLines; nextFontPositionY = 0-(m_pConfiguration->m_nCommonHeight - m_pConfiguration->m_nCommonHeight * quantityOfLines); for (unsigned int i= 0; i < stringLen; i++) { unsigned short c = m_sString[i]; if (c == '\n') { nextFontPositionX = 0; nextFontPositionY -= m_pConfiguration->m_nCommonHeight; continue; } tFontDefHashElement *element = NULL; // unichar is a short, and an int is needed on HASH_FIND_INT unsigned int key = c; HASH_FIND_INT(m_pConfiguration->m_pFontDefDictionary, &key, element); CCAssert(element, "FontDefinition could not be found!"); ccBMFontDef fontDef = element->fontDef; CCRect rect = fontDef.rect; rect = CC_RECT_PIXELS_TO_POINTS(rect); rect.origin.x += m_tImageOffset.x; rect.origin.y += m_tImageOffset.y; CCSprite *fontChar; fontChar = (CCSprite*)(this->getChildByTag(i)); if( ! fontChar ) { fontChar = new CCSprite(); fontChar->initWithTexture(m_pobTextureAtlas->getTexture(), rect); this->addChild(fontChar, 0, i); fontChar->release(); } else { // reusing fonts fontChar->setTextureRect(rect, false, rect.size); // restore to default in case they were modified fontChar->setVisible(true); fontChar->setOpacity(255); } // See issue 1343. cast( signed short + unsigned integer ) == unsigned integer (sign is lost!) int yOffset = m_pConfiguration->m_nCommonHeight - fontDef.yOffset; CCPoint fontPos = ccp( (float)nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width*0.5f + kerningAmount, (float)nextFontPositionY + yOffset - rect.size.height*0.5f * CC_CONTENT_SCALE_FACTOR() ); fontChar->setPosition(CC_POINT_PIXELS_TO_POINTS(fontPos)); // update kerning nextFontPositionX += fontDef.xAdvance + kerningAmount; //prev = c; // Apply label properties fontChar->setOpacityModifyRGB(m_bIsOpacityModifyRGB); // Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on if ( i < colors.size()) { fontChar->setColor(colors.at(i)); } else fontChar->setColor(m_tColor); // only apply opacity if it is different than 255 ) // to prevent modifying the color too (issue #610) if( m_cOpacity != 255 ) { fontChar->setOpacity(m_cOpacity); } if (longestLine < nextFontPositionX) { longestLine = nextFontPositionX; } } tmpSize.width = (float) longestLine; tmpSize.height = (float) totalHeight; this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize)); }
GlyphDef * FontFreeType::getGlyphDefintionsForText(const char *pText, int &outNumGlyphs, bool UTF16text) { unsigned short* utf16String = 0; if (UTF16text) { utf16String = (unsigned short*) pText; } else { utf16String = cc_utf8_to_utf16(pText); } // if (!utf16String) return 0; int numChar = cc_wcslen(utf16String); if (!numChar) return 0; // allocate the needed Glyphs GlyphDef *pGlyphs = new GlyphDef[numChar]; assert( pGlyphs != NULL ); if (!pGlyphs) return 0; // sore result as CCRect for (int c=0; c<numChar; ++c) { Rect tempRect; if( !getBBOXFotChar(utf16String[c], tempRect) ) { log("Warning: Cannot find definition for glyph: %c in font:%s", utf16String[c], _fontName.c_str()); tempRect.origin.x = 0; tempRect.origin.y = 0; tempRect.size.width = 0; tempRect.size.height = 0; pGlyphs[c].setRect(tempRect); pGlyphs[c].setUTF16Letter(utf16String[c]); pGlyphs[c].setValid(false); pGlyphs[c].setPadding(_letterPadding); } else { pGlyphs[c].setRect(tempRect); pGlyphs[c].setUTF16Letter(utf16String[c]); pGlyphs[c].setPadding(_letterPadding); pGlyphs[c].setValid(true); } } outNumGlyphs = numChar; // free memory if (!UTF16text) delete [] utf16String; // done return pGlyphs; }