00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <config.h>
00019 #endif
00020
00021 #include "U7file.h"
00022 #include "databuf.h"
00023 #include "font.h"
00024 #include "ibuf8.h"
00025 #include "vgafile.h"
00026 #include "exceptions.h"
00027
00028 #ifndef UNDER_CE
00029 using std::cout;
00030 using std::endl;
00031 using std::size_t;
00032 using std::string;
00033 using std::strncmp;
00034 #endif
00035
00036 FontManager fontManager;
00037
00038
00039 inline bool Is_space(char c)
00040 { return c == ' ' || c == '\n' || c == '\t'; }
00041
00042
00043
00044
00045
00046 static const char *Pass_space
00047 (
00048 const char *text
00049 )
00050 {
00051 while (Is_space(*text))
00052 text++;
00053 return (text);
00054 }
00055
00056
00057
00058
00059
00060 static const char *Pass_word
00061 (
00062 const char *text
00063 )
00064 {
00065 while (*text && (!Is_space(*text) || (*text == '\f') || (*text == '\v')))
00066 text++;
00067 return (text);
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 int Font::paint_text_box
00082 (
00083 Image_buffer8 *win,
00084 const char *text,
00085 int x, int y,
00086 int w, int h,
00087 int vert_lead,
00088 int pbreak
00089 )
00090 {
00091 const char *start = text;
00092 win->set_clip(x, y, w, h);
00093 int endx = x + w;
00094 int curx = x, cury = y;
00095 int height = get_text_height() + vert_lead + ver_lead;
00096 int space_width = get_text_width(" ", 1);
00097 int max_lines = h/height;
00098 string *lines = new string[max_lines + 1];
00099 int cur_line = 0;
00100 const char *last_punct_end = 0;
00101
00102 int last_punct_line = -1, last_punct_offset = -1;
00103
00104 while (*text)
00105 {
00106 switch (*text)
00107 {
00108 case '\n':
00109 curx = x;
00110 text++;
00111 cur_line++;
00112 if (cur_line >= max_lines)
00113 break;
00114 continue;
00115 case '\r':
00116 text++;
00117 continue;
00118 case ' ':
00119 case '\t':
00120 {
00121 const char *wrd = Pass_space(text);
00122 if (wrd != text)
00123 {
00124 int w = get_text_width(text, wrd - text);
00125 if (w <= 0)
00126 w = space_width;
00127 int nsp = w/space_width;
00128 lines[cur_line].append(nsp, ' ');
00129 curx += nsp*space_width;
00130 }
00131 text = wrd;
00132 break;
00133 }
00134 }
00135
00136 if (cur_line >= max_lines)
00137 break;
00138
00139 const char *ewrd = Pass_word(text);
00140 int width = get_text_width(text, ewrd - text);
00141 if (curx + width - hor_lead > endx)
00142 {
00143 curx = x;
00144 cur_line++;
00145 if (cur_line >= max_lines)
00146 break;
00147 }
00148
00149
00150 lines[cur_line].append(text, ewrd - text);
00151 curx += width;
00152 text = ewrd;
00153
00154 if (text[-1] == '.' || text[-1] == '?' || text[-1] == '!' ||
00155 text[-1] == ',')
00156 {
00157 last_punct_end = text;
00158 last_punct_line = cur_line;
00159 last_punct_offset = lines[cur_line].length();
00160 }
00161 }
00162 if (*text &&
00163
00164 pbreak && last_punct_end)
00165 text = Pass_space(last_punct_end);
00166 else
00167 last_punct_line = -1;
00168
00169 for (int i = 0; i <= cur_line; i++)
00170 {
00171 const char *str = lines[i].data();
00172 int len = lines[i].length();
00173 if (i == last_punct_line)
00174 len = last_punct_offset;
00175 paint_text(win, str, len, x, cury);
00176 cury += height;
00177 if (i == last_punct_line)
00178 break;
00179 }
00180 win->clear_clip();
00181 delete [] lines;
00182 if (*text)
00183 return -(text - start);
00184 else
00185 return (cury - y);
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195 int Font::paint_text
00196 (
00197 Image_buffer8 *win,
00198 const char *text,
00199 int xoff, int yoff
00200 )
00201 {
00202 int x = xoff;
00203 int chr;
00204 yoff += get_text_baseline();
00205 if (font_shapes)
00206 while ((chr = *text++) != 0)
00207 {
00208 Shape_frame *shape = font_shapes->get_frame((unsigned char)chr);
00209 if (!shape)
00210 continue;
00211 shape->paint_rle(x, yoff);
00212 x += shape->get_width() + hor_lead;
00213 }
00214 return (x - xoff);
00215 }
00216
00217
00218
00219
00220
00221
00222
00223 int Font::paint_text
00224 (
00225 Image_buffer8 *win,
00226 const char *text,
00227 int textlen,
00228 int xoff, int yoff
00229 )
00230 {
00231 int x = xoff;
00232 yoff += get_text_baseline();
00233 if (font_shapes)
00234 while (textlen--)
00235 {
00236 Shape_frame *shape= font_shapes->get_frame((unsigned char)*text++);
00237 if (!shape)
00238 continue;
00239 shape->paint_rle(x, yoff);
00240 x += shape->get_width() + hor_lead;
00241 }
00242 return (x - xoff);
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 int Font::paint_text_box_fixedwidth
00263 (
00264 Image_buffer8 *win,
00265 const char *text,
00266 int x, int y,
00267 int w, int h,
00268 int char_width,
00269 int vert_lead,
00270 int pbreak
00271 )
00272 {
00273 const char *start = text;
00274 win->set_clip(x, y, w, h);
00275 int endx = x + w;
00276 int curx = x, cury = y;
00277 int height = get_text_height() + vert_lead + ver_lead;
00278 int max_lines = h/height;
00279 string *lines = new string[max_lines + 1];
00280 int cur_line = 0;
00281 const char *last_punct_end = 0;
00282
00283 int last_punct_line = -1, last_punct_offset = -1;
00284
00285 while (*text)
00286 {
00287 switch (*text)
00288 {
00289 case '\n':
00290 curx = x;
00291 text++;
00292 cur_line++;
00293 if (cur_line >= max_lines)
00294 break;
00295 continue;
00296 case ' ':
00297 case '\t':
00298 {
00299 const char *wrd = Pass_space(text);
00300 if (wrd != text)
00301 {
00302 int w = (wrd - text) * char_width;
00303 if (!w)
00304 w = char_width;
00305 int nsp = w/char_width;
00306 lines[cur_line].append(nsp, ' ');
00307 curx += nsp*char_width;
00308 }
00309 text = wrd;
00310 break;
00311 }
00312 }
00313
00314 if (cur_line >= max_lines)
00315 break;
00316
00317 const char *ewrd = Pass_word(text);
00318 int width = (ewrd - text) * char_width;
00319 if (curx + width - hor_lead > endx)
00320 {
00321 curx = x;
00322 cur_line++;
00323 if (cur_line >= max_lines)
00324 break;
00325 }
00326
00327
00328 lines[cur_line].append(text, ewrd - text);
00329 curx += width;
00330 text = ewrd;
00331
00332 if (text[-1] == '.' || text[-1] == '?' || text[-1] == '!' ||
00333 text[-1] == ',')
00334 {
00335 last_punct_end = text;
00336 last_punct_line = cur_line;
00337 last_punct_offset = lines[cur_line].length();
00338 }
00339 }
00340 if (*text &&
00341
00342 pbreak && last_punct_end)
00343 text = Pass_space(last_punct_end);
00344 else
00345 last_punct_line = -1;
00346
00347 for (int i = 0; i <= cur_line; i++)
00348 {
00349 const char *str = lines[i].data();
00350 int len = lines[i].length();
00351 if (i == last_punct_line)
00352 len = last_punct_offset;
00353 paint_text_fixedwidth(win, str, len, x, cury, char_width);
00354 cury += height;
00355 if (i == last_punct_line)
00356 break;
00357 }
00358 win->clear_clip();
00359 delete [] lines;
00360 if (*text)
00361 return -(text - start);
00362 else
00363 return (cury - y);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373 int Font::paint_text_fixedwidth
00374 (
00375 Image_buffer8 *win,
00376 const char *text,
00377 int xoff, int yoff,
00378 int width
00379 )
00380 {
00381 int x = xoff;
00382 int w;
00383 int chr;
00384 yoff += get_text_baseline();
00385 while ((chr = *text++) != 0)
00386 {
00387 Shape_frame *shape = font_shapes->get_frame((unsigned char)chr);
00388 if (!shape)
00389 continue;
00390 x += w = (width - shape->get_width()) / 2;
00391 shape->paint_rle(x, yoff);
00392 x += width - w;
00393 }
00394 return (x - xoff);
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404 int Font::paint_text_fixedwidth
00405 (
00406 Image_buffer8 *win,
00407 const char *text,
00408 int textlen,
00409 int xoff, int yoff,
00410 int width
00411 )
00412 {
00413 int w;
00414 int x = xoff;
00415 yoff += get_text_baseline();
00416 while (textlen--)
00417 {
00418 Shape_frame *shape = font_shapes->get_frame((unsigned char) *text++);
00419 if (!shape)
00420 continue;
00421 x += w = (width - shape->get_width()) / 2;
00422 shape->paint_rle(x, yoff);
00423 x += width - w;
00424 }
00425 return (x - xoff);
00426 }
00427
00428
00429
00430
00431
00432 int Font::get_text_width
00433 (
00434 const char *text
00435 )
00436 {
00437 int width = 0;
00438 short chr;
00439 if (font_shapes)
00440 while ((chr = *text++) != 0) {
00441 Shape_frame* shape = font_shapes->get_frame((unsigned char)chr);
00442 if (shape)
00443 width += shape->get_width() + hor_lead;
00444 }
00445 return (width);
00446 }
00447
00448
00449
00450
00451
00452 int Font::get_text_width
00453 (
00454 const char *text,
00455 int textlen
00456 )
00457 {
00458 int width = 0;
00459 if (font_shapes)
00460 while (textlen--) {
00461 Shape_frame* shape =font_shapes->get_frame((unsigned char)*text++);
00462 if (shape)
00463 width += shape->get_width() + hor_lead;
00464 }
00465 return (width);
00466 }
00467
00468
00469
00470
00471
00472 int Font::get_text_height
00473 (
00474 )
00475 {
00476
00477
00478
00479 return highest + lowest + 1;
00480 }
00481
00482
00483
00484
00485
00486 int Font::get_text_baseline
00487 (
00488 )
00489 {
00490
00491 return highest;
00492 }
00493
00494 Font::Font(): font_shapes(0), font_data(0), font_buf(0), orig_font_buf(0)
00495 {
00496 }
00497
00498 Font::Font(const char *fname, int index, int hlead, int vlead): font_shapes(0), font_data(0), font_buf(0), orig_font_buf(0)
00499 {
00500 load(fname, index, hlead, vlead);
00501 }
00502
00503 Font::~Font()
00504 {
00505 if(font_shapes)
00506 delete font_shapes;
00507 if(font_data)
00508 delete font_data;
00509 if(orig_font_buf)
00510 delete [] orig_font_buf;
00511 }
00512
00513 int Font::load(const char *fname, int index, int hlead, int vlead)
00514 {
00515 if(font_shapes)
00516 delete font_shapes;
00517 if (font_data)
00518 delete font_data;
00519 if(orig_font_buf)
00520 delete [] orig_font_buf;
00521 font_shapes = 0;
00522 font_data = 0;
00523 orig_font_buf = 0;
00524 try
00525 {
00526
00527 size_t len;
00528
00529 U7object font_obj(fname, index);
00530 font_buf = font_obj.retrieve(len);
00531
00532 if (!font_buf || !len) throw (exult_exception ("Unable to retrieve data"));
00533
00534 orig_font_buf = font_buf;
00535 if(!strncmp(font_buf,"font",4))
00536 font_buf += 8;
00537 font_data = new BufferDataSource(font_buf, len);
00538 font_shapes = new Shape_file(font_data);
00539 hor_lead = hlead;
00540 ver_lead = vlead;
00541 calc_highlow();
00542 }
00543 catch (exult_exception &e)
00544 {
00545 font_data = 0;
00546 font_shapes = 0;
00547 hor_lead = 0;
00548 ver_lead = 0;
00549 orig_font_buf = 0;
00550 }
00551 return 0;
00552 }
00553
00554 int Font::center_text(Image_buffer8 *win, int x, int y, const char *s)
00555 {
00556 return draw_text(win, x - get_text_width(s)/2, y, s);
00557 }
00558
00559 void Font::calc_highlow()
00560 {
00561 bool unset = true;
00562
00563 for (int i = 0; i < font_shapes->get_num_frames(); i++)
00564 {
00565 Shape_frame *f = font_shapes->get_frame(i);
00566
00567 if (!f) continue;
00568
00569 if (unset)
00570 {
00571 unset = false;
00572 highest = f->get_yabove();
00573 lowest = f->get_ybelow();
00574 continue;
00575 }
00576
00577 if (f->get_yabove() > highest) highest = f->get_yabove();
00578 if (f->get_ybelow() > lowest) lowest = f->get_ybelow();
00579 }
00580 }
00581
00582 FontManager::FontManager()
00583 {
00584 }
00585
00586 FontManager::~FontManager()
00587 {
00588 fonts.clear();
00589 }
00590
00591 void FontManager::add_font(const char *name, const char *archive, int index, int hlead, int vlead)
00592 {
00593 remove_font(name);
00594
00595 Font *font = new Font(archive, index, hlead, vlead);
00596
00597 fonts[name] = font;
00598 }
00599
00600 void FontManager::remove_font(const char *name)
00601 {
00602 if(fonts[name]!=0) {
00603 delete fonts[name];
00604 fonts.erase(name);
00605 }
00606 }
00607
00608 Font *FontManager::get_font(const char *name)
00609 {
00610 return fonts[name];
00611 }
00612
00613 void FontManager::reset()
00614 {
00615 #ifndef DONT_HAVE_HASH_MAP
00616 hash_map<const char*, Font*, hashstr, eqstr>::iterator i;
00617 #else
00618 std::map<const char*, Font*, ltstr>::iterator i;
00619 #endif
00620
00621 for (i=fonts.begin(); i != fonts.end(); ++i) {
00622 delete (*i).second;
00623 }
00624
00625 fonts.clear();
00626 }