// KTextParser.cpp: implementation of the KTextParser class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "KTextParser.h" #include "KTextRender.h" #include #ifdef _COUNTRY_TL_ #include "./Localization/Thailand.h" #endif #ifdef _COUNTRY_ME_ #include "./Localization/MiddleEast.h" KTextParser::StringTableHandler* KTextParser::s_pStringTableHandler; KTextParser::mapEmoticon KTextParser::s_mapEmoticonFilter; #endif //#include "KNDBManager.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// bool KTextParser::s_bUseWordWrap = false; KTextParser::KTextParser() { m_dwCurrentLineWidth = 0; #ifndef _COUNTRY_ME_ m_CurrentTP.Init(); #endif m_dwHAlign = KTextRender::KTALIGN_HCENTER;m_dwVAlign = KTextRender::KTALIGN_VCENTER; m_bEditMode = false; } KTextParser::~KTextParser() { Clear(); } // 2010.06.08 - prodongi int KTextParser::AddString(LPCSTR lpszString, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit, bool scroll ) //int KTextParser::AddString(LPCSTR lpszString, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit) { #ifdef _COUNTRY_TL_ //태국에서 준 워드 브레이크 버그 문자열 //첫번째 태그를 넘겨 주는 버그가 있음 //2009-05-19 : hunee //LPCSTR PPP = "睾納죵芽羽밝杆췬↕瓮擡ℓ紀"; //lpszString = PPP; // 왠지 영문자와 숫자만으로 구성된 작은스트링들은 설정된 폭이 너무 작아서 이 루틴에서 짤려버리는 일이 많다. // 따라서 따로 체크해서 기존루틴으로 처리. if (LocalizationTL::isOnlyEnglishWord(lpszString)) { // 2010.06.15 - prodongi //_AddString(lpszString, 0, dwMaxWidth, bTagEnable, bUseSplit); _AddString(lpszString, 0, dwMaxWidth, bTagEnable, bUseSplit, scroll); return (int)m_vtTextPrimitive.size(); } // 여기부터 복잡한 루틴이 들어갑니다. /// 태그가 덕지덕지 붙은 스트링을 태그 다 떼고 잘라내서 순수 텍스트만 가지고 wordbreak를 건 후 /// 도로 태그를 원래 위치에 붙이는 무식한 코드 by 정동섭 TEXT_TOKEN token; std::string fontName = ""; int fontSize = -1; int nCount = 0; while(1) { _GetNextToken(&token, lpszString, nCount); if (token.dwType == TEXT_TOKEN::EOS) break; if (token.dwType == TEXT_TOKEN::FONT) fontName = token.sText; else if (token.dwType == TEXT_TOKEN::SIZE) fontSize = token.dwFontSize; } // 일단 이 string이 어떤 폰트와 어떤 크기로 찍히는 것인지를 살펴본다. // string 내부에서 폰트와 크기가 여러번 변하는 놈이면 골룸 // 일단 한 스트링 안에서는 폰트, 크기가 처음부터 끝까지 일정하다고 가정하고 코딩 DWORD thaiAlphabetWidth = 0, thaiAlphabetHeight = 0; if (fontName == "") fontName = m_CurrentTP.sFontName.c_str(); if (fontSize == -1) fontSize = m_CurrentTP.nFontSize; std::vector strLines; nCount = 0; while(1) // 이 루프에서는
단위로 스트링을 잘라낸다. { //
이 걸려있는 놈은 어차피 강제로 줄바꿈이 되는 놈일 테니 이놈들 단위로 잘라서 그 사이사이만 워드브레이킹 처리 strLines.push_back(""); while(1) { _GetNextToken(&token, lpszString, nCount); // _GetNextToken(&token, test.c_str(), nCount); if (token.dwType == TEXT_TOKEN::EOS || token.dwType == TEXT_TOKEN::BREAK) break; if (token.dwType == TEXT_TOKEN::TEXT) strLines.back() += token.sText; else strLines.back() += token.sTokenText; // < > 을 포함한 태그 전체 문자열이 sTokenText에 들어간다. } if (token.dwType == TEXT_TOKEN::EOS) break; } std::string strResult; // 이 변수에 최종결과가 들어간다. for (int i=0; i 기준으로 잘라진 문자열 각각을 처리 { int tagCount = 0; std::vector tagVector; std::vector tagPosition; std::string strText; while(1) // 이 루프에서 태그와 순수문자열을 분리한다. { int nowPos = tagCount; _GetNextToken(&token, strLines[i].c_str(), tagCount); if (token.dwType == TEXT_TOKEN::EOS) break; if (token.dwType == TEXT_TOKEN::TEXT) strText += token.sText; else { tagPosition.push_back(nowPos); tagVector.push_back(token.sTokenText); } } // 이제 tagvector에는 tag들이, strText에는 남겨진 스트링만 있다. std::string strBreaked; while(1) { const char* p = strText.c_str(); std::string sLine, sTmp; int nCharCount = 0; for (; *p != 0; ) { nCharCount++; DWORD nWidth = 0, nHeight = 15; char nowChar[10] = {0, }; const char* p1 = LocalizationTL::CharNextTh(p); memcpy(nowChar, p, p1-p); p = p1; sLine += nowChar; // 이 스트링이 쓰여질 말칸에 주어진 스트링의 첫부분부터 세어서 몇글자나 들어갈지 체크하는 부분 // 여기까지 초 무식한 코드로 문자열 시작지점에서부터 1글자씩 증가시켜 나가면서 // 계속 부분 문자열 너비를 구해서 말칸의 너비를 초과하는 시점을 찾는다. // 가변폭 폰트이기때문에 이럴 수 밖에 없었다. KTextRender::GetStringSize(fontName.c_str(), fontSize, false, sLine.c_str(),(int)sLine.size(),&nWidth, &nHeight); if (nWidth > dwMaxWidth) { LocalizationTL::g_TEWordBreak.n_ch = nCharCount-2; // 왜인지 정확히 모르겠는데 1글자 오버하는 경우가.. sTmp = LocalizationTL::g_TEWordBreak.BreakString(strText.c_str()); // 태국어 워드브레이킹을 건다. break; } } if (*p == 0) { // 이리로 빠졌으면 문자열 끝까지 돌았지만 말칸 너비를 초과 안 한 경우 strBreaked += strText; // 이 경우엔 워드브레이킹 필요 없음 break; } int nBR = sTmp.find(""); // 워드브레이킹 결과를 찾는다. while (nBR == 0) { sTmp = sTmp.substr(4); nBR = sTmp.find(""); } if (nBR == std::string::npos) { // 워드브레이킹을 걸었지만 줄바꿈이 안 되었을 경우 strBreaked += sTmp; // 더이상의 처리 필요 없음 break; } else { // 줄바꿈이 되었을 경우 strBreaked += sTmp.substr(0, nBR); // 첫줄만 떼넨다. strBreaked += ""; strText = strText.substr(nBR); // 나머지 부분을 가지고 처음부터 반복 } // 문자열이 다르면 한줄에 들어갈 글자수가 달라지기 때문에 처음부터 다시 세어야 함 (이놈의 가변폭 폰트..) } int BRcount = 0; std::vector BRPosition; while(1) { _GetNextToken(&token, strBreaked.c_str(), BRcount); if (token.dwType == TEXT_TOKEN::EOS) break; if (token.dwType == TEXT_TOKEN::BREAK) BRPosition.push_back(BRcount-4); } // 이제 새로 생긴
이 어디 붙어있는지 모두 체크했다. // 이제 도로 tag들을 원래 위치에 끼워 넣자 for (int j=0; j 이 몇개나 있냐? for (int k=0; k tagPosition[j] + (prevBR * 4)) break; // 이 태그 앞에 가 몇개나 있나 올바르게 찾으려면 태그 위치에 prevBR++; // 그 앞에 가 삽입되어서 밀려난 거리를 더해준 거리까지 감안해야 한다. } pos += (prevBR * 4); // tag 앞에 워드브레이킹때문에 새로 생긴
의 갯수*4만큼 tag의 위치를 뒤로 밀어야 제 위치로 들어간다..
이 4글자니까 strBreaked.insert(pos, tagVector[j]); // 삽입된 tag의 길이만큼 그 tag 뒤에 있는 BR의 위치를 뒤로 밀어줘야 나중에 계산이 맞는다.. for (int k=0; k tagPosition[j]) { BRPosition[k] += tagVector[j].length(); } } } strResult += strBreaked; // 모두 됐으면 원래 문자열을 만든다. if (i < strLines.size()-1) //
태그도 알맞게 넣어 준다. strResult += "
"; } // 2010.06.08 - prodongi _AddString(strResult.c_str(), 0, dwMaxWidth, bTagEnable, bUseSplit, scroll); //_AddString(strResult.c_str(), 0, dwMaxWidth, bTagEnable, bUseSplit); #else // 2010.06.08 - prodongi _AddString(lpszString, 0, dwMaxWidth, bTagEnable, bUseSplit, scroll ); //_AddString(lpszString, 0, dwMaxWidth, bTagEnable, bUseSplit); #endif #ifdef _COUNTRY_ME_ return (int)m_vtTextParagraph.size(); #else return (int)m_vtTextPrimitive.size(); #endif } //#define _OLD_WORD_WRAP_ #ifdef _OLD_WORD_WRAP_ // 2010.06.08 - prodongi void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit, bool scroll) //void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit) { int nCount = 0; BOOL bLoop = TRUE; while ( bLoop) { m_CurrentTP.dwCount = nCount; TEXT_TOKEN token; if(!bTagEnable) { token.sText = lpszString; token.dwType = TEXT_TOKEN::TEXT; } else { _GetNextToken(&token, lpszString, nCount); } switch(token.dwType) { case TEXT_TOKEN::TEXT: { // 줄바꿈이 있을때만 따로 리스트에 저장 if(m_CurrentTP.nBreak > 0 || m_CurrentTP.nPageBreak > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.sText.erase(); m_CurrentTP.dwOffset = 0; m_CurrentTP.nBreak = m_CurrentTP.nPageBreak = 0; //줄바꿈 초기화 m_CurrentTP.bIsLineBreak = false; } // 텍스트가 있으면 if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.sText += token.sText; BOOL bBold = m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD; //BOLD 검사 DWORD dwStrWidth = 0, dwStrHeight = 0; //문자열 가로,세로 얻기 /*KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size(),&dwStrWidth, &dwStrHeight);*/ std::string strTemp = m_CurrentTP.sText; KTextRender::GetEmoticonFilterText( strTemp ); //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, &dwStrHeight); } else { KTextRender::GetStringSize( "default", m_CurrentTP.nFontSize, bBold, strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, &dwStrHeight); } //현재 라인 가로 크기에 스트링 가로 크기 더하기 m_dwCurrentLineWidth += dwStrWidth; // 한줄을 넘기게 되면 linebreak를 걸어주자 if( m_dwCurrentLineWidth > dwMaxWidth) { //더해진 가로 크기에 스트링 가로 크기 다시 빼기 m_dwCurrentLineWidth -= dwStrWidth; // 추가된 Primitive를 Line size로 자르자. while (1) { int nBackLast_Space = 0; int nOldLast_Space = 0; int nLast_Space = 0; int nMaxStr = 0; DWORD dwWidth = 0, dwHeight = 0; char * psz1 = const_cast(m_CurrentTP.sText.c_str()); char * psz2 = psz1; char * last_space = NULL; char * Oldlast_space = NULL; char * Backlast_space = NULL; // dwMaxWidth에 걸맞는 Size를 찾자. int nWordSize = 0 ; while(1) { if( !(*psz1) ) break; psz2 = CharNext(psz1); nMaxStr++; if( (psz2 - psz1) == 2) { // 한 글자가 2byte 인 경우 (ex: 한글) nMaxStr++; nBackLast_Space = nOldLast_Space; Backlast_space = Oldlast_space; //이전 ' ' nOldLast_Space = nLast_Space; Oldlast_space = last_space; last_space = psz2+1; //' '의 다음문자 지정 nLast_Space = nMaxStr; //' '까지의 길이 } if( *psz2 == ' ' ) { nBackLast_Space = nOldLast_Space; Backlast_space = Oldlast_space; //이전 ' ' nOldLast_Space = nLast_Space; Oldlast_space = last_space; last_space = psz2+1; //' '의 다음문자 지정 nLast_Space = nMaxStr; //' '까지의 길이 } nWordSize++; //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); } // 문자 하나의 size가 maxwidth를 넘는 경우 그냥 하나 단위로 짜름 if(nWordSize == 1 && dwWidth > dwMaxWidth) break; // 바로 전 글자까지만 짜르면 된다. if(m_dwCurrentLineWidth + dwWidth > dwMaxWidth) { // 이경우 2byte중 1byte만 남게 된 경우므로 // 아예 2byte를 다 잘라 버린다. nMaxStr -= int(psz2 - psz1); //위치가 앞으로 이동 된 경우 if( nMaxStr < nLast_Space ) { if( nOldLast_Space == nLast_Space ) { //이전 ' ' 으로 복구 nLast_Space = nBackLast_Space; last_space = Backlast_space; } else { //이전 ' ' 으로 복구 nLast_Space = nOldLast_Space; last_space = Oldlast_space; } } break; } psz1 = psz2; } // 이미 한줄이 꽉찬 상태에서 새로 Text가 추가 되면 // 그냥 줄바꿈만 해주고 다시 계산해 준다. if(nMaxStr == 0) { if(m_vtTextPrimitive.size() > 0) m_vtTextPrimitive.back().bIsLineBreak = true; //줄바꿈 설정 m_dwCurrentLineWidth = 0; //땜방, sFontName 값이 없다. // 다시 줄의 넓이를 계산한다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), m_CurrentTP.sText.length() , &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), m_CurrentTP.sText.length() , &dwWidth, &dwHeight); } // 만약 한줄에 다 들어가면 Loop 탈출 if(dwWidth < dwMaxWidth) { m_dwCurrentLineWidth = dwWidth; break; } // 그게 아니면 다시 계산 else continue; } std::string s; // 자른후에 사용할 string 저장 int nCutSize = nMaxStr; if( s_bUseWordWrap ) { //크기가 모자람 if( nMaxStr < nLast_Space ) { if( nOldLast_Space == nLast_Space ) { //이전 ' ' 으로 복구 nLast_Space = nBackLast_Space; } else { //이전 ' ' 으로 복구 nLast_Space = nOldLast_Space; } } if( nLast_Space != 0 ) nCutSize = nLast_Space; } s = m_CurrentTP.sText.c_str() + nCutSize; // _performance_print( "백업 %s\n", s.c_str() ); // 다음행의 시작 스페이스는 날린다 while( nMaxStr && !s.empty() && s[0] == ' ' ) s.erase( 0, 1 ); m_CurrentTP.sText.resize(nCutSize); //크기 재설정 m_CurrentTP.bIsLineBreak = true; //줄바꿈 설정 m_vtTextPrimitive.push_back(m_CurrentTP); // _performance_print( "저장 %s\n", m_CurrentTP.sText.c_str() ); //새로 시작 m_CurrentTP.dwOffset = 0; m_CurrentTP.bIsLineBreak = false; m_CurrentTP.sText = s; //복구 //땜방 // 남은 string이 한줄을 넘지 않는다면 loop 를 탈출!! if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } m_dwCurrentLineWidth = 0; if(dwWidth <= dwMaxWidth) { // 현재남은 Line의 길이를 기억해야 한다. m_dwCurrentLineWidth = dwWidth; break; } } } if(!bTagEnable) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); m_dwCurrentLineWidth = 0; return; } } break; case TEXT_TOKEN::TEXTCMD: _AddString(token.sText.c_str(), nDepth + 1, dwMaxWidth,bTagEnable,bUseSplit); break; case TEXT_TOKEN::FONT: // Font의 종류가 다르면 if(m_CurrentTP.sFontName != token.sText) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.sFontName = token.sText; KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); } break; case TEXT_TOKEN::SIZE: if(m_CurrentTP.nFontSize != (int)token.dwFontSize) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.nFontSize = token.dwFontSize; KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); } break; case TEXT_TOKEN::OFFSET: { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.sText.erase(); } m_CurrentTP.dwOffset = token.dwOffset; } break; case TEXT_TOKEN::COLOR: // Color가 다르면 if(m_CurrentTP.Color.color != token.dwColor ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.Color = token.dwColor; } break; case TEXT_TOKEN::BOLD: if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD)) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Bold bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_BOLD; } break; case TEXT_TOKEN::UNBOLD: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Bold bit Clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_BOLD; } break; case TEXT_TOKEN::UNDER_LINE: if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER)) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Underline bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_UNDER; } break; case TEXT_TOKEN::UNDER_LINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Underline bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_UNDER; } break; case TEXT_TOKEN::STRIKE_LINE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_STRIKE; } break; case TEXT_TOKEN::STRIKE_LINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_STRIKE; } break; case TEXT_TOKEN::SHADOW: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_SHADOW; } break; case TEXT_TOKEN::SHADOWOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_SHADOW; } break; case TEXT_TOKEN::OUTLINE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_OUTLINE; } break; case TEXT_TOKEN::OUTLINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_OUTLINE; } break; case TEXT_TOKEN::GLOW: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW; } break; case TEXT_TOKEN::GLOWOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW; } break; case TEXT_TOKEN::COLOR_FX: { if(m_CurrentTP.ColorFX.color != token.dwColor ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.ColorFX = token.dwColor; } } break; case TEXT_TOKEN::GLOW2X: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW2X; } break; case TEXT_TOKEN::GLOW2XOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW2X; } break; case TEXT_TOKEN::INVERSE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_INVERSE; } break; case TEXT_TOKEN::INVERSE_OFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_INVERSE; } break; case TEXT_TOKEN::BREAK: m_CurrentTP.nBreak++; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.nBreak = 0; m_CurrentTP.sText.erase(); m_CurrentTP.dwOffset = 0; m_dwCurrentLineWidth = 0; break; case TEXT_TOKEN::PAGEBREAK: m_CurrentTP.nPageBreak++; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.nPageBreak = 0; m_CurrentTP.sText.erase(); m_CurrentTP.dwOffset = 0; m_dwCurrentLineWidth = 0; break; case TEXT_TOKEN::EMOTICON: case TEXT_TOKEN::NX3: { // Icon의 크기는 기본적으로 현재 Font Size의 2배 m_dwCurrentLineWidth += m_CurrentTP.nFontSize * 2; if(m_CurrentTP.sText.size() > 0) { // 줄을 넘어가면 줄바꿈을 해주자 if(m_dwCurrentLineWidth > dwMaxWidth) { m_CurrentTP.bIsLineBreak = true; m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; } m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.bIsLineBreak = false; m_CurrentTP.sText.erase(); } // 그 전에 Text아닌 다른걸 넣었다면 else if(m_vtTextPrimitive.size() > 0 && m_vtTextPrimitive.back().dwIconType != KICON_TEXT) { // 줄을 넘어가면 줄바꿈을 해주자 if(m_dwCurrentLineWidth > dwMaxWidth) { m_vtTextPrimitive.back().bIsLineBreak = true; m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; } } // 한줄의 크기가 Icon보다 작은 경우는 전혀 고려하지 않았다 m_CurrentTP.dwIconType = token.dwType - TEXT_TOKEN::EMOTICON + KICON_EMOTICON; m_CurrentTP.dwIconID = token.dwIconID; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.dwIconType = KICON_TEXT; break; } case TEXT_TOKEN::HALIGN: m_dwHAlign = token.dwAlign; break; case TEXT_TOKEN::VALIGN: m_dwVAlign = token.dwAlign; break; // End Of String case TEXT_TOKEN::EOS: if(nDepth == 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_dwCurrentLineWidth = 0; m_CurrentTP.Init(); } bLoop = FALSE; break; default: break; } } } #else #ifndef _COUNTRY_ME_ //// 2010.06.08 - prodongi //void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit, bool scroll, bool bUseSplitOffset/*false*/) ////void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit) //{ // int nCount = 0; // BOOL bLoop = TRUE; // // // 텍스트의 중간중간에 섞인 태그를 보관. bintitle. 2010.09.29. // std::string strOldToken, strOldText, strOldTokenLineBreak; // // while ( bLoop) // { // m_CurrentTP.dwCount = nCount; // TEXT_TOKEN token; // token.dwType = TEXT_TOKEN::NONE; // // if(!bTagEnable) // { // token.sText = lpszString; // token.dwType = TEXT_TOKEN::TEXT; // } // else // { // _GetNextToken(&token, lpszString, nCount); // } // // // 텍스트의 중간중간에 섞인 태그를 보관. bintitle. 2010.09.29. // if( bUseSplitOffset && !strOldText.empty() && token.dwType != TEXT_TOKEN::NONE && token.dwType != TEXT_TOKEN::TEXT && // !token.sTokenText.empty() && token.sTokenText != strOldToken ) // { // strOldTokenLineBreak = strOldToken = token.sTokenText; // strOldText.erase(); // } // // switch(token.dwType) // { // case TEXT_TOKEN::TEXT: // { // // 줄바꿈이 있을때만 따로 리스트에 저장 // if(m_CurrentTP.nBreak > 0 || m_CurrentTP.nPageBreak > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.sText.erase(); // m_CurrentTP.nBreak = m_CurrentTP.nPageBreak = 0; //줄바꿈 초기화 // m_CurrentTP.bIsLineBreak = false; // } // // 텍스트가 있으면 // if(m_CurrentTP.sText.size() > 0) // { // std::string s; // s = lpszString+nCount; // if( !s.empty() && s[0] != ' ' ) // m_CurrentTP.bContinue = true; // // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.bContinue = false; // m_CurrentTP.sText.erase(); // } // if (token.sText.find("") != std::string::npos) // { // int xxxx=1; // } // // // 보관한 태그를 끼워넣기. bintitle. 2010.29. // if( bUseSplitOffset && !strOldToken.empty() && !token.sText.empty() && m_vtTextPrimitive.size() > 0 ) // { // m_CurrentTP.sText += strOldToken + token.sText; // strOldToken.erase(); // } // else // { // m_CurrentTP.sText += token.sText; // strOldText = token.sText; // } // // // 이전. // //m_CurrentTP.sText += token.sText; // // BOOL bBold = m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD; //BOLD 검사 // DWORD dwStrWidth = 0, dwStrHeight = 0; // // //문자열 가로,세로 얻기 // /*KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size(),&dwStrWidth, // // &dwStrHeight);*/ // std::string strTemp = m_CurrentTP.sText; // KTextRender::GetEmoticonFilterText( strTemp ); // // //땜방, sFontName 값이 없다. // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, // // &dwStrHeight); // } // else // { // KTextRender::GetStringSize( "default", m_CurrentTP.nFontSize, bBold, // strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, &dwStrHeight); // } // // //현재 라인 가로 크기에 스트링 가로 크기 더하기 // m_dwCurrentLineWidth += dwStrWidth; // // // 한줄을 넘기게 되면 linebreak를 걸어주자 // // 2010.06.03 - prodongi // if( !scroll && (m_dwCurrentLineWidth > dwMaxWidth)) // //if( m_dwCurrentLineWidth > dwMaxWidth) // { // //더해진 가로 크기에 스트링 가로 크기 다시 빼기 // m_dwCurrentLineWidth -= dwStrWidth; // // // 추가된 Primitive를 Line size로 자르자. // while (1) // { // int nBackLast_Space = 0; // int nOldLast_Space = 0; // int nLast_Space = 0; // int nMaxStr = 0; // DWORD dwWidth = 0, dwHeight = 0; // // char * psz1 = const_cast(m_CurrentTP.sText.c_str()); // char * psz2 = psz1; // char * last_space = NULL; // char * Oldlast_space = NULL; // char * Backlast_space = NULL; // // // // dwMaxWidth에 걸맞는 Size를 찾자. // int nWordSize = 0 ; // while(1) // { // if( !(*psz1) ) break; // psz2 = CharNext(psz1); // nMaxStr++; // // if( (psz2 - psz1) == 2) // { // // 한 글자가 2byte 인 경우 (ex: 한글) // nMaxStr++; // // nBackLast_Space = nOldLast_Space; // Backlast_space = Oldlast_space; // // //이전 ' ' // nOldLast_Space = nLast_Space; // Oldlast_space = last_space; // // last_space = psz2+1; //' '의 다음문자 지정 // nLast_Space = nMaxStr; //' '까지의 길이 // } // // if( *psz2 == ' ' ) // { // nBackLast_Space = nOldLast_Space; // Backlast_space = Oldlast_space; // // //이전 ' ' // nOldLast_Space = nLast_Space; // Oldlast_space = last_space; // // last_space = psz2+1; //' '의 다음문자 지정 // nLast_Space = nMaxStr; //' '까지의 길이 // } // // nWordSize++; // // //땜방, sFontName 값이 없다. // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); // } // else // { // KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); // } // // // 문자 하나의 size가 maxwidth를 넘는 경우 그냥 하나 단위로 짜름 // if(nWordSize == 1 && dwWidth > dwMaxWidth) // break; // // // 바로 전 글자까지만 짜르면 된다. // if(m_dwCurrentLineWidth + dwWidth > dwMaxWidth) // { // // 이경우 2byte중 1byte만 남게 된 경우므로 // // 아예 2byte를 다 잘라 버린다. // nMaxStr -= int(psz2 - psz1); // // //위치가 앞으로 이동 된 경우 // if( nMaxStr < nLast_Space ) // { // if( nOldLast_Space == nLast_Space ) // { // //이전 ' ' 으로 복구 // nLast_Space = nBackLast_Space; // last_space = Backlast_space; // } // else // { // //이전 ' ' 으로 복구 // nLast_Space = nOldLast_Space; // last_space = Oldlast_space; // } // } // // break; // } // psz1 = psz2; // } // // // 이미 한줄이 꽉찬 상태에서 새로 Text가 추가 되면 // // 그냥 줄바꿈만 해주고 다시 계산해 준다. // if(nMaxStr == 0) // { // if(m_vtTextPrimitive.size() > 0) // m_vtTextPrimitive.back().bIsLineBreak = true; //줄바꿈 설정 // // m_dwCurrentLineWidth = 0; // // //땜방, sFontName 값이 없다. // // 다시 줄의 넓이를 계산한다. // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(),m_CurrentTP.sText.length() , &dwWidth, &dwHeight); // } // else // { // KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(),m_CurrentTP.sText.length() , &dwWidth, &dwHeight); // } // // // 만약 한줄에 다 들어가면 Loop 탈출 // if(dwWidth < dwMaxWidth) // { // m_dwCurrentLineWidth = dwWidth; // break; // } // // 그게 아니면 다시 계산 // else // continue; // } // // std::string s; // // // 자른후에 사용할 string 저장 // int nCutSize = nMaxStr; // // if( s_bUseWordWrap ) // { // //크기가 모자람 // if( nMaxStr < nLast_Space ) // { // if( nOldLast_Space == nLast_Space ) // { // //이전 ' ' 으로 복구 // nLast_Space = nBackLast_Space; // } // else // { // //이전 ' ' 으로 복구 // nLast_Space = nOldLast_Space; // } // } // // if( nLast_Space != 0 ) // nCutSize = nLast_Space; // } // // s = m_CurrentTP.sText.c_str() + nCutSize; // // // _performance_print( "백업 %s\n", s.c_str() ); // // // 다음행의 시작 스페이스는 날린다 // while( nMaxStr && !s.empty() && s[0] == ' ' ) s.erase( 0, 1 ); // // m_CurrentTP.sText.resize(nCutSize); //크기 재설정 // m_CurrentTP.bIsLineBreak = true; //줄바꿈 설정 // // if( s_bUseWordWrap ) // { // //땜방, sFontName 값이 없다. // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(), nCutSize, &dwWidth, &dwHeight); // } // else // { // KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(), nCutSize, &dwWidth, &dwHeight); // } // // if( dwWidth <= dwMaxWidth ) // { // if( nLast_Space != 0 && nMaxStr != nLast_Space ) // { // //Space 몇개 있는가? // std::vector vecText; // nsl::split( m_CurrentTP.sText.c_str(), vecText, " ", false ); // // if( vecText.size()>1 ) // { // std::string strText, strTemp; // DWORD checkWidth, checkHeight, accumWidth; // accumWidth = checkWidth = checkHeight = 0; // // std::vector vecTextWidthList; // // //단어들의 길이 계산 // for( unsigned int k(0); vecText.size()>k; k++ ) // { // //땜방, sFontName 값이 없다. // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), // // m_CurrentTP.nFontSize, bBold, // vecText[k].c_str(), vecText[k].length(), &checkWidth, // // &checkHeight); // } // else // { // KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, // // bBold, // vecText[k].c_str(), vecText[k].length(), &checkWidth, // // &checkHeight); // } // // vecTextWidthList.push_back( checkWidth ); // accumWidth += checkWidth; // } // // //여백 계산 // unsigned int nTotalBlankWidth = (dwMaxWidth-m_dwCurrentLineWidth)-(accumWidth); // // 1줄에 여러 개의 primitive가 들어갈 경우 첫 primitive가 아닌 2번째 이상의 primitive에서 줄바꿈이 일어날 경우 줄바꿈 될 텍스트를 좌우정렬하려는 과정에서 // // 이미 앞에 들어가 있던 문자의 길이를 무시하려 하기 때문에 무조건 0부터 끝까지 기준으로 좌우정렬하려고 해서 // // 이미 있던 글자와 겹쳐지는 문제가 발생한다. 그래서 어디서부터 끝까지 좌우맞춤을 할 것인지 확실하게 정하기 위해 (dwMaxWidth-m_dwCurrentLineWidth) 로 고침 // //Blank의 길이 계산 // unsigned int nBlankWidth = nTotalBlankWidth/(vecText.size()-1); // int accumWidthTemp = m_dwCurrentLineWidth; // accumWidth = 0; // // for( unsigned int k(0); vecText.size()>k; k++ ) // { // if( !bUseSplit ) // { // m_CurrentTP.dwOffset = accumWidth; // // //마지막 // if( k == vecText.size()-1 ) // m_CurrentTP.bIsLineBreak = true; // else // m_CurrentTP.bIsLineBreak = false; // // m_CurrentTP.sText = vecText[k].c_str(); // // if( nBlankWidth == nTotalBlankWidth ) // m_CurrentTP.nBlankWidth = 4; // else // m_CurrentTP.nBlankWidth = nBlankWidth; // // m_CurrentTP.bIsWordWrap = true; // m_vtTextPrimitive.push_back(m_CurrentTP); // } // else // { // if( k==0 ) // { // strText = vecText[k].c_str(); // } // else // { // strTemp = nsl::format( "%s", accumWidthTemp, vecText[k].c_str() ); // } // // strText += strTemp; // } // // accumWidth += vecTextWidthList[k]; //단어 // accumWidth += nBlankWidth; //Blank // accumWidthTemp += vecTextWidthList[k]; //단어 // accumWidthTemp += nBlankWidth; //Blank // // // // } // // if( bUseSplit ) // { // m_CurrentTP.bIsLineBreak = true; // m_CurrentTP.sText = strText; // m_vtTextPrimitive.push_back(m_CurrentTP); // } // // m_CurrentTP.nBlankWidth = 0; // m_CurrentTP.bIsWordWrap = false; // } // else // { // m_vtTextPrimitive.push_back(m_CurrentTP); // } // }//if( nLast_Space != 0 && nMaxStr != nLast_Space ) // else // { // m_vtTextPrimitive.push_back(m_CurrentTP); // } // }//if( dwWidth <= dwMaxWidth ) // else // { // m_vtTextPrimitive.push_back(m_CurrentTP); //// assert(0 && "if( dwWidth <= dwMaxWidth )" ); // } // }//if( s_bUseWordWrap ) // else // { // m_vtTextPrimitive.push_back(m_CurrentTP); // } // // //새로 시작 // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.bIsLineBreak = false; // m_CurrentTP.bIsWordWrap = false; // //m_CurrentTP.sText = s; //복구 // // // bintitle. 2010.09.29. 분할된 행에도 이전행의 <태그> 가 적용되어야 한다. // if( bUseSplitOffset ) // { // m_CurrentTP.sText = strOldTokenLineBreak + s; //복구 // strOldTokenLineBreak.erase(); // } // else // m_CurrentTP.sText = s; //복구 // // //땜방 // // 남은 string이 한줄을 넘지 않는다면 loop 를 탈출!! // // if( m_CurrentTP.sFontName.length() ) // { // KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); // } // else // { // KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, // m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); // } // // m_dwCurrentLineWidth = 0; // if(dwWidth <= dwMaxWidth) // { // // 현재남은 Line의 길이를 기억해야 한다. // m_dwCurrentLineWidth = dwWidth; // break; // } // } // } // // if(!bTagEnable) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.sText.erase(); // m_dwCurrentLineWidth = 0; // return; // } // } // break; // case TEXT_TOKEN::TEXTCMD: // // 2010.06.08 - prodongi // _AddString(token.sText.c_str(), nDepth + 1, dwMaxWidth, bTagEnable, bUseSplit, scroll); // //_AddString(token.sText.c_str(), nDepth + 1, dwMaxWidth, bTagEnable, bUseSplit); // break; // case TEXT_TOKEN::FONT: // // Font의 종류가 다르면 // if(m_CurrentTP.sFontName != token.sText) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.sText.erase(); // } // m_CurrentTP.sFontName = token.sText; // // KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); // } // break; // // case TEXT_TOKEN::SIZE: // if(m_CurrentTP.nFontSize != (int)token.dwFontSize) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_CurrentTP.sText.erase(); // } // m_CurrentTP.nFontSize = token.dwFontSize; // KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); // } // break; // case TEXT_TOKEN::OFFSET: // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.sText.erase(); // } // m_CurrentTP.dwOffset = token.dwOffset; // } // break; // // // 그려질 오브젝트 y 오프셋 추가 적용 // case TEXT_TOKEN::OFFSETY: // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.sText.erase(); // } // m_CurrentTP.nOffsetY = token.nOffsetY; // } // break; // // case TEXT_TOKEN::COLOR: // // Color가 다르면 // if(m_CurrentTP.Color.color != token.dwColor ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // m_CurrentTP.Color = token.dwColor; // } // break; // case TEXT_TOKEN::BOLD: // if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD)) // { // if(m_CurrentTP.sText.size() > 0) // { // std::string s; // s = lpszString+nCount; // if( !s.empty() && s[0] != ' ' ) // m_CurrentTP.bContinue = true; // // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.bContinue = false; // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // Bold bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_BOLD; // } // break; // case TEXT_TOKEN::UNBOLD: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD) // { // if(m_CurrentTP.sText.size() > 0) // { // std::string s; // s = lpszString+nCount; // if( !s.empty() && s[0] != ' ' ) // m_CurrentTP.bContinue = true; // // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.bContinue = false; // m_CurrentTP.sText.erase(); // } // // // Bold bit Clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_BOLD; // } // break; // case TEXT_TOKEN::UNDER_LINE: // if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER)) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // Underline bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_UNDER; // } // break; // case TEXT_TOKEN::UNDER_LINEOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // Underline bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_UNDER; // } // break; // case TEXT_TOKEN::STRIKE_LINE: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // strike bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_STRIKE; // } // break; // case TEXT_TOKEN::STRIKE_LINEOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // strike bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_STRIKE; // } // break; // case TEXT_TOKEN::SHADOW: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // strike bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_SHADOW; // } // break; // case TEXT_TOKEN::SHADOWOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // strike bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_SHADOW; // } // break; // case TEXT_TOKEN::OUTLINE: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_OUTLINE; // } // break; // case TEXT_TOKEN::OUTLINEOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_OUTLINE; // } // break; // case TEXT_TOKEN::GLOW: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW; // } // break; // case TEXT_TOKEN::GLOWOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW; // } // break; // case TEXT_TOKEN::COLOR_FX: // { // if(m_CurrentTP.ColorFX.color != token.dwColor ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // m_CurrentTP.ColorFX = token.dwColor; // } // } // break; // case TEXT_TOKEN::GLOW2X: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) ) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW2X; // } // break; // case TEXT_TOKEN::GLOW2XOFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) // { // if(m_CurrentTP.sText.size() > 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // bit clear // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW2X; // } // break; // case TEXT_TOKEN::INVERSE: // if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) ) // { // if(m_CurrentTP.sText.size() > 0) // { // std::string s; // s = lpszString+nCount; // if( !s.empty() && s[0] != ' ' ) // m_CurrentTP.bContinue = true; // // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.bContinue = false; // m_CurrentTP.dwOffset = 0; // m_CurrentTP.sText.erase(); // } // // // strike bit add // m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_INVERSE; // } // break; // case TEXT_TOKEN::INVERSE_OFF: // if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) // { // if(m_CurrentTP.sText.size() > 0) // { // std::string s; // s = lpszString+nCount; // if( !s.empty() && s[0] != ' ' ) // m_CurrentTP.bContinue = true; // // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.bContinue = false; // m_CurrentTP.sText.erase(); // } // // // strike bit add // m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_INVERSE; // } // break; // case TEXT_TOKEN::CARET: // // break; // // case TEXT_TOKEN::CARET_OFF: // // break; // // case TEXT_TOKEN::BREAK: // m_CurrentTP.nBreak++; // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.nBreak = 0; // m_CurrentTP.sText.erase(); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_dwCurrentLineWidth = 0; // if (token.sTokenText == "") // m_vtTextPrimitive.back().bIsLineBreak = true; // break; // case TEXT_TOKEN::PAGEBREAK: // m_CurrentTP.nPageBreak++; // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.nPageBreak = 0; // m_CurrentTP.sText.erase(); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_dwCurrentLineWidth = 0; // break; // case TEXT_TOKEN::EMOTICON: // case TEXT_TOKEN::NX3: // { // // Icon의 크기는 기본적으로 현재 Font Size의 2배 // m_dwCurrentLineWidth += m_CurrentTP.nFontSize * 2; // // if(m_CurrentTP.sText.size() > 0) // { // // 줄을 넘어가면 줄바꿈을 해주자 // if(m_dwCurrentLineWidth > dwMaxWidth) // { // m_CurrentTP.bIsLineBreak = true; // m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; // } // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // // m_CurrentTP.bIsLineBreak = false; // m_CurrentTP.sText.erase(); // } // // // 그 전에 Text아닌 다른걸 넣었다면 // else if(m_vtTextPrimitive.size() > 0 && m_vtTextPrimitive.back().dwIconType != KICON_TEXT) // { // // 줄을 넘어가면 줄바꿈을 해주자 // if(m_dwCurrentLineWidth > dwMaxWidth) // { // m_vtTextPrimitive.back().bIsLineBreak = true; // m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; // } // } // // // 한줄의 크기가 Icon보다 작은 경우는 전혀 고려하지 않았다 // m_CurrentTP.dwIconType = token.dwType - TEXT_TOKEN::EMOTICON + KICON_EMOTICON; // m_CurrentTP.dwIconID = token.dwIconID; // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.dwIconType = KICON_TEXT; // break; // } // // case TEXT_TOKEN::HALIGN: // m_dwHAlign = token.dwAlign; // break; // // case TEXT_TOKEN::VALIGN: // m_dwVAlign = token.dwAlign; // break; // // End Of String // case TEXT_TOKEN::EOS: // if(nDepth == 0) // { // m_vtTextPrimitive.push_back(m_CurrentTP); // m_CurrentTP.dwOffset = 0; // m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 // m_dwCurrentLineWidth = 0; // m_CurrentTP.Init(); // } // bLoop = FALSE; // break; // default: // break; // } // } // // if( m_bEditMode && s_bUseWordWrap ) // { // //라인 브레이크 별로, 스페이스 쪼개서 dwOffSet 재 설정 // if( !bUseSplit ) // { // int nPrimitiveCount = m_vtTextPrimitive.size(); // // DWORD checkWidth, checkHeight; // DWORD dwTextWidth = 0; // // std::vector vecTextWidthList; // std::vector vecTextPrList; // // int nContinue = 0; // // for(int i = 0; i < nPrimitiveCount; ++i) // { // const KTextParser::TEXT_PRIMITIVE &textPr = GetPrimitive(i); // // BOOL bBold = textPr.dwFontFlag & KTextRender::KTFLAG_BOLD; //BOLD 검사 // BOOL bCheckWidth = false; // // //땜방, sFontName 값이 없다. // if( textPr.sFontName.length() ) // { // KTextRender::GetStringSize(textPr.sFontName.c_str(), textPr.nFontSize, bBold, // textPr.sText.c_str(), textPr.sText.length(), &checkWidth, &checkHeight); // } // else // { // KTextRender::GetStringSize("default", textPr.nFontSize, bBold, // textPr.sText.c_str(), textPr.sText.length(), &checkWidth, &checkHeight); // } // // dwTextWidth += checkWidth; // // // 2010.06.08 - prodongi // if (!scroll) // { // int nCheckWidth = dwMaxWidth - dwTextWidth; // if( nCheckWidth < 0 ) // { // //강제 변환 // dwTextWidth -= checkWidth; // bCheckWidth = true; // } // else // { // vecTextPrList.push_back( i ); // vecTextWidthList.push_back( checkWidth ); // // if( textPr.bContinue ) // nContinue++; // } // } // else // { // vecTextPrList.push_back( i ); // vecTextWidthList.push_back( checkWidth ); // // if( textPr.bContinue ) // nContinue++; // } // // if( bCheckWidth || textPr.nBreak != 0 || textPr.nPageBreak != 0 || textPr.bIsLineBreak || i == nPrimitiveCount -1) // // // { // //dwOffSet 계산 // int nTotalBlankWidth = dwMaxWidth - dwTextWidth; // if( nTotalBlankWidth < 0 ) // { // assert( 0 ); // } // // std::string strFull; // for( unsigned int k(0); vecTextPrList.size()>k; k++ ) // { // KTextParser::TEXT_PRIMITIVE &w_textPr = GetPrimitive( vecTextPrList[k] ); // // strFull += w_textPr.sText.c_str(); // // if( !w_textPr.bContinue ) // strFull += " "; // // if( bCheckWidth && k == (vecTextPrList.size()-1) ) // w_textPr.bIsLineBreak = true; // } // //// _performance_print( "%s\n", strFull.c_str() ); // // //Space 몇개 있는가? // std::vector vecText; // nsl::split( strFull.c_str(), vecText, " ", false ); // // if( vecText.size() <=1 ) return; // // int nBlankWidth = nTotalBlankWidth/(vecText.size()-1); // // int nAccWidth = 0; // for( unsigned int k(0); vecTextPrList.size()>k; k++ ) // { // KTextParser::TEXT_PRIMITIVE &w_textPr = GetPrimitive( vecTextPrList[k] ); // // w_textPr.dwOffset = nAccWidth; // // nAccWidth += vecTextWidthList[k]; // // if( !w_textPr.bContinue ) // { // if( textPr.bIsWordWrap ) // nAccWidth += nBlankWidth; // } // } // // nContinue = 0; // dwTextWidth = 0; // vecTextWidthList.erase( vecTextWidthList.begin(), vecTextWidthList.end() ); // vecTextPrList.erase( vecTextPrList.begin(), vecTextPrList.end() ); // } // } // } // } //} // 2010.06.08 - prodongi void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit, bool scroll ) //void KTextParser::_AddString(LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit) { int nCount = 0; BOOL bLoop = TRUE; /// 2010.10.07 스트링을 분할 할때 스트링에 이모티콘 필터가 있으면 /// 필터 길이도 같이 계산이 되어서 분할이 제대로 안되는 것 같음, /// 그래서 분할 할때는 필터를 제외하고, 분할 후에 다시 필터를 추가하도록 수정함- prodongi //std::string strEmoticon; while ( bLoop) { m_CurrentTP.dwCount = nCount; TEXT_TOKEN token; if(!bTagEnable) { token.sText = lpszString; token.dwType = TEXT_TOKEN::TEXT; } else { _GetNextToken(&token, lpszString, nCount); } switch(token.dwType) { case TEXT_TOKEN::TEXT: { // 줄바꿈이 있을때만 따로 리스트에 저장 if(m_CurrentTP.nBreak > 0 || m_CurrentTP.nPageBreak > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.sText.erase(); m_CurrentTP.nBreak = m_CurrentTP.nPageBreak = 0; //줄바꿈 초기화 m_CurrentTP.bIsLineBreak = false; } // 텍스트가 있으면 if(m_CurrentTP.sText.size() > 0) { std::string s; s = lpszString+nCount; if( !s.empty() && s[0] != ' ' ) m_CurrentTP.bContinue = true; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.bContinue = false; m_CurrentTP.sText.erase(); } if (token.sText.find("") != std::string::npos) { int xxxx=1; } m_CurrentTP.sText += token.sText; BOOL bBold = m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD; //BOLD 검사 DWORD dwStrWidth = 0, dwStrHeight = 0; //문자열 가로,세로 얻기 /*KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size(),&dwStrWidth, &dwStrHeight);*/ std::string strTemp = m_CurrentTP.sText; KTextRender::GetEmoticonFilterText( strTemp ); /// 2010.10.07 이모티콘 체크, 이모티콘은 항상 스트링의 맨 앞에 오는 걸로 생각함 - prodongi /* size_t emoticonSize = 0; if (strEmoticon.empty()) { std::string strTokenTemp = token.sText; KTextRender::GetEmoticonFilterText(strTokenTemp); if (strTokenTemp != token.sText) { std::string::size_type pos = token.sText.find(strTokenTemp.c_str()); if (std::string::npos != pos) { strEmoticon = token.sText.substr(0, pos); // calcul emoticon size emoticonSize = m_CurrentTP.nFontSize + 6;//g_nEmoticonFilterOffset; } } m_CurrentTP.sText = strTemp; } */ //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, &dwStrHeight); } else { KTextRender::GetStringSize( "default", m_CurrentTP.nFontSize, bBold, strTemp.c_str(),(int)strTemp.size(),&dwStrWidth, &dwStrHeight); } //현재 라인 가로 크기에 스트링 가로 크기 더하기 m_dwCurrentLineWidth += dwStrWidth; // 한줄을 넘기게 되면 linebreak를 걸어주자 // 2010.06.03 - prodongi if( !scroll && (m_dwCurrentLineWidth > dwMaxWidth)) //if( m_dwCurrentLineWidth > dwMaxWidth) { //더해진 가로 크기에 스트링 가로 크기 다시 빼기 m_dwCurrentLineWidth -= dwStrWidth; // 추가된 Primitive를 Line size로 자르자. while (1) { int nBackLast_Space = 0; int nOldLast_Space = 0; int nLast_Space = 0; int nMaxStr = 0; DWORD dwWidth = 0, dwHeight = 0; char * psz1 = const_cast(m_CurrentTP.sText.c_str()); char * psz2 = psz1; char * last_space = NULL; char * Oldlast_space = NULL; char * Backlast_space = NULL; // dwMaxWidth에 걸맞는 Size를 찾자. int nWordSize = 0 ; while(1) { if( !(*psz1) ) break; /// 2010.11.24 - prodongi psz2 = CharNextExA(KTextRender::GetDefaultCodePage(), psz1, 0); //psz2 = CharNext(psz1); nMaxStr++; if( (psz2 - psz1) == 2) { // 한 글자가 2byte 인 경우 (ex: 한글) nMaxStr++; nBackLast_Space = nOldLast_Space; Backlast_space = Oldlast_space; //이전 ' ' nOldLast_Space = nLast_Space; Oldlast_space = last_space; last_space = psz2+1; //' '의 다음문자 지정 nLast_Space = nMaxStr; //' '까지의 길이 } if( *psz2 == ' ' ) { nBackLast_Space = nOldLast_Space; Backlast_space = Oldlast_space; //이전 ' ' nOldLast_Space = nLast_Space; Oldlast_space = last_space; last_space = psz2+1; //' '의 다음문자 지정 nLast_Space = nMaxStr; //' '까지의 길이 } nWordSize++; //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nMaxStr, &dwWidth, &dwHeight); } // 문자 하나의 size가 maxwidth를 넘는 경우 그냥 하나 단위로 짜름 if(nWordSize == 1 && dwWidth > dwMaxWidth) break; // 바로 전 글자까지만 짜르면 된다. if(m_dwCurrentLineWidth + dwWidth > dwMaxWidth) { // 이경우 2byte중 1byte만 남게 된 경우므로 // 아예 2byte를 다 잘라 버린다. nMaxStr -= int(psz2 - psz1); //위치가 앞으로 이동 된 경우 if( nMaxStr < nLast_Space ) { if( nOldLast_Space == nLast_Space ) { //이전 ' ' 으로 복구 nLast_Space = nBackLast_Space; last_space = Backlast_space; } else { //이전 ' ' 으로 복구 nLast_Space = nOldLast_Space; last_space = Oldlast_space; } } break; } psz1 = psz2; } /// 2011.06.13 한 라인에 단어 한개가 추가 ‰瑛?때, 최대 길이를 넘어간 경우의 예외 처리 - prodongi /// 많은 테스트 필요 /// 2011.06.13 mantis 10254 - prodongi /// 2011.07.25 redmine #18044 - prodongi if( s_bUseWordWrap && 0 == nLast_Space && !bUseSplit) { std::string str = m_CurrentTP.sText; // add line break m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.bIsLineBreak = true; m_CurrentTP.bIsWordWrap = false; m_CurrentTP.sText.clear(); m_vtTextPrimitive.push_back(m_CurrentTP); // add new text m_CurrentTP.bIsLineBreak = false; m_CurrentTP.sText = str; m_vtTextPrimitive.push_back(m_CurrentTP); if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } m_dwCurrentLineWidth = dwWidth; m_CurrentTP.sText.clear(); break; } // 이미 한줄이 꽉찬 상태에서 새로 Text가 추가 되면 // 그냥 줄바꿈만 해주고 다시 계산해 준다. if(nMaxStr == 0) { if(m_vtTextPrimitive.size() > 0) m_vtTextPrimitive.back().bIsLineBreak = true; //줄바꿈 설정 m_dwCurrentLineWidth = 0; //땜방, sFontName 값이 없다. // 다시 줄의 넓이를 계산한다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),m_CurrentTP.sText.length() , &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),m_CurrentTP.sText.length() , &dwWidth, &dwHeight); } // 만약 한줄에 다 들어가면 Loop 탈출 if(dwWidth < dwMaxWidth) { m_dwCurrentLineWidth = dwWidth; break; } // 그게 아니면 다시 계산 else continue; } std::string s; // 자른후에 사용할 string 저장 int nCutSize = nMaxStr; if( s_bUseWordWrap ) { //크기가 모자람 if( nMaxStr < nLast_Space ) { if( nOldLast_Space == nLast_Space ) { //이전 ' ' 으로 복구 nLast_Space = nBackLast_Space; } else { //이전 ' ' 으로 복구 nLast_Space = nOldLast_Space; } } if( nLast_Space != 0 ) nCutSize = nLast_Space; } s = m_CurrentTP.sText.c_str() + nCutSize; // _performance_print( "백업 %s\n", s.c_str() ); // 다음행의 시작 스페이스는 날린다 while( nMaxStr && !s.empty() && s[0] == ' ' ) s.erase( 0, 1 ); m_CurrentTP.sText.resize(nCutSize); //크기 재설정 m_CurrentTP.bIsLineBreak = true; //줄바꿈 설정 if( s_bUseWordWrap ) { //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nCutSize, &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(), nCutSize, &dwWidth, &dwHeight); } if( dwWidth <= dwMaxWidth ) { if( nLast_Space != 0 && nMaxStr != nLast_Space ) { //Space 몇개 있는가? std::vector vecText; nsl::split( m_CurrentTP.sText.c_str(), vecText, " ", false ); if( vecText.size()>1 ) { std::string strText, strTemp; DWORD checkWidth, checkHeight, accumWidth; accumWidth = checkWidth = checkHeight = 0; std::vector vecTextWidthList; //단어들의 길이 계산 for( unsigned int k(0); vecText.size()>k; k++ ) { //땜방, sFontName 값이 없다. if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, vecText[k].c_str(), vecText[k].length(), &checkWidth, &checkHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, vecText[k].c_str(), vecText[k].length(), &checkWidth, &checkHeight); } vecTextWidthList.push_back( checkWidth ); accumWidth += checkWidth; } /// 2010.10.05 - prodongi /// 아래 방식 처럼 쓴다면 빈 칸 사이즈가 글자 수에 따라서 틀려지기 때문에 이상하게 보인다, 수정이 필요할 것 같음,, //여백 계산 unsigned int nTotalBlankWidth = (dwMaxWidth-m_dwCurrentLineWidth)-(accumWidth); // 1줄에 여러 개의 primitive가 들어갈 경우 첫 primitive가 아닌 2번째 이상의 primitive에서 줄바꿈이 일어날 경우 줄바꿈 될 텍스트를 좌우정렬하려는 과정에서 // 이미 앞에 들어가 있던 문자의 길이를 무시하려 하기 때문에 무조건 0부터 끝까지 기준으로 좌우정렬하려고 해서 // 이미 있던 글자와 겹쳐지는 문제가 발생한다. 그래서 어디서부터 끝까지 좌우맞춤을 할 것인지 확실하게 정하기 위해 (dwMaxWidth-m_dwCurrentLineWidth) 로 고침 //Blank의 길이 계산 unsigned int nBlankWidth = nTotalBlankWidth/(vecText.size()-1); int accumWidthTemp = m_dwCurrentLineWidth; /// 2011.04.15 - prodongi //accumWidth = 0; accumWidth = m_dwCurrentLineWidth; /// 2011.04.15 m_vtTextPrimitive의 맨 마지막 텍스트가 현재 라인의 첫 텍스트라는 보장이 없기 때문에 /// 아래 처럼 accumWidth를 계산하면 텍스트가 겹처서 출력 될 수가 있다. - prodongi /* // 추가. bintitle. 2010.10.01. // 이전 Primitive 에서 bIsLineBreak 가 아닌경우에는 이전 텍스트의 길이만큼 offset을 적용해야 다음 Primitive와 겹치지 않는다. int nPrimitiveIndex = m_vtTextPrimitive.size(); if( !m_vtTextPrimitive.empty() && !m_vtTextPrimitive[ nPrimitiveIndex - 1 ].bIsLineBreak ) { TEXT_PRIMITIVE oldPrimitive = m_vtTextPrimitive[ nPrimitiveIndex - 1 ]; if( oldPrimitive.sFontName.empty() ) { KTextRender::GetStringSize("default", oldPrimitive.nFontSize, bBold, oldPrimitive.sText.c_str(), oldPrimitive.sText.length(), &accumWidth, &checkHeight); } else { KTextRender::GetStringSize(oldPrimitive.sFontName.c_str(), oldPrimitive.nFontSize, bBold, oldPrimitive.sText.c_str(), oldPrimitive.sText.length(), &accumWidth, &checkHeight); } } */ for( unsigned int k(0); vecText.size()>k; k++ ) { if( !bUseSplit ) { m_CurrentTP.dwOffset = accumWidth; /* /// 2010.10.08 두번째 텍스트 부터 첫 번째 텍스트의 이모티콘 사이즈를 더해 준다 - prodongi if (0 != k && emoticonSize) m_CurrentTP.dwOffset += emoticonSize; */ //마지막 if( k == vecText.size()-1 ) m_CurrentTP.bIsLineBreak = true; else m_CurrentTP.bIsLineBreak = false; m_CurrentTP.sText = vecText[k].c_str(); if( nBlankWidth == nTotalBlankWidth ) m_CurrentTP.nBlankWidth = 4; else m_CurrentTP.nBlankWidth = nBlankWidth; m_CurrentTP.bIsWordWrap = true; m_vtTextPrimitive.push_back(m_CurrentTP); } else { if( k==0 ) { strText = vecText[k].c_str(); } else { strTemp = nsl::format( "%s", accumWidthTemp, vecText[k].c_str() ); } strText += strTemp; } accumWidth += vecTextWidthList[k]; //단어 accumWidth += nBlankWidth; //Blank accumWidthTemp += vecTextWidthList[k]; //단어 accumWidthTemp += nBlankWidth; //Blank } if( bUseSplit ) { m_CurrentTP.bIsLineBreak = true; m_CurrentTP.sText = strText; m_vtTextPrimitive.push_back(m_CurrentTP); } m_CurrentTP.nBlankWidth = 0; m_CurrentTP.bIsWordWrap = false; } else { m_vtTextPrimitive.push_back(m_CurrentTP); } }//if( nLast_Space != 0 && nMaxStr != nLast_Space ) else { m_vtTextPrimitive.push_back(m_CurrentTP); } }//if( dwWidth <= dwMaxWidth ) else { m_vtTextPrimitive.push_back(m_CurrentTP); // assert(0 && "if( dwWidth <= dwMaxWidth )" ); } }//if( s_bUseWordWrap ) else { m_vtTextPrimitive.push_back(m_CurrentTP); } //새로 시작 m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.bIsLineBreak = false; m_CurrentTP.bIsWordWrap = false; m_CurrentTP.sText = s; //복구 //땜방 // 남은 string이 한줄을 넘지 않는다면 loop 를 탈출!! if( m_CurrentTP.sFontName.length() ) { KTextRender::GetStringSize(m_CurrentTP.sFontName.c_str(), m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } else { KTextRender::GetStringSize("default", m_CurrentTP.nFontSize, bBold, m_CurrentTP.sText.c_str(),(int)m_CurrentTP.sText.size() , &dwWidth, &dwHeight); } m_dwCurrentLineWidth = 0; if(dwWidth <= dwMaxWidth) { // 현재남은 Line의 길이를 기억해야 한다. m_dwCurrentLineWidth = dwWidth; break; } } } if(!bTagEnable) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.sText.erase(); m_dwCurrentLineWidth = 0; return; } } break; case TEXT_TOKEN::TEXTCMD: // 2010.06.08 - prodongi _AddString(token.sText.c_str(), nDepth + 1, dwMaxWidth, bTagEnable, bUseSplit, scroll); //_AddString(token.sText.c_str(), nDepth + 1, dwMaxWidth, bTagEnable, bUseSplit); break; case TEXT_TOKEN::FONT: // Font의 종류가 다르면 if(m_CurrentTP.sFontName != token.sText) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.sText.erase(); } m_CurrentTP.sFontName = token.sText; KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); } break; case TEXT_TOKEN::SIZE: if(m_CurrentTP.nFontSize != (int)token.dwFontSize) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.sText.erase(); } m_CurrentTP.nFontSize = token.dwFontSize; KTextRender::AddFont(m_CurrentTP.sFontName.c_str(),m_CurrentTP.nFontSize); } break; case TEXT_TOKEN::OFFSET: { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.sText.erase(); } m_CurrentTP.dwOffset = token.dwOffset; } break; // 그려질 오브젝트 y 오프셋 추가 적용 case TEXT_TOKEN::OFFSETY: { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.sText.erase(); } m_CurrentTP.nOffsetY = token.nOffsetY; } break; case TEXT_TOKEN::COLOR: // Color가 다르면 if(m_CurrentTP.Color.color != token.dwColor ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.Color = token.dwColor; } break; case TEXT_TOKEN::BOLD: if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD)) { if(m_CurrentTP.sText.size() > 0) { std::string s; s = lpszString+nCount; if( !s.empty() && s[0] != ' ' ) m_CurrentTP.bContinue = true; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.bContinue = false; m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Bold bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_BOLD; } break; case TEXT_TOKEN::UNBOLD: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_BOLD) { if(m_CurrentTP.sText.size() > 0) { std::string s; s = lpszString+nCount; if( !s.empty() && s[0] != ' ' ) m_CurrentTP.bContinue = true; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.bContinue = false; m_CurrentTP.sText.erase(); } // Bold bit Clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_BOLD; } break; case TEXT_TOKEN::UNDER_LINE: if(! (m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER)) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Underline bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_UNDER; } break; case TEXT_TOKEN::UNDER_LINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_UNDER) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // Underline bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_UNDER; } break; case TEXT_TOKEN::STRIKE_LINE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_STRIKE; } break; case TEXT_TOKEN::STRIKE_LINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_STRIKE) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_STRIKE; } break; case TEXT_TOKEN::SHADOW: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_SHADOW; } break; case TEXT_TOKEN::SHADOWOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_SHADOW) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_SHADOW; } break; case TEXT_TOKEN::OUTLINE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_OUTLINE; } break; case TEXT_TOKEN::OUTLINEOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_OUTLINE) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_OUTLINE; } break; case TEXT_TOKEN::GLOW: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW; } break; case TEXT_TOKEN::GLOWOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW; } break; case TEXT_TOKEN::COLOR_FX: { if(m_CurrentTP.ColorFX.color != token.dwColor ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } m_CurrentTP.ColorFX = token.dwColor; } } break; case TEXT_TOKEN::GLOW2X: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) ) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_GLOW2X; } break; case TEXT_TOKEN::GLOW2XOFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_GLOW2X) { if(m_CurrentTP.sText.size() > 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // bit clear m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_GLOW2X; } break; case TEXT_TOKEN::INVERSE: if(!(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) ) { if(m_CurrentTP.sText.size() > 0) { std::string s; s = lpszString+nCount; if( !s.empty() && s[0] != ' ' ) m_CurrentTP.bContinue = true; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.bContinue = false; m_CurrentTP.dwOffset = 0; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag |= KTextRender::KTFLAG_INVERSE; } break; case TEXT_TOKEN::INVERSE_OFF: if(m_CurrentTP.dwFontFlag & KTextRender::KTFLAG_INVERSE) { if(m_CurrentTP.sText.size() > 0) { std::string s; s = lpszString+nCount; if( !s.empty() && s[0] != ' ' ) m_CurrentTP.bContinue = true; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.bContinue = false; m_CurrentTP.sText.erase(); } // strike bit add m_CurrentTP.dwFontFlag &= ~KTextRender::KTFLAG_INVERSE; } break; case TEXT_TOKEN::CARET: break; case TEXT_TOKEN::CARET_OFF: break; case TEXT_TOKEN::BREAK: m_CurrentTP.nBreak++; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.nBreak = 0; m_CurrentTP.sText.erase(); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_dwCurrentLineWidth = 0; /// 2010.10.05 는 무엇인가?? bIsLineBreak는 여기서 항상 true가 되야 될거 같음 - prodongi //if (token.sTokenText == "") m_vtTextPrimitive.back().bIsLineBreak = true; break; case TEXT_TOKEN::PAGEBREAK: m_CurrentTP.nPageBreak++; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.nPageBreak = 0; m_CurrentTP.sText.erase(); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_dwCurrentLineWidth = 0; break; case TEXT_TOKEN::EMOTICON: case TEXT_TOKEN::NX3: { // Icon의 크기는 기본적으로 현재 Font Size의 2배 m_dwCurrentLineWidth += m_CurrentTP.nFontSize * 2; if(m_CurrentTP.sText.size() > 0) { // 줄을 넘어가면 줄바꿈을 해주자 if(m_dwCurrentLineWidth > dwMaxWidth) { m_CurrentTP.bIsLineBreak = true; m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; } m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_CurrentTP.bIsLineBreak = false; m_CurrentTP.sText.erase(); } // 그 전에 Text아닌 다른걸 넣었다면 else if(m_vtTextPrimitive.size() > 0 && m_vtTextPrimitive.back().dwIconType != KICON_TEXT) { // 줄을 넘어가면 줄바꿈을 해주자 if(m_dwCurrentLineWidth > dwMaxWidth) { m_vtTextPrimitive.back().bIsLineBreak = true; m_dwCurrentLineWidth = m_CurrentTP.nFontSize * 2; } } // 한줄의 크기가 Icon보다 작은 경우는 전혀 고려하지 않았다 m_CurrentTP.dwIconType = token.dwType - TEXT_TOKEN::EMOTICON + KICON_EMOTICON; m_CurrentTP.dwIconID = token.dwIconID; m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.dwIconType = KICON_TEXT; break; } case TEXT_TOKEN::HALIGN: m_dwHAlign = token.dwAlign; break; case TEXT_TOKEN::VALIGN: m_dwVAlign = token.dwAlign; break; // End Of String case TEXT_TOKEN::EOS: if(nDepth == 0) { m_vtTextPrimitive.push_back(m_CurrentTP); m_CurrentTP.dwOffset = 0; m_CurrentTP.nOffsetY = 0; // 그려질 오브젝트 y 오프셋 m_dwCurrentLineWidth = 0; m_CurrentTP.Init(); } bLoop = FALSE; break; default: break; } } /// 2010.10.07 - prodongi /* if (!strEmoticon.empty() && !m_vtTextPrimitive.empty()) { std::string strFront = m_vtTextPrimitive.front().sText; m_vtTextPrimitive.front().sText = strEmoticon + strFront; } */ if( m_bEditMode && s_bUseWordWrap ) { //라인 브레이크 별로, 스페이스 쪼개서 dwOffSet 재 설정 if( !bUseSplit ) { int nPrimitiveCount = m_vtTextPrimitive.size(); DWORD checkWidth, checkHeight; DWORD dwTextWidth = 0; std::vector vecTextWidthList; std::vector vecTextPrList; int nContinue = 0; for(int i = 0; i < nPrimitiveCount; ++i) { const KTextParser::TEXT_PRIMITIVE &textPr = GetPrimitive(i); BOOL bBold = textPr.dwFontFlag & KTextRender::KTFLAG_BOLD; //BOLD 검사 BOOL bCheckWidth = false; //땜방, sFontName 값이 없다. if( textPr.sFontName.length() ) { KTextRender::GetStringSize(textPr.sFontName.c_str(), textPr.nFontSize, bBold, textPr.sText.c_str(), textPr.sText.length(), &checkWidth, &checkHeight); } else { KTextRender::GetStringSize("default", textPr.nFontSize, bBold, textPr.sText.c_str(), textPr.sText.length(), &checkWidth, &checkHeight); } dwTextWidth += checkWidth; // 2010.06.08 - prodongi if (!scroll) { int nCheckWidth = dwMaxWidth - dwTextWidth; if( nCheckWidth < 0 ) { //강제 변환 dwTextWidth -= checkWidth; bCheckWidth = true; } else { vecTextPrList.push_back( i ); vecTextWidthList.push_back( checkWidth ); if( textPr.bContinue ) nContinue++; } } else { vecTextPrList.push_back( i ); vecTextWidthList.push_back( checkWidth ); if( textPr.bContinue ) nContinue++; } if( bCheckWidth || textPr.nBreak != 0 || textPr.nPageBreak != 0 || textPr.bIsLineBreak || i == nPrimitiveCount -1) { //dwOffSet 계산 int nTotalBlankWidth = dwMaxWidth - dwTextWidth; if( nTotalBlankWidth < 0 ) { assert( 0 ); } std::string strFull; for( unsigned int k(0); vecTextPrList.size()>k; k++ ) { KTextParser::TEXT_PRIMITIVE &w_textPr = GetPrimitive( vecTextPrList[k] ); strFull += w_textPr.sText.c_str(); if( !w_textPr.bContinue ) strFull += " "; if( bCheckWidth && k == (vecTextPrList.size()-1) ) w_textPr.bIsLineBreak = true; } // _performance_print( "%s\n", strFull.c_str() ); //Space 몇개 있는가? std::vector vecText; nsl::split( strFull.c_str(), vecText, " ", false ); if( vecText.size() <=1 ) return; int nBlankWidth = nTotalBlankWidth/(vecText.size()-1); int nAccWidth = 0; for( unsigned int k(0); vecTextPrList.size()>k; k++ ) { KTextParser::TEXT_PRIMITIVE &w_textPr = GetPrimitive( vecTextPrList[k] ); w_textPr.dwOffset = nAccWidth; nAccWidth += vecTextWidthList[k]; if( !w_textPr.bContinue ) { if( textPr.bIsWordWrap ) nAccWidth += nBlankWidth; } } nContinue = 0; dwTextWidth = 0; vecTextWidthList.erase( vecTextWidthList.begin(), vecTextWidthList.end() ); vecTextPrList.erase( vecTextPrList.begin(), vecTextPrList.end() ); } } } } } #endif #endif static inline char getCharToken( const char *string, int &count ) { char a; while( 1 ) { a = string[count++]; if ( a == '\n' || a == '\r' || a == '\t' ) continue; break; } return a; } static inline int hextoint( const char *str ) { int result = 0; for ( int i=0 ; i< 2 ; i++ ) { if ( str[i] >= '0' && str[i] <= '9' ) result += (str[i] - '0') * (i==0 ? 16 : 1); else if ( str[i] >= 'A' && str[i] <= 'F' ) result += (str[i] - 'A' + 10 ) * (i==0 ? 16 : 1); else if ( str[i] >= 'a' && str[i] <= 'f' ) result += (str[i] - 'a' + 10 ) * (i==0 ? 16 : 1); else return 0; } return result; } void KTextParser::_GetNextToken( TEXT_TOKEN *pToken, LPCSTR lpszToken, int & nCount) { char a = getCharToken( lpszToken, nCount ); if ( a == '\0' ) { pToken->dwType = TEXT_TOKEN::EOS; return; } if ( a == '<' ) { bool success = false; int tcount = nCount; std::string str; while ( 1 ) { char c = getCharToken( lpszToken, tcount ); if ( c == ' ' ) continue; else if ( c == '>' ) { success = true; break; } else if ( c == '<' || c == '\0' ) break; str += c; } if ( success == true ) { nCount = tcount; _InterpretCommand(str.c_str(), pToken); return; } } #ifdef _COUNTRY_ME_ if ( a == '#' ) { int tcount = nCount; char c = getCharToken( lpszToken, tcount ); if ( c == '@' ) { std::string str = "#@"; while ( 1 ) { c = getCharToken( lpszToken, tcount ); if ( c == '@' ) { c = getCharToken( lpszToken, tcount ); assert( c == '#' ); str += "@#"; break; } str += c; } nCount = tcount; pToken->dwType = TEXT_TOKEN::EMOTICON; pToken->sText = str; return; } } std::string str; while ( 1 ) { str += a; a = getCharToken( lpszToken, nCount ); if ( a == '<' || a == '#' || a == '\0' ) { nCount--; break; } } #else std::string str; while ( 1 ) { str += a; a = getCharToken( lpszToken, nCount ); if ( a == '<' /*|| a == '#'*/ || a == '\0' ) { nCount--; break; } } #endif pToken->dwType = TEXT_TOKEN::TEXT; pToken->sText = str; return; } void KTextParser::_InterpretCommand( LPCSTR lpszToken, TEXT_TOKEN * pToken) { LPCSTR cmds[] = { "FONT:", "#", "BR", "P", "$L","$", "B", "/B", "U", "/U", // 10 "STRIKE", "/STRIKE", "INV", "/INV","SHD", "/SHD", "%%", "%", "SIZE:", "LEFT", // 20 "TOP", "RIGHT", "BOTTOM", "HCENTER", "VCENTER", "OUT", "/OUT", "GLOW", "/GLOW", "SHADOW", // 30 "/SHADOW", "@", "2XGLOW","/2XGLOW", "OFFSETY:", "CARET", "/CARET", "OFFSET:", // 38 "WB" }; pToken->sTokenText = std::string("<") + lpszToken; pToken->sTokenText += ">"; for ( int i=0 ; i < _countof( cmds ) ; i++ ) { if ( strnicmp( cmds[i], lpszToken, strlen( cmds[i] ) ) == 0 ) { switch(i) { case 0: // Font Change { pToken->dwType = TEXT_TOKEN::FONT; pToken->sText = lpszToken + strlen(cmds[0]); } return; case 1: // Color Change { //Str에는 RGB 형식으로 넘어온다 const char *str = lpszToken + 1; int len = (int)strlen(str); if ( len < 6 ) { pToken->dwType = TEXT_TOKEN::INVALID; return; } unsigned char colors[4] = { 0,0,0,255, }; len = ((len/2)>4) ? 4 : len/2; for ( int j=0 ; jdwType = TEXT_TOKEN::COLOR; // a,r,g,b pToken->dwColor = (colors[3] << 24) | (colors[0] << 16) | (colors[1] << 8) | colors[2]; } return; case 2: // Br case 38: { pToken->dwType = TEXT_TOKEN::BREAK; } return; case 3: // P { pToken->dwType = TEXT_TOKEN::PAGEBREAK; } return; case 4: // $L return; case 5: // $ { const char *begin = lpszToken + 1; const char *end = lpszToken + strlen(lpszToken); const char *sep = strchr( begin, ':' ); pToken->dwType = TEXT_TOKEN::TEXT; if( *begin == 0 || end == NULL ) return; std::string strId; std::string strText; if( sep ) { strId.assign( begin, sep ); strText.assign( sep + 1, end ); } else { strText.assign( begin, end ); } if( !strId.empty() ) { int nId = atoi( strId.c_str() ); // TODO : strText = nId; const char *szText = KTextRender::GetString( nId ); if( szText ) strText = szText; // 태그는 일단 제거한다. while( true ) { size_t tag_begin = strText.find( '<' ); if( tag_begin == strText.npos ) break; size_t tag_end = strText.find( '>' ); if( tag_end == strText.npos ) break; if( tag_end > tag_begin ) strText.erase( strText.begin() + tag_begin, strText.begin() + tag_end + 1 ); else { char szError[256]; sprintf_s( szError, 256, "ID %d 번 스트링 \"%s\" 에 이상이 있습니다.", nId, KTextRender::GetString( nId ) ); MessageBox( NULL, szError, "RAPPELZ Token Parser", MB_OK ); _exit(0); } } } pToken->sText = strText; } return; case 6: // B { pToken->dwType = TEXT_TOKEN::BOLD; } return; case 7: // /B { pToken->dwType = TEXT_TOKEN::UNBOLD; } return; case 8: // U { pToken->dwType = TEXT_TOKEN::UNDER_LINE; } return; case 9: // /U { pToken->dwType = TEXT_TOKEN::UNDER_LINEOFF; } return; case 10: // S { pToken->dwType = TEXT_TOKEN::STRIKE_LINE; } return; case 11: // /S { pToken->dwType = TEXT_TOKEN::STRIKE_LINEOFF; } return; case 12: // INV { pToken->dwType = TEXT_TOKEN::INVERSE; } return; case 13: // /INV { pToken->dwType = TEXT_TOKEN::INVERSE_OFF; } return; case 29: case 14: // SHADOW { pToken->dwType = TEXT_TOKEN::SHADOW; } return; case 30: case 15: // /SHADOW { pToken->dwType = TEXT_TOKEN::SHADOWOFF; } return; // Emoticon case 16: // %% pToken->dwType = TEXT_TOKEN::EMOTICON; pToken->dwIconID = atoi( lpszToken + 1 ); return; // NX3 case 17: // % pToken->dwType = TEXT_TOKEN::NX3; pToken->dwIconID = atoi( lpszToken + 1 ); return; case 18: // SIZE: { pToken->dwType = TEXT_TOKEN::SIZE; pToken->dwFontSize = atoi(lpszToken + strlen(cmds[18])); } return; case 19: // LEFT { pToken->dwType = TEXT_TOKEN::HALIGN; pToken->dwAlign = KTextRender::KTALIGN_LEFT; } return; case 20: // TOP { pToken->dwType = TEXT_TOKEN::VALIGN; pToken->dwAlign = KTextRender::KTALIGN_TOP; } return; case 21: // RIGHT { pToken->dwType = TEXT_TOKEN::HALIGN; pToken->dwAlign = KTextRender::KTALIGN_RIGHT; } return; case 22: // BOTTOM { pToken->dwType = TEXT_TOKEN::VALIGN; pToken->dwAlign = KTextRender::KTALIGN_BOTTOM; } return; case 23: // HCENTER { pToken->dwType = TEXT_TOKEN::HALIGN; pToken->dwAlign = KTextRender::KTALIGN_HCENTER; } return; case 24: // VCENTER { pToken->dwType = TEXT_TOKEN::VALIGN; pToken->dwAlign = KTextRender::KTALIGN_VCENTER; } return; case 25: // OUTLINE { pToken->dwType = TEXT_TOKEN::OUTLINE; } return; case 26: // /OUTLINE OFF { pToken->dwType = TEXT_TOKEN::OUTLINEOFF; } return; case 27: // GLOW { pToken->dwType = TEXT_TOKEN::GLOW; } return; case 28: // /GLOW OFF { pToken->dwType = TEXT_TOKEN::GLOWOFF; } return; case 31: // /Color_FX "@" { //Str에는 RGB 형식으로 넘어온다 const char *str = lpszToken + 1; int len = (int)strlen(str); if ( len < 6 ) { pToken->dwType = TEXT_TOKEN::INVALID; return; } unsigned char colors[4] = { 0,0,0,255, }; len = ((len/2)>4) ? 4 : len/2; for ( int j=0 ; jdwType = TEXT_TOKEN::COLOR_FX; // a,r,g,b pToken->dwColor = (colors[3] << 24) | (colors[0] << 16) | (colors[1] << 8) | colors[2]; } return; case 32: //"2XGLOW" { pToken->dwType = TEXT_TOKEN::GLOW2X; } return; case 33: //"/2XGLOW" { pToken->dwType = TEXT_TOKEN::GLOW2XOFF; } return; // 그려질 오브젝트 y 오프셋 추가 적용 case 34: // OFFSETY: { pToken->dwType = TEXT_TOKEN::OFFSETY; pToken->nOffsetY = atoi(lpszToken + strlen(cmds[34])); } return; case 35: // CARET { pToken->dwType = TEXT_TOKEN::CARET; } return; case 36: // CARET_OFF { pToken->dwType = TEXT_TOKEN::CARET_OFF; } return; // 그려질 오브젝트 y 오프셋 추가 적용 case 37: // OFFSET: { pToken->dwType = TEXT_TOKEN::OFFSET; pToken->dwOffset = atoi(lpszToken + strlen(cmds[37])); } return; default: return; } } } pToken->dwType = TEXT_TOKEN::UNKNOWN; } #ifdef _COUNTRY_ME_ void KTextParser::AddEmoticonFilter( const std::string& strText, const std::string& strAni ) { s_mapEmoticonFilter.insert( mapEmoticon::value_type( strText, strAni ) ); } // 2010.06.08 - prodongi void KTextParser::_AddString( LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit, bool scroll ) //void KTextParser::_AddString( LPCSTR lpszString, int nDepth, DWORD dwMaxWidth, bool bTagEnable, bool bUseSplit ) { Clear(); int nCount = 0; bool bLoop = true; KParagraphAttr attrCurrent; bool bStrike = false; bool bUnder = false; bool bInverse = false; KTextParagraph* pTextPara = new KTextParagraph( attrCurrent ); if ( bTagEnable ) { while ( bLoop ) { TEXT_TOKEN token; _GetNextToken(&token, lpszString, nCount); switch ( token.dwType ) { case TEXT_TOKEN::EOS : bLoop = false; break; case TEXT_TOKEN::TEXT : pTextPara->AddString( token.sText ); break; case TEXT_TOKEN::EMOTICON : { imapEmoticon itor = s_mapEmoticonFilter.find( token.sText ); if ( itor != s_mapEmoticonFilter.end() ) { if ( pTextPara->GetLength() ) { m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } pTextPara->m_bEmoticon = true; pTextPara->m_strText = itor->second.c_str(); m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } } break; case TEXT_TOKEN::SHADOW: if ( pTextPara->m_attr.bShadow == false ) { if ( pTextPara->GetLength() ) { m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } pTextPara->m_attr.bShadow = true; } break; case TEXT_TOKEN::SHADOWOFF: if ( pTextPara->m_attr.bShadow == true ) { if ( pTextPara->GetLength() ) { m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } pTextPara->m_attr.bShadow = false; } break; case TEXT_TOKEN::BREAK: case TEXT_TOKEN::PAGEBREAK: pTextPara->SetLineBreak( true ); m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); break; case TEXT_TOKEN::OFFSET: if ( pTextPara->GetLength() ) { m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } pTextPara->SetOffsetX( token.dwOffset ); break; case TEXT_TOKEN::OFFSETY: if ( pTextPara->GetLength() ) { m_vtTextParagraph.push_back( pTextPara ); pTextPara = new KTextParagraph( attrCurrent ); } pTextPara->SetOffsetY( token.nOffsetY ); break; case TEXT_TOKEN::COLOR: if ( attrCurrent.dwColor != token.dwColor ) { if ( pTextPara->GetString().empty() ) pTextPara->m_attr.dwColor = token.dwColor; else pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_FCOLOR, token.dwColor ); attrCurrent.dwColor = token.dwColor; } break; case TEXT_TOKEN::FONT: { std::string strFontName = KFontManager::GetInstance()->GetFaceName( token.sText.c_str() ); if ( strFontName != attrCurrent.strFontName ) { if ( pTextPara->GetString().empty() ) pTextPara->m_attr.strFontName = KFontManager::GetInstance()->GetFaceName( strFontName.c_str() ); else pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_FONT, strFontName ); attrCurrent.strFontName = strFontName; } } break; case TEXT_TOKEN::SIZE: if ( attrCurrent.nFontSize != token.dwFontSize ) { if ( pTextPara->GetString().empty() ) pTextPara->m_attr.nFontSize = token.dwFontSize; else pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_SIZE, token.dwFontSize ); attrCurrent.nFontSize = token.dwFontSize; } break; case TEXT_TOKEN::GLOW: pTextPara->m_attr.bGlow = true; attrCurrent.bGlow = true; break; case TEXT_TOKEN::BOLD: if ( attrCurrent.bBold == false ) { if ( pTextPara->GetLength() ) pTextPara->m_attr.bBold = true; else pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_BOLD, true ); attrCurrent.bBold = true; } break; case TEXT_TOKEN::UNBOLD: if ( attrCurrent.bBold == true ) { if ( pTextPara->GetLength() ) pTextPara->m_attr.bBold = false; else pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_BOLD, false ); attrCurrent.bBold = false; } break; case TEXT_TOKEN::UNDER_LINE: if ( !bUnder ) { bUnder = true; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_UNDERLINE, bUnder ); } break; case TEXT_TOKEN::UNDER_LINEOFF: if ( bUnder ) { bUnder = false; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_UNDERLINE, bUnder ); } break; case TEXT_TOKEN::STRIKE_LINE: if ( !bStrike ) { bStrike = true; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_STRIKE, bStrike ); } break; case TEXT_TOKEN::STRIKE_LINEOFF: if ( bStrike ) { bStrike = false; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_STRIKE, bStrike ); } break; case TEXT_TOKEN::HALIGN: m_dwHAlign = token.dwAlign; break; case TEXT_TOKEN::VALIGN: m_dwVAlign = token.dwAlign; break; case TEXT_TOKEN::INVERSE: if ( !bInverse ) { bInverse = true; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_INVERSE, bInverse ); } break; case TEXT_TOKEN::INVERSE_OFF: if ( bInverse ) { bInverse = false; pTextPara->AddAttribute( KTextParagraph::KTextAttrBase::TA_INVERSE, bInverse ); } break; } } if ( pTextPara->GetLength() ) m_vtTextParagraph.push_back( pTextPara ); else delete pTextPara; } } #endif