zoukankan      html  css  js  c++  java
  • Android 上的 制表符(tab) —— 一个奇妙的字符 (cocos2dx crash)

    今天測试发现了游戏的一个问题,系统邮件,假设发了tab,在android上一打开邮件内容就会crash。并且他们非常确定是tab的问题。


        凭我多个月的经验(确实没多年。

    。)来看。从来没听说在android上会由于一个tab崩溃。并且假设有这个问题。肯定会有非常多人遇到,预计早就吵翻天了,搜索了一下,什么可用信息都没有。

        于是写个測试project測试了一下。分别在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);

        然后開始怒跟代码,发现project中使用了一个自己定义控件,是为了实现一个富文本框的功能。

    所谓富文本框就是能显示各种颜色,能显示url,有的东西还能点的那种。可是这个东西的实现,当中有一步。是把一个utf8字符串拆开,拆成单个字符,把每一个字符的纹理做出来。然后来拼图,拼成一个文本框。那么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, 
                                   int             nWidth/* = 0*/, 
                                   int             nHeight/* = 0*/,
                                   ETextAlign      eAlignMask/* = kAlignCenter*/,
                                   const char *    pFontName/* = nil*/,
                                   int             nSize/* = 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上面会被自己主动忽略

    立即再写个project測试:

        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会不会被忽略呢,果断开个project再測试,例如以下:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
            <TextView
            android: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。
  • 相关阅读:
    mysql 迁移
    ubuntu 安装 mysql
    Ubuntu 常用命令
    ubuntu 安装 redis
    Ubuntu 文件移动
    题解 [NOI2014] 动物园
    项目管理实践【四】Bug跟踪管理【Bug Trace and Management】
    项目管理实践【五】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website automatically】
    项目管理实践【三】每日构建【Daily Build Using CruiseControl.NET and MSBuild】
    SQL Server修改表结构后批量更新所有视图
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6889503.html
Copyright © 2011-2022 走看看