cocos2dx windows phone平台下CCLabelTTF自动换行的实现

先吐个槽,刚准备发这条博客的时候居然发现账号被盗了,真是有人闲得蛋疼,顺便赞一个csdn的客服,处理的很快。


好了,言归正转。看了一下,自动换行的实现在CCFreeType这个类里,这个类的实现只是针对英文的,它采用空格断句的方式来进行操作,一个word一个word的加,如果发现超过规定的范围就会换行,但是对于中文来说,这个实现简直弱爆了,所以就会出现不能自动换行的情况。参考它的实现,做一点小的修改,基本原理如下

1、读一行文本出来,参考它的实现,算出这个文本的宽度

2、如果这个宽度没有超过,则直接显示

3、如果这个宽度走过了,则按等宽字体处理,根据宽度算出来总共应该是几行,然后按长度进行分隔换行。

注意这个实现有几个问题:

1、性能问题,其实是在计算出了所有的字之后才发现超过了,这个本来可以发现的更早,但是为了尽可能利用原有的代码结构,只用先这样了。

2、是以等宽字体的实现的,这个不一定正确,所以可能会出现某一些还是超过了的情况。


最后附上修改的diff,我使用的是2.2.4版本。

diff --git a/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.cpp b/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.cpp
index 9886d0a..46489af 100644
--- a/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.cpp
+++ b/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.cpp
@@ -368,13 +368,67 @@ FT_Error CCFreeTypeFont::addWord(const std::string& word)
     return error;
 }
 
