一个神奇的字符 (cocos2dx crash)

今天测试发现了游戏的一个问题,系统邮件,如果发了tab,在android上一打开邮件内容就会crash。而且他们很确定是tab的问题。

凭我多个月的经验(确实没多年。。。)来看,从来没听说在android上会因为一个tab崩溃,而且如果有这个问题,肯定会有很多人遇到,估计早就吵翻天了,搜索了一下,什么可用信息都没有。

于是写个测试工程测试了一下,分别在mac下和windows下,用文本编辑工具编辑了4个txt文档,utf有bom和无bom,内容是“ tab abcd ”,发现都能正常显示,也不会crash。如下:

unsigned long fSize = 0;unsigned char *data = CCFileUtils::sharedFileUtils()->getFileData("tab.txt", "rb", &fSize);CCLabelTTF *label = CCLabelTTF::create((const char*)data, "abc", 30);label->setPosition(ccp(visibleSize.width/2, visibleSize.height/2));addChild(label);

。那么tab肯定会被拆成单个字符,最后发现就是在生成这个tab的纹理的时候,crash了。堆栈如下:

顺便科普一下labelTTF显示的原理,大致就是,通过字体和字号,然后调用相应平台的api,生成一张图(image),注意是一张图啊,然后作为纹理,设置给一个精灵。从上面的堆栈来看,就是在生成这个image的时候crash了。

然后找代码,在CCTexture2D下找到上面堆栈的最后一步,如下:

bool CCTexture2D::initWithString(const char *text, const char *fontName, float fontSize, const CCSize& dimensions, CCTextAlignment hAlignment, CCVerticalTextAlignment vAlignment){… … … …do{CCImage* pImage = new CCImage();CC_BREAK_IF(NULL == pImage);bRet = pImage->initWithString(text, (int)dimensions.width, (int)dimensions.height, eAlign, fontName, (int)fontSize);CC_BREAK_IF(!bRet);bRet = initWithImage(pImage);CC_SAFE_RELEASE(pImage);} while (0);… … … …return bRet; }这里第一步是,new一个image出来,然后用文字去init这个image,然后再用这个image去init这个texture。我们接着看init这个image这里,android下的代码是这样的:bool CCImage::initWithString(const char * pText,intnWidth/* = 0*/,intnHeight/* = 0*/,ETextAligneAlignMask/* = kAlignCenter*/,const char * pFontName/* = nil*/,intnSize/* = 0*/){bool bRet = false;do{CC_BREAK_IF(! pText);BitmapDC &dc = sharedBitmapDC();CC_BREAK_IF(! dc.getBitmapFromJava(pText, nWidth, nHeight, eAlignMask, pFontName, nSize));m_pData = dc.m_pData;CC_BREAK_IF(! m_pData);m_nWidth = (short)dc.m_nWidth;m_nHeight = (short)dc.m_nHeight;m_bHasAlpha = true;m_bPreMulti = true;m_nBitsPerComponent = 8;bRet = true;} while (0);return bRet;}其中重点是getBitmapFromJava这个函数,如下 bool getBitmapFromJava(const char *text, int nWidth, int nHeight, CCImage::ETextAlign eAlignMask, const char * pFontName, float fontSize){return getBitmapFromJavaShadowStroke(text, nWidth, nHeight, eAlignMask, pFontName, fontSize );} 从这里就知道了,肯定是把文字,字体,字号这些东西,叫给java层,让它们调用系统相关的东西,返回一个bitmap回来,然后就是下一步,把这个返回的image去初始化texture。但是不需要下一步了,因为到这就crash了,得到如下log:

从这个log看,大概意思就是java层在创建bitmap的时候,需要一个图片的宽高,但是这个大小等于0了。

但是之前测试是可以显示tab的,仔细想想,之前的测试有一个问题,就是之前的测试都是tab加其他字符的混合,这个地方因为富文本框的处理,是单个tab字符,那么再用单个tab测试一下。果然就和上面一样crash了。

再回到这个crash log本身,这个要生成的图,就是写了字的那个图,那么这个图片的宽高应该取决于字符的内容和字符的大小,怎么会是0呢。难道是因为tab在android上面会被自动忽略。马上再写个工程测试:

unsigned long fSize = 0;unsigned char *data = CCFileUtils::sharedFileUtils()->getFileData("tab.txt", "rb", &fSize);CCLabelTTF *label = CCLabelTTF::create((const char*)data, "abc", 30);label->setPosition(ccp(visibleSize.width/2, visibleSize.height/2));CCLayerColor *col = CCLayerColor::create(ccc4(123, 255,0 , 255));col->setContentSize(label->getContentSize());col->ignoreAnchorPointForPosition(false);col->setAnchorPoint(ccp(0.5, 0.5));col->setPosition(ccp(label->getPosition().x,label->getPosition().y));addChild(col);addChild(label); 这个测试和之前那个的区别,主要在于在文字后面加了一个同大小的色块,这样我们就能看到纹理的实际范围(早该如此,其实是开始2了没想到。。。),果然发现不管如何加tab,tab都不会显示,纹理的大小和不加tab的大小是一样的。

如果在cocos2dx上是这样,但是他最后会调用到android系统的java层去生成这个bitmap,,说明这个不是cocos2dx的问题,那么在android应用上,tab会不会被忽略呢,果断开个工程再测试,如下:

<LinearLayout xmlns:android=""xmlns:tools=""android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world"android:background="#FFFF0000"/></LinearLayout><resources><string name="app_name">tabTest</string><string name="hello_world">Hello world!</string><string name="action_settings">Settings</string></resources> 果然还是没显示tab,哈哈哈哈哈,收工~~

总结:android系统会忽略tab,在cocos2dx里面用CCLabelTTF的时候,如果文本内容只有一个tab字符,会crash。

看着你手中的戒指,你说,你可以把它取下来吗?

一个神奇的字符 (cocos2dx crash)

相关文章:

你感兴趣的文章:

标签云: