void FontAtlas::findNewCharacters(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap) { std::u16string newChars; FT_Encoding charEncoding = _fontFreeType->getEncoding(); //find new characters if (_letterDefinitions.empty()) { // fixed #16169: new android project crash in android 5.0.2 device (Nexus 7) when use 3.12. // While using clang compiler with gnustl_static on android, the copy assignment operator of `std::u16string` // will affect the memory validity, it means after `newChars` is destroyed, the memory of `u16Text` holds // will be a dead region. `u16text` represents the variable in `Label::_utf16Text`, when somewhere // allocates memory by `malloc, realloc, new, new[]`, the generated memory address may be the same // as `Label::_utf16Text` holds. If doing a `memset` or other memory operations, the orignal `Label::_utf16Text` // will be in an unknown state. Meanwhile, a bunch lots of logic which depends on `Label::_utf16Text` // will be broken. // newChars = u16Text; // Using `append` method is a workaround for this issue. So please be carefuly while using the assignment operator // of `std::u16string`. newChars.append(u16Text); } else { auto length = u16Text.length(); newChars.reserve(length); for (size_t i = 0; i < length; ++i) { auto outIterator = _letterDefinitions.find(u16Text[i]); if (outIterator == _letterDefinitions.end()) { newChars.push_back(u16Text[i]); } } } if (!newChars.empty()) { switch (charEncoding) { case FT_ENCODING_UNICODE: { for (auto u16Code : newChars) { charCodeMap[u16Code] = u16Code; } break; } case FT_ENCODING_GB2312: { conversionU16TOGB2312(newChars, charCodeMap); break; } default: OUTPUT_LOG("FontAtlas::findNewCharacters: Unsupported encoding:%d", charEncoding); break; } } }
std::vector<char16_t> getChar16VectorFromUTF16String(const std::u16string& utf16) { std::vector<char16_t> ret; size_t len = utf16.length(); ret.reserve(len); for (size_t i = 0; i < len; ++i) { ret.push_back(utf16[i]); } return ret; }
bool convertUTF16ToUTF8String(const std::u16string& utf16, std::string &Out) { assert(Out.empty()); // Avoid OOB by returning early on empty input. if (utf16.empty()) return true; const UTF16 *Src = reinterpret_cast<const UTF16 *>(utf16.data()); const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(utf16.data() + utf16.length()); // Byteswap if necessary. std::vector<UTF16> ByteSwapped; if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) { ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd); for (size_t I = 0, E = ByteSwapped.size(); I != E; ++I) ByteSwapped[I] = SwapByteOrder_16(ByteSwapped[I]); Src = &ByteSwapped[0]; SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1; } // Skip the BOM for conversion. if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE) Src++; // Just allocate enough space up front. We'll shrink it later. Out.resize(utf16.length() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1); UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]); UTF8 *DstEnd = Dst + Out.size(); ConversionResult CR = ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion); assert(CR != targetExhausted); if (CR != conversionOK) { Out.clear(); return false; } Out.resize(reinterpret_cast<char *>(Dst) - &Out[0]); return true; }
bool mapToDimension(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; if (value[0] == '+') { if (value.erase(0, 1).empty()) return false; } size_t pos = 0; while (value[pos] == '0') ++pos; if (0 < pos) { if (value.erase(0, pos).empty()) return false; } pos = 0; while (isDigit(value[pos])) ++pos; if (value.length() <= pos) { value += u"px"; return true; } size_t end = pos; if (value[pos] == '.') { ++pos; if (value.length() <= pos || !isDigit(value[pos])) { value.replace(end, std::u16string::npos, u"px"); return true; } ++pos; while (isDigit(value[pos])) ++pos; } if (pos < value.length() && value[pos] == '%') { value.erase(++pos); return true; } value.replace(pos, std::u16string::npos, u"px"); // TODO: Check whether floating point length should be allowed return true; }
bool mapToInteger(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; const char16_t* input = value.c_str(); const char16_t* end = input + value.length(); int u; end = parseInt(input, end, u); if (!end) return false; value.erase(end - input); return true; }
std::string utf16_to_ascii8(const std::u16string& utf16_string) { // Strip extended codes, map to '#' instead (placeholder) std::vector<u8> out; out.reserve(utf16_string.length() + 1); for (const auto& code : utf16_string) { out.push_back(code > 0xFF ? '#': (u8)code); } out.push_back(0); return { reinterpret_cast<char*>(out.data()) }; }
bool UserDictionaryDecoder::DecodeArticle( IBitStream *bstr, std::u16string &res, std::u16string const& prefix, LenTable& ltArticles, std::vector<char32_t>& articleSymbols) { unsigned len = bstr->read(16); if (len == 0xFFFF) { len = bstr->read(32); } res.clear(); unsigned symIdx; std::vector<uint32_t> vec; while ((unsigned)res.length() < len) { ltArticles.Decode(*bstr, symIdx); unsigned sym = articleSymbols.at(symIdx); vec.push_back(sym); if (sym >= 0x10000) { if (sym >= 0x10040) { unsigned startIdx = bstr->read(BitLength(len)); unsigned len = sym - 0x1003d; res += res.substr(startIdx, len); vec.push_back(startIdx); } else { unsigned startIdx = bstr->read(BitLength(prefix.length())); unsigned len = sym - 0xfffd; res += prefix.substr(startIdx, len); vec.push_back(startIdx); } } else { res += (char16_t)sym; } } return true; }
bool mapToPixelLength(std::u16string& value) { if (stripLeadingWhitespace(value).empty()) return false; const char16_t* input = value.c_str(); const char16_t* end = input + value.length(); int u; end = parseInt(input, end, u); if (!end || u < 0) return false; if (0 < u) value.replace(end - input, std::u16string::npos, u"px"); else value.erase(end - input); return true; }
void FontAtlas::findNewCharacters(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap) { std::u16string newChars; FT_Encoding charEncoding = _fontFreeType->getEncoding(); //find new characters if (_letterDefinitions.empty()) { newChars = u16Text; } else { auto length = u16Text.length(); newChars.reserve(length); for (size_t i = 0; i < length; ++i) { auto outIterator = _letterDefinitions.find(u16Text[i]); if (outIterator == _letterDefinitions.end()) { newChars.push_back(u16Text[i]); } } } if (!newChars.empty()) { switch (charEncoding) { case FT_ENCODING_UNICODE: { for (auto u16Code : newChars) { charCodeMap[u16Code] = u16Code; } break; } case FT_ENCODING_GB2312: { conversionU16TOGB2312(newChars, charCodeMap); break; } default: CCLOG("FontAtlas::findNewCharacters: Unsupported encoding:%d", charEncoding); break; } } }
bool HTMLElementImp::toPxOrPercentage(std::u16string& value) { stripLeadingAndTrailingWhitespace(value); if (value.empty()) return false; const char16_t* s = value.c_str(); while (*s) { if (*s == '%') break; if (!isDigit(*s)) return false; ++s; } if (!*s) { value += u"px"; return true; } assert(*s == '%'); if (!s[1] && 1 < value.length()) return true; return false; }
void ctr::news::add(std::u16string title, std::u16string message, void* image, u32 imageSize, bool jpeg) { if(!initialized) { ctr::err::set(initError); return; } ctr::err::parse(ctr::err::SOURCE_NEWS_ADD_NOTIFICATION, (u32) NEWS_AddNotification((const u16*) title.c_str(), title.length(), (const u16*) message.c_str(), message.length(), image, imageSize, jpeg)); }
void FontAtlas::conversionU16TOGB2312(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap) { size_t strLen = u16Text.length(); auto gb2312StrSize = strLen * 2; auto gb2312Text = new (std::nothrow) char[gb2312StrSize]; memset(gb2312Text, 0, gb2312StrSize); switch (_fontFreeType->getEncoding()) { case FT_ENCODING_GB2312: { #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 || CC_TARGET_PLATFORM == CC_PLATFORM_WINRT WideCharToMultiByte(936, NULL, (LPCWCH)u16Text.c_str(), strLen, (LPSTR)gb2312Text, gb2312StrSize, NULL, NULL); #elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID conversionEncodingJNI((char*)u16Text.c_str(), gb2312StrSize, "UTF-16LE", gb2312Text, "GB2312"); #else if (_iconv == nullptr) { _iconv = iconv_open("gb2312", "utf-16le"); } if (_iconv == (iconv_t)-1) { CCLOG("conversion from utf16 to gb2312 not available"); } else { char* pin = (char*)u16Text.c_str(); char* pout = gb2312Text; size_t inLen = strLen * 2; size_t outLen = gb2312StrSize; iconv(_iconv, (char**)&pin, &inLen, &pout, &outLen); } #endif } break; default: CCLOG("Unsupported encoding:%d", _fontFreeType->getEncoding()); break; } unsigned short gb2312Code = 0; unsigned char* dst = (unsigned char*)&gb2312Code; unsigned short u16Code; for (size_t index = 0, gbIndex = 0; index < strLen; ++index) { u16Code = u16Text[index]; if (u16Code < 256) { charCodeMap[u16Code] = u16Code; gbIndex += 1; } else { dst[0] = gb2312Text[gbIndex + 1]; dst[1] = gb2312Text[gbIndex]; charCodeMap[u16Code] = gb2312Code; gbIndex += 2; } } delete[] gb2312Text; }
bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String) { FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); if(fontTTf == nullptr) return false; size_t length = utf16String.length(); float offsetAdjust = _letterPadding / 2; long bitmapWidth; long bitmapHeight; Rect tempRect; FontLetterDefinition tempDef; auto scaleFactor = CC_CONTENT_SCALE_FACTOR(); auto pixelFormat = fontTTf->getOutlineSize() > 0 ? Texture2D::PixelFormat::AI88 : Texture2D::PixelFormat::A8; bool existNewLetter = false; int bottomHeight = _commonLineHeight - _fontAscender; float startY = _currentPageOrigY; for (size_t 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; tempDef.clipBottom = bottomHeight - (tempDef.height + tempRect.origin.y + offsetAdjust); if (_currentPageOrigX + tempDef.width > CacheTextureWidth) { _currentPageOrigY += _commonLineHeight; _currentPageOrigX = 0; if(_currentPageOrigY + _commonLineHeight >= CacheTextureHeight) { unsigned char *data = nullptr; if(pixelFormat == Texture2D::PixelFormat::AI88) { data = _currentPageData + CacheTextureWidth * (int)startY * 2; } else { data = _currentPageData + CacheTextureWidth * (int)startY; } _atlasTextures[_currentPage]->updateWithData(data, 0, startY, CacheTextureWidth, CacheTextureHeight - startY); startY = 0.0f; _currentPageOrigY = 0; memset(_currentPageData, 0, _currentPageDataSize); _currentPage++; auto tex = new (std::nothrow) Texture2D; if (_antialiasEnabled) { tex->setAntiAliasTexParameters(); } else { tex->setAliasTexParameters(); } tex->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, CacheTextureWidth, CacheTextureHeight, Size(CacheTextureWidth,CacheTextureHeight) ); 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; tempDef.clipBottom = 0; _currentPageOrigX += 1; } _fontLetterDefinitions[tempDef.letteCharUTF16] = tempDef; } } if(existNewLetter) { if (_rendererRecreate) { _atlasTextures[_currentPage]->initWithData(_currentPageData, _currentPageDataSize, pixelFormat, CacheTextureWidth, CacheTextureHeight, Size(CacheTextureWidth,CacheTextureHeight) ); } else { unsigned char *data = nullptr; if(pixelFormat == Texture2D::PixelFormat::AI88) { data = _currentPageData + CacheTextureWidth * (int)startY * 2; } else { data = _currentPageData + CacheTextureWidth * (int)startY; } _atlasTextures[_currentPage]->updateWithData(data, 0, startY, CacheTextureWidth, _currentPageOrigY - startY + _commonLineHeight); } } return true; }
bool toInteger(const std::u16string& value, int& output) { const char16_t* input = value.c_str(); const char16_t* end = input + value.length(); return parseInt(input, end, output); // Do not care what follows after digits. }
void FontAtlas::conversionU16TOGB2312(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap) { size_t strLen = u16Text.length(); auto gb2312StrSize = strLen * 2; auto gb2312Text = new (std::nothrow) char[gb2312StrSize]; memset(gb2312Text, 0, gb2312StrSize); switch (_fontFreeType->getEncoding()) { case FT_ENCODING_GB2312: { if (_iconv == nullptr) { _iconv = iconv_open("gb2312", "utf-16le"); } if (_iconv == (iconv_t)-1) { OUTPUT_LOG("conversion from utf16 to gb2312 not available"); } else { char* pout = gb2312Text; size_t inLen = strLen * 2; size_t outLen = gb2312StrSize; #if _LIBICONV_VERSION == 0x109 || _LIBICONV_VERSION == 0x010F const char* pin = (char*)u16Text.c_str(); iconv(_iconv, &pin, &inLen, &pout, &outLen); #else char* pin = (char*)u16Text.c_str(); iconv(_iconv, &pin, &inLen, &pout, &outLen); #endif } } break; default: OUTPUT_LOG("Unsupported encoding:%d", _fontFreeType->getEncoding()); break; } unsigned short gb2312Code = 0; unsigned char* dst = (unsigned char*)&gb2312Code; unsigned short u16Code; for (size_t index = 0, gbIndex = 0; index < strLen; ++index) { u16Code = u16Text[index]; if (u16Code < 256) { charCodeMap[u16Code] = u16Code; gbIndex += 1; } else { dst[0] = gb2312Text[gbIndex + 1]; dst[1] = gb2312Text[gbIndex]; charCodeMap[u16Code] = gb2312Code; gbIndex += 2; } } delete[] gb2312Text; }