00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "Font.h"
00022
00023 namespace Pentagram {
00024
00025 DEFINE_RUNTIME_CLASSTYPE_CODE_BASE_CLASS(Font)
00026
00027 Font::Font() : highRes(false)
00028 {
00029
00030 }
00031
00032
00033 Font::~Font()
00034 {
00035 }
00036
00037
00038 void Font::getTextSize(const std::string& text,
00039 int& resultwidth, int& resultheight,
00040 unsigned int& remaining,
00041 int width, int height, TextAlign align,
00042 bool u8specials)
00043 {
00044 std::list<PositionedText> tmp;
00045 tmp = typesetText<Traits>(this, text, remaining,
00046 width, height, align, u8specials,
00047 resultwidth, resultheight);
00048 }
00049
00050
00051
00052 bool Font::Traits::canBreakAfter(std::string::const_iterator& i)
00053 {
00054
00055
00056 return true;
00057 }
00058
00059
00060
00061 bool Font::SJISTraits::canBreakAfter(std::string::const_iterator& i)
00062 {
00063 std::string::const_iterator j = i;
00064 uint32 u1 = unicode(j);
00065
00066
00067
00068
00069 switch (u1) {
00070 case 0xff08: case 0x3014: case 0xff3b: case 0xff5b: case 0x3008:
00071 case 0x300a: case 0x300c: case 0x300e: case 0x3010: case 0x2018:
00072 case 0x201c:
00073 return false;
00074 default:
00075 break;
00076 }
00077
00078 uint32 u2 = unicode(j);
00079 switch (u2) {
00080 case 0x3001: case 0x3002: case 0xff0c: case 0xff0e: case 0xff09:
00081 case 0x3015: case 0xff3d: case 0xff5d: case 0x3009: case 0x300b:
00082 case 0x300d: case 0x300f: case 0x3011: case 0x2019: case 0x201d:
00083 case 0x309d: case 0x309e: case 0x30fd: case 0x30fe: case 0x3005:
00084 case 0xff1f: case 0xff01: case 0xff1a: case 0xff1b: case 0x3041:
00085 case 0x3043: case 0x3045: case 0x3047: case 0x3049: case 0x3083:
00086 case 0x3085: case 0x3087: case 0x308e: case 0x30a1: case 0x30a3:
00087 case 0x30a5: case 0x30a7: case 0x30a9: case 0x30e3: case 0x30e5:
00088 case 0x30e7: case 0x30ee: case 0x3063: case 0x30f5: case 0x30c3:
00089 case 0x30f6: case 0x30fb: case 0x2026: case 0x30fc:
00090 return false;
00091 default:
00092 break;
00093 }
00094
00095
00096 if (((u1 >= 'A' && u1 <= 'Z') || (u1 >= 'a' && u1 <= 'z')) &&
00097 ((u2 >= 'A' && u2 <= 'Z') || (u2 >= 'a' && u2 <= 'z')))
00098 {
00099 return false;
00100 }
00101 return true;
00102 }
00103
00104 }
00105
00106 template<class T>
00107 static void findWordEnd(const std::string& text,
00108 std::string::const_iterator& iter, bool u8specials)
00109 {
00110 while (iter != text.end()) {
00111 if (T::isSpace(iter, u8specials)) return;
00112 T::advance(iter);
00113 }
00114 }
00115
00116 template<class T>
00117 static void passSpace(const std::string& text,
00118 std::string::const_iterator& iter, bool u8specials)
00119 {
00120 while (iter != text.end()) {
00121 if (!T::isSpace(iter, u8specials)) return;
00122 T::advance(iter);
00123 }
00124 return;
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 template<class T>
00142 std::list<PositionedText> typesetText(Pentagram::Font* font,
00143 const std::string& text,
00144 unsigned int& remaining,
00145 int width, int height,
00146 Pentagram::Font::TextAlign align,
00147 bool u8specials,
00148 int& resultwidth, int& resultheight,
00149 std::string::size_type cursor)
00150 {
00151 #if 0
00152 pout << "typeset (" << width << "," << height << ") : "
00153 << text << std::endl;
00154 #endif
00155
00156
00157 remaining = text.size();
00158
00159 std::string curline;
00160
00161 int totalwidth = 0;
00162 int totalheight = 0;
00163
00164 std::list<PositionedText> lines;
00165 PositionedText line;
00166
00167 std::string::const_iterator iter = text.begin();
00168 std::string::const_iterator cursoriter = text.begin();
00169 if (cursor != std::string::npos) cursoriter += cursor;
00170 std::string::const_iterator curlinestart = text.begin();
00171
00172 bool breakhere = false;
00173 while (true)
00174 {
00175 if (iter == text.end() || breakhere || T::isBreak(iter, u8specials))
00176 {
00177
00178 int stringwidth = 0, stringheight = 0;
00179 font->getStringSize(curline, stringwidth, stringheight);
00180 line.dims.x = 0; line.dims.y = totalheight;
00181 line.dims.w = stringwidth;
00182 line.dims.h = stringheight;
00183 line.text = curline;
00184 line.cursor = std::string::npos;
00185 if (cursor != std::string::npos && cursoriter >= curlinestart &&
00186 (cursoriter < iter || (!breakhere && cursoriter == iter)))
00187 {
00188 line.cursor = cursoriter - curlinestart;
00189 if (line.dims.w == 0) {
00190 stringwidth = line.dims.w = 2;
00191 }
00192 }
00193 lines.push_back(line);
00194
00195 if (stringwidth > totalwidth) totalwidth = stringwidth;
00196 totalheight += font->getBaselineSkip();
00197
00198 curline = "";
00199
00200 if (iter == text.end())
00201 break;
00202
00203 if (breakhere) {
00204 breakhere = false;
00205 curlinestart = iter;
00206 } else {
00207 T::advance(iter);
00208 curlinestart = iter;
00209 }
00210
00211 if (height != 0 && totalheight + font->getHeight() > height) {
00212
00213 remaining = curlinestart - text.begin();
00214 break;
00215 }
00216
00217 } else {
00218
00219
00220 std::string::const_iterator nextword = iter;
00221 passSpace<T>(text, nextword, u8specials);
00222
00223
00224 bool foundLF = false;
00225 std::string spaces;
00226 for (; iter < nextword; T::advance(iter)) {
00227 if (T::isBreak(iter, u8specials)) {
00228 foundLF = true;
00229 break;
00230 } else if (T::isTab(iter, u8specials)) {
00231 spaces.append(" ");
00232 } else if (!curline.empty()) {
00233 spaces.append(" ");
00234 }
00235 }
00236 if (foundLF) continue;
00237
00238
00239 std::string::const_iterator endofnextword = iter;
00240 findWordEnd<T>(text, endofnextword, u8specials);
00241 int stringwidth = 0, stringheight = 0;
00242 std::string newline = curline + spaces +
00243 text.substr(nextword-text.begin(),endofnextword-nextword);
00244 font->getStringSize(newline, stringwidth, stringheight);
00245
00246
00247 if (width != 0 && stringwidth > width) {
00248 if (!curline.empty()) {
00249 iter = nextword;
00250 } else {
00251
00252
00253
00254 iter = nextword;
00255 std::string::const_iterator saveiter;
00256 std::string::const_iterator saveiter_fail;
00257 std::string curline_fail;
00258 newline = spaces;
00259 bool breakok = true;
00260 int breakcount = -1;
00261 do {
00262 if (breakok) {
00263 curline = newline;
00264 saveiter = iter;
00265 breakcount++;
00266 }
00267 curline_fail = newline;
00268 saveiter_fail = iter;
00269
00270 if (iter == text.end()) break;
00271
00272 breakok = T::canBreakAfter(iter);
00273
00274
00275 T::advance(iter);
00276 newline = spaces + text.substr(nextword-text.begin(),
00277 iter-nextword);
00278 font->getStringSize(newline, stringwidth,stringheight);
00279 } while (stringwidth <= width);
00280 if (breakcount > 0) {
00281 iter = saveiter;
00282 } else {
00283 iter = saveiter_fail;
00284 curline = curline_fail;
00285 }
00286 }
00287 breakhere = true;
00288 continue;
00289 } else {
00290
00291 curline = newline;
00292 iter = endofnextword;
00293 }
00294 }
00295 }
00296
00297 if (lines.size() == 1 && align == Pentagram::Font::TEXT_LEFT) {
00298
00299 width = totalwidth;
00300 }
00301
00302 if (width != 0) totalwidth = width;
00303
00304
00305 totalheight -= font->getBaselineSkip();
00306 totalheight += font->getHeight();
00307
00308
00309 std::list<PositionedText>::iterator lineiter;
00310 for (lineiter = lines.begin(); lineiter != lines.end(); ++lineiter) {
00311 switch (align) {
00312 case Pentagram::Font::TEXT_LEFT:
00313 break;
00314 case Pentagram::Font::TEXT_RIGHT:
00315 lineiter->dims.x = totalwidth - lineiter->dims.w;
00316 break;
00317 case Pentagram::Font::TEXT_CENTER:
00318 lineiter->dims.x = (totalwidth - lineiter->dims.w) / 2;
00319 break;
00320 }
00321 #if 0
00322 pout << lineiter->dims.x << "," << lineiter->dims.y << " "
00323 << lineiter->dims.w << "," << lineiter->dims.h << ": "
00324 << lineiter->text << std::endl;
00325 #endif
00326 }
00327
00328 resultwidth = totalwidth;
00329 resultheight = totalheight;
00330
00331 return lines;
00332 }
00333
00334
00335
00336 template
00337 std::list<PositionedText> typesetText<Pentagram::Font::Traits>
00338 (Pentagram::Font* font, const std::string& text,
00339 unsigned int& remaining, int width, int height,
00340 Pentagram::Font::TextAlign align, bool u8specials,
00341 int& resultwidth, int& resultheight, std::string::size_type cursor);
00342
00343 template
00344 std::list<PositionedText> typesetText<Pentagram::Font::SJISTraits>
00345 (Pentagram::Font* font, const std::string& text,
00346 unsigned int& remaining, int width, int height,
00347 Pentagram::Font::TextAlign align, bool u8specials,
00348 int& resultwidth, int& resultheight, std::string::size_type cursor);