+FT_Error CCFreeTypeFont::addLine(wchar_t* line, int size, bool wrap)
+{
+       std::vector<TGlyph> glyphs; // glyphs for the word
+       FT_BBox             bbox;   // bounding box containing all of the glyphs in the word
+       int maxWidth = m_inWidth ? m_inWidth : m_windowWidth;
+
+       FT_Vector pen = m_currentLine->pen;
+       FT_Error error = initWordGlyphs(glyphs, line, size, pen);
+       if (!error)
+       {
+               compute_bbox(glyphs, &bbox);
+               if (!wrap || bbox.xMax <= maxWidth)
+               {
+                       m_currentLine->pen = pen;
+                       m_currentLine->glyphs.insert(m_currentLine->glyphs.end(), glyphs.begin(), glyphs.end());
+                       if (m_currentLine->width == 0)
+                       {
+                               m_currentLine->bbox = bbox;
+                       }
+                       else
+                       {
+                               m_currentLine->bbox.xMax = bbox.xMax;
+                       }
+                       m_currentLine->width = m_currentLine->bbox.xMax - m_currentLine->bbox.xMin;
+               }
+               else
+               {
+                       int width = bbox.xMax;
+                       int lines = width / maxWidth + 1;
+                       float fline = float(width) / float(maxWidth);
+                       int lineWidth = int(size / fline);
+                       int offset = 0;
+                       for (int i = 0; i < lines; i++)
+                       {
+                               if (i)
+                               {
+                                       newLine();
+                               }
+                               wchar_t* buffer = line + offset;
+                               int buffer_len = size - offset;
+                               if (buffer_len > lineWidth)
+                               {
+                                       buffer_len = lineWidth;
+                               }
+                               offset += buffer_len;
+                               addLine(buffer, buffer_len, false);
+                               if (i < lines - 1)
+                               {
+                                       endLine();
+                               }
+                       }
+               }
+       }
+       return error;
+}
+
 FT_Error CCFreeTypeFont::initGlyphs(const char* text) 
 {
     FT_Error error = 0;
     std::stringstream stringStream(text);
     std::string line;
-    vector<std::string> lines;
-    vector<std::string> words;
 
     m_textWidth = 0;
     m_textHeight = 0;
@@ -387,19 +441,21 @@ FT_Error CCFreeTypeFont::initGlyphs(const char* text)
     {
         newLine();
 
-        std::size_t prev = 0, pos;
-        while ((pos = line.find_first_of(" ", prev)) != std::string::npos)
-        {
-            if (pos > prev)
-            {
-                addWord(line.substr(prev, pos-prev));
-            }
-            prev = pos + 1;
-        }
-        if (prev < line.length())
-        {
-            addWord(line.substr(prev, std::string::npos));
-        }
+               wchar_t *       pwszBuffer = nullptr;
+
+               int num_chars = line.size();
+               int nBufLen = num_chars + 1;
+               pwszBuffer = new wchar_t[nBufLen];
+               if (!pwszBuffer)
+               {
+                       return -1;
+               }
+
+               memset(pwszBuffer, 0, nBufLen);
+               num_chars = MultiByteToWideChar(CP_UTF8, 0, line.c_str(), num_chars, pwszBuffer, nBufLen);
+               pwszBuffer[num_chars] = '\0';
+               error = addLine(pwszBuffer, num_chars, true);
+               CC_SAFE_DELETE_ARRAY(pwszBuffer);
         endLine();
     }
 
@@ -513,6 +569,64 @@ FT_Error CCFreeTypeFont::initWordGlyphs(std::vector<TGlyph>& glyphs, const std::
        return error;
 }
 
+FT_Error CCFreeTypeFont::initWordGlyphs(std::vector<TGlyph>& glyphs, wchar_t* word, int size, FT_Vector& pen)
+{
+       FT_GlyphSlot    slot = m_face->glyph;
+       FT_UInt                 glyph_index;
+       FT_UInt                 previous = 0;
+       FT_Error                error = 0;
+       PGlyph                  glyph;
+       unsigned int    numGlyphs = 0;
+
+       glyphs.clear();
+       glyphs.resize(size);
+       FT_Bool useKerning = FT_HAS_KERNING(m_face);
+
+       for (int n = 0; n < size; n++)
+       {
+               glyph = &glyphs[numGlyphs];
+
+               /* convert character code to glyph index */
+               FT_ULong c = word[n];
+               glyph_index = FT_Get_Char_Index(m_face, c);
+
+               if (useKerning && previous && glyph_index)
+               {
+                       FT_Vector  delta;
+                       FT_Get_Kerning(m_face, previous, glyph_index,
+                               FT_KERNING_DEFAULT, &delta);
+                       pen.x += delta.x >> 6;
+               }
+
+               /* store current pen position */
+               glyph->pos = pen;
+               glyph->index = glyph_index;
+
+               /* load glyph image into the slot without rendering */
+               error = FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT);
+               if (error)
+                       continue;  /* ignore errors, jump to next glyph */
+
+               /* extract glyph image and store it in our table */
+               error = FT_Get_Glyph(m_face->glyph, &glyph->image);
+               if (error)
+                       continue;  /* ignore errors, jump to next glyph */
+
+               /* translate the glyph image now */
+               FT_Glyph_Transform(glyph->image, 0, &glyph->pos);
+
+               /* increment pen position */
+               pen.x += slot->advance.x >> 6;
+
+               /* record current glyph index */
+               previous = glyph_index;
+
+               numGlyphs++;
+       }
+
+       return error;
+}
+
 void  CCFreeTypeFont::compute_bbox(std::vector<TGlyph>& glyphs, FT_BBox  *abbox)
 {
     FT_BBox bbox;
diff --git a/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.h b/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.h
index 4c1cc3e..a325071 100644
--- a/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.h
+++ b/cocos2d-x-2.2.4/cocos2dx/platform/winrt/CCFreeTypeFont.h
@@ -100,6 +100,7 @@ private:
 
     FT_Error CCFreeTypeFont::initGlyphs(const char* text);
     FT_Error CCFreeTypeFont::initWordGlyphs(std::vector<TGlyph>& glyphs, const std::string& text, FT_Vector& pen);
+       FT_Error CCFreeTypeFont::initWordGlyphs(std::vector<TGlyph>& glyphs, wchar_t* word, int size, FT_Vector& pen);
 
        void compute_bbox(std::vector<TGlyph>& glyphs, FT_BBox  *abbox);
 
@@ -114,6 +115,7 @@ private:
     FT_Vector getPenForAlignment(FTLineInfo* pInfo, CCImage::ETextAlign eAlignMask, int lineNumber, int totalLines);
 
     FT_Error addWord(const std::string& word);
+       FT_Error addLine(wchar_t* line, int size, bool wrap);
     void newLine();
     void endLine();


你可能感兴趣的:(cocos2dx windows phone平台下CCLabelTTF自动换行的实现)