Label:support font that contains GB2312 char map.

This commit is contained in:
WenhaiLin 2015-07-28 16:28:32 +08:00
parent 3cc039b063
commit 9edd66d4a7
7 changed files with 299 additions and 127 deletions

View File

@ -24,6 +24,11 @@
****************************************************************************/ ****************************************************************************/
#include "2d/CCFontAtlas.h" #include "2d/CCFontAtlas.h"
#if CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_WINRT && CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
#include <iconv.h>
#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
#include "android/jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h"
#endif
#include "2d/CCFontFreeType.h" #include "2d/CCFontFreeType.h"
#include "base/ccUTF8.h" #include "base/ccUTF8.h"
#include "base/CCDirector.h" #include "base/CCDirector.h"
@ -31,7 +36,6 @@
#include "base/CCEventDispatcher.h" #include "base/CCEventDispatcher.h"
#include "base/CCEventType.h" #include "base/CCEventType.h"
NS_CC_BEGIN NS_CC_BEGIN
const int FontAtlas::CacheTextureWidth = 512; const int FontAtlas::CacheTextureWidth = 512;
@ -41,6 +45,8 @@ const char* FontAtlas::CMD_RESET_FONTATLAS = "__cc_RESET_FONTATLAS";
FontAtlas::FontAtlas(Font &theFont) FontAtlas::FontAtlas(Font &theFont)
: _font(&theFont) : _font(&theFont)
, _fontFreeType(nullptr)
, _iconv(nullptr)
, _currentPageData(nullptr) , _currentPageData(nullptr)
, _fontAscender(0) , _fontAscender(0)
, _rendererRecreatedListener(nullptr) , _rendererRecreatedListener(nullptr)
@ -49,23 +55,23 @@ FontAtlas::FontAtlas(Font &theFont)
{ {
_font->retain(); _font->retain();
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); _fontFreeType = dynamic_cast<FontFreeType*>(_font);
if (fontTTf) if (_fontFreeType)
{ {
_lineHeight = _font->getFontMaxHeight(); _lineHeight = _font->getFontMaxHeight();
_fontAscender = fontTTf->getFontAscender(); _fontAscender = _fontFreeType->getFontAscender();
auto texture = new (std::nothrow) Texture2D; auto texture = new (std::nothrow) Texture2D;
_currentPage = 0; _currentPage = 0;
_currentPageOrigX = 0; _currentPageOrigX = 0;
_currentPageOrigY = 0; _currentPageOrigY = 0;
_letterPadding = 0; _letterPadding = 0;
if(fontTTf->isDistanceFieldEnabled()) if (_fontFreeType->isDistanceFieldEnabled())
{ {
_letterPadding += 2 * FontFreeType::DistanceMapSpread; _letterPadding += 2 * FontFreeType::DistanceMapSpread;
} }
_currentPageDataSize = CacheTextureWidth * CacheTextureHeight; _currentPageDataSize = CacheTextureWidth * CacheTextureHeight;
auto outlineSize = fontTTf->getOutlineSize(); auto outlineSize = _fontFreeType->getOutlineSize();
if(outlineSize > 0) if(outlineSize > 0)
{ {
_lineHeight += 2 * outlineSize; _lineHeight += 2 * outlineSize;
@ -94,8 +100,7 @@ FontAtlas::FontAtlas(Font &theFont)
FontAtlas::~FontAtlas() FontAtlas::~FontAtlas()
{ {
#if CC_ENABLE_CACHE_TEXTURE_DATA #if CC_ENABLE_CACHE_TEXTURE_DATA
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); if (_fontFreeType && _rendererRecreatedListener)
if (fontTTf && _rendererRecreatedListener)
{ {
auto eventDispatcher = Director::getInstance()->getEventDispatcher(); auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->removeEventListener(_rendererRecreatedListener); eventDispatcher->removeEventListener(_rendererRecreatedListener);
@ -107,6 +112,14 @@ FontAtlas::~FontAtlas()
relaseTextures(); relaseTextures();
delete []_currentPageData; delete []_currentPageData;
#if CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_WINRT && CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
if (_iconv)
{
iconv_close(_iconv);
_iconv = nullptr;
}
#endif
} }
void FontAtlas::relaseTextures() void FontAtlas::relaseTextures()
@ -120,8 +133,7 @@ void FontAtlas::relaseTextures()
void FontAtlas::purgeTexturesAtlas() void FontAtlas::purgeTexturesAtlas()
{ {
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); if (_fontFreeType && _atlasTextures.size() > 1)
if (fontTTf && _atlasTextures.size() > 1)
{ {
auto eventDispatcher = Director::getInstance()->getEventDispatcher(); auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->dispatchCustomEvent(CMD_PURGE_FONTATLAS,this); eventDispatcher->dispatchCustomEvent(CMD_PURGE_FONTATLAS,this);
@ -131,8 +143,7 @@ void FontAtlas::purgeTexturesAtlas()
void FontAtlas::listenRendererRecreated(EventCustom *event) void FontAtlas::listenRendererRecreated(EventCustom *event)
{ {
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); if (_fontFreeType)
if (fontTTf)
{ {
auto eventDispatcher = Director::getInstance()->getEventDispatcher(); auto eventDispatcher = Director::getInstance()->getEventDispatcher();
eventDispatcher->dispatchCustomEvent(CMD_PURGE_FONTATLAS,this); eventDispatcher->dispatchCustomEvent(CMD_PURGE_FONTATLAS,this);
@ -160,13 +171,133 @@ bool FontAtlas::getLetterDefinitionForChar(char16_t utf16Char, FontLetterDefinit
} }
} }
bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String) void FontAtlas::conversionU16TOGB2312(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap)
{ {
FontFreeType* fontTTf = dynamic_cast<FontFreeType*>(_font); size_t strLen = u16Text.length();
if(fontTTf == nullptr) auto gb2312StrSize = strLen * 2;
return false; auto gb2312Text = new (std::nothrow) char[gb2312StrSize];
memset(gb2312Text, 0, gb2312StrSize);
size_t length = utf16String.length(); 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;
}
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.resize(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 FontAtlas::prepareLetterDefinitions(const std::u16string& utf16Text)
{
if (_fontFreeType == nullptr)
{
return false;
}
std::unordered_map<unsigned short, unsigned short> codeMapOfNewChar;
findNewCharacters(utf16Text, codeMapOfNewChar);
if (codeMapOfNewChar.empty())
{
return false;
}
float offsetAdjust = _letterPadding / 2; float offsetAdjust = _letterPadding / 2;
long bitmapWidth; long bitmapWidth;
@ -175,20 +306,13 @@ bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String)
FontLetterDefinition tempDef; FontLetterDefinition tempDef;
auto scaleFactor = CC_CONTENT_SCALE_FACTOR(); auto scaleFactor = CC_CONTENT_SCALE_FACTOR();
auto pixelFormat = fontTTf->getOutlineSize() > 0 ? Texture2D::PixelFormat::AI88 : Texture2D::PixelFormat::A8; auto pixelFormat = _fontFreeType->getOutlineSize() > 0 ? Texture2D::PixelFormat::AI88 : Texture2D::PixelFormat::A8;
bool existNewLetter = false;
float startY = _currentPageOrigY; float startY = _currentPageOrigY;
for (size_t i = 0; i < length; ++i) for (auto&& it : codeMapOfNewChar)
{ {
auto outIterator = _letterDefinitions.find(utf16String[i]); auto bitmap = _fontFreeType->getGlyphBitmap(it.second, bitmapWidth, bitmapHeight, tempRect, tempDef.xAdvance);
if (outIterator == _letterDefinitions.end())
{
existNewLetter = true;
auto bitmap = fontTTf->getGlyphBitmap(utf16String[i],bitmapWidth,bitmapHeight,tempRect,tempDef.xAdvance);
if (bitmap && bitmapWidth > 0 && bitmapHeight > 0) if (bitmap && bitmapWidth > 0 && bitmapHeight > 0)
{ {
tempDef.validDefinition = true; tempDef.validDefinition = true;
@ -240,7 +364,7 @@ bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String)
tex->release(); tex->release();
} }
} }
fontTTf->renderCharAt(_currentPageData,_currentPageOrigX,_currentPageOrigY,bitmap,bitmapWidth,bitmapHeight); _fontFreeType->renderCharAt(_currentPageData, _currentPageOrigX, _currentPageOrigY, bitmap, bitmapWidth, bitmapHeight);
tempDef.U = _currentPageOrigX; tempDef.U = _currentPageOrigX;
tempDef.V = _currentPageOrigY; tempDef.V = _currentPageOrigY;
@ -268,12 +392,9 @@ bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String)
_currentPageOrigX += 1; _currentPageOrigX += 1;
} }
_letterDefinitions[utf16String[i]] = tempDef; _letterDefinitions[it.first] = tempDef;
}
} }
if(existNewLetter)
{
unsigned char *data = nullptr; unsigned char *data = nullptr;
if (pixelFormat == Texture2D::PixelFormat::AI88) if (pixelFormat == Texture2D::PixelFormat::AI88)
{ {
@ -283,9 +404,8 @@ bool FontAtlas::prepareLetterDefinitions(const std::u16string& utf16String)
{ {
data = _currentPageData + CacheTextureWidth * (int)startY; data = _currentPageData + CacheTextureWidth * (int)startY;
} }
_atlasTextures[_currentPage]->updateWithData(data, 0, startY, _atlasTextures[_currentPage]->updateWithData(data, 0, startY, CacheTextureWidth, _currentPageOrigY - startY + _lineHeight);
CacheTextureWidth, _currentPageOrigY - startY + _lineHeight);
}
return true; return true;
} }

View File

@ -41,6 +41,7 @@ class Font;
class Texture2D; class Texture2D;
class EventCustom; class EventCustom;
class EventListenerCustom; class EventListenerCustom;
class FontFreeType;
struct FontLetterDefinition struct FontLetterDefinition
{ {
@ -109,10 +110,17 @@ public:
protected: protected:
void relaseTextures(); void relaseTextures();
void findNewCharacters(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap);
void conversionU16TOGB2312(const std::u16string& u16Text, std::unordered_map<unsigned short, unsigned short>& charCodeMap);
std::unordered_map<ssize_t, Texture2D*> _atlasTextures; std::unordered_map<ssize_t, Texture2D*> _atlasTextures;
std::unordered_map<char16_t, FontLetterDefinition> _letterDefinitions; std::unordered_map<char16_t, FontLetterDefinition> _letterDefinitions;
float _lineHeight; float _lineHeight;
Font* _font; Font* _font;
FontFreeType* _fontFreeType;
void* _iconv;
// Dynamic GlyphCollection related stuff // Dynamic GlyphCollection related stuff
int _currentPage; int _currentPage;

View File

@ -99,6 +99,7 @@ FontFreeType::FontFreeType(bool distanceFieldEnabled /* = false */,int outline /
, _outlineSize(0.0f) , _outlineSize(0.0f)
, _lineHeight(0) , _lineHeight(0)
, _fontAtlas(nullptr) , _fontAtlas(nullptr)
, _encoding(FT_ENCODING_UNICODE)
{ {
if (outline > 0) if (outline > 0)
{ {
@ -154,7 +155,8 @@ bool FontFreeType::createFontObject(const std::string &fontName, int fontSize)
return false; return false;
} }
if (FT_Select_Charmap(face, face->charmaps[foundIndex]->encoding)) _encoding = face->charmaps[foundIndex]->encoding;
if (FT_Select_Charmap(face, _encoding))
{ {
return false; return false;
} }

View File

@ -53,35 +53,38 @@ class CC_DLL FontFreeType : public Font
public: public:
static const int DistanceMapSpread; static const int DistanceMapSpread;
static FontFreeType * create(const std::string &fontName, int fontSize, GlyphCollection glyphs, const char *customGlyphs,bool distanceFieldEnabled = false,int outline = 0); static FontFreeType* create(const std::string &fontName, int fontSize, GlyphCollection glyphs,
const char *customGlyphs,bool distanceFieldEnabled = false,int outline = 0);
static void shutdownFreeType(); static void shutdownFreeType();
bool isDistanceFieldEnabled() const { return _distanceFieldEnabled;} bool isDistanceFieldEnabled() const { return _distanceFieldEnabled;}
float getOutlineSize() const { return _outlineSize; } float getOutlineSize() const { return _outlineSize; }
void renderCharAt(unsigned char *dest,int posX, int posY, unsigned char* bitmap,long bitmapWidth,long bitmapHeight); void renderCharAt(unsigned char *dest,int posX, int posY, unsigned char* bitmap,long bitmapWidth,long bitmapHeight);
virtual FontAtlas * createFontAtlas() override; FT_Encoding getEncoding() const { return _encoding; }
virtual int * getHorizontalKerningForTextUTF16(const std::u16string& text, int &outNumLetters) const override;
int* getHorizontalKerningForTextUTF16(const std::u16string& text, int &outNumLetters) const override;
unsigned char* getGlyphBitmap(unsigned short theChar, long &outWidth, long &outHeight, Rect &outRect,int &xAdvance); unsigned char* getGlyphBitmap(unsigned short theChar, long &outWidth, long &outHeight, Rect &outRect,int &xAdvance);
int getFontAscender() const;
virtual FontAtlas* createFontAtlas() override;
virtual int getFontMaxHeight() const override { return _lineHeight; } virtual int getFontMaxHeight() const override { return _lineHeight; }
virtual int getFontAscender() const; private:
protected:
FontFreeType(bool distanceFieldEnabled = false, int outline = 0); FontFreeType(bool distanceFieldEnabled = false, int outline = 0);
virtual ~FontFreeType(); virtual ~FontFreeType();
bool createFontObject(const std::string &fontName, int fontSize);
private: bool createFontObject(const std::string &fontName, int fontSize);
bool initFreeType(); bool initFreeType();
FT_Library getFTLibrary(); FT_Library getFTLibrary();
int getHorizontalKerningForChars(unsigned short firstChar, unsigned short secondChar) const; int getHorizontalKerningForChars(unsigned short firstChar, unsigned short secondChar) const;
unsigned char * getGlyphBitmapWithOutline(unsigned short theChar, FT_BBox &bbox); unsigned char* getGlyphBitmapWithOutline(unsigned short code, FT_BBox &bbox);
static FT_Library _FTlibrary; static FT_Library _FTlibrary;
static bool _FTInitialized; static bool _FTInitialized;
@ -92,6 +95,8 @@ private:
float _outlineSize; float _outlineSize;
int _lineHeight; int _lineHeight;
FontAtlas* _fontAtlas; FontAtlas* _fontAtlas;
FT_Encoding _encoding;
}; };
/// @endcond /// @endcond

View File

@ -532,6 +532,18 @@ public class Cocos2dxHelper {
editor.commit(); editor.commit();
} }
public static byte[] conversionEncoding(byte[] text, String fromCharset,String newCharset)
{
try {
String str = new String(text,fromCharset);
return str.getBytes(newCharset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
// =========================================================== // ===========================================================
// Inner and Anonymous Classes // Inner and Anonymous Classes
// =========================================================== // ===========================================================

View File

@ -413,3 +413,25 @@ void deleteValueForKeyJNI(const char* key)
t.env->DeleteLocalRef(stringArg1); t.env->DeleteLocalRef(stringArg1);
} }
} }
void conversionEncodingJNI(const char* src, int byteSize, const char* fromCharset, char* dst, const char* newCharset)
{
JniMethodInfo methodInfo;
if (JniHelper::getStaticMethodInfo(methodInfo, CLASS_NAME, "conversionEncoding", "([BLjava/lang/String;Ljava/lang/String;)[B")) {
jbyteArray strArray = methodInfo.env->NewByteArray(byteSize);
methodInfo.env->SetByteArrayRegion(strArray, 0, byteSize, reinterpret_cast<const jbyte*>(src));
jstring stringArg1 = methodInfo.env->NewStringUTF(fromCharset);
jstring stringArg2 = methodInfo.env->NewStringUTF(newCharset);
jbyteArray newArray = (jbyteArray)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, strArray, stringArg1, stringArg2);
jsize theArrayLen = methodInfo.env->GetArrayLength(newArray);
methodInfo.env->GetByteArrayRegion(newArray, 0, theArrayLen, (jbyte*)dst);
methodInfo.env->DeleteLocalRef(strArray);
methodInfo.env->DeleteLocalRef(stringArg1);
methodInfo.env->DeleteLocalRef(stringArg2);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}
}

View File

@ -54,4 +54,7 @@ extern void setFloatForKeyJNI(const char* key, float value);
extern void setDoubleForKeyJNI(const char* key, double value); extern void setDoubleForKeyJNI(const char* key, double value);
extern void setStringForKeyJNI(const char* key, const char* value); extern void setStringForKeyJNI(const char* key, const char* value);
extern void deleteValueForKeyJNI(const char* key); extern void deleteValueForKeyJNI(const char* key);
extern void conversionEncodingJNI(const char* src, int byteSize, const char* fromCharset, char* dst, const char* newCharset);
#endif /* __Java_org_cocos2dx_lib_Cocos2dxHelper_H__ */ #endif /* __Java_org_cocos2dx_lib_Cocos2dxHelper_H__ */