00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <iostream>
00023
00024 using namespace std;
00025
00026 #include <cstdio>
00027 #include <cstdlib>
00028 #include <cstring>
00029 #include "ttfont.h"
00030
00031 #include "osdtypes.h"
00032 #include "osdsurface.h"
00033
00034 static int have_library = 0;
00035 static FT_Library the_library;
00036
00037 #define FT_VALID(handle) ((handle) && (handle)->clazz != NULL)
00038
00039 struct Raster_Map
00040 {
00041 int width;
00042 int rows;
00043 int cols;
00044 int size;
00045 unsigned char *bitmap;
00046 };
00047
00048 void TTFFont::setColor(int color)
00049 {
00050 color %= 256;
00051 m_color_normal_y = color;
00052 m_color_normal_u = m_color_normal_v = 128;
00053
00054 if (m_color_normal_y > 0x80)
00055 {
00056 m_color_outline_y = 0x20;
00057 m_color_outline_u = m_color_outline_v = 128;
00058 }
00059 else
00060 {
00061 m_color_outline_y = 0xE0;
00062 m_color_outline_u = m_color_outline_v = 128;
00063 }
00064
00065 m_color_shadow_y = 0x20;
00066 m_color_shadow_u = m_color_shadow_v = 128;
00067 }
00068
00069 void TTFFont::setColor(QColor color, kTTF_Color k)
00070 {
00071 float y = (0.299 * color.red()) +
00072 (0.587 * color.green()) +
00073 (0.114 * color.blue());
00074 float u = (0.564 * (color.blue() - y));
00075 float v = (0.713 * (color.red() - y));
00076
00077 switch (k)
00078 {
00079 case kTTF_Normal:
00080 m_color_normal_y = (uint8_t)(y);
00081 m_color_normal_u = (uint8_t)(127 + u);
00082 m_color_normal_v = (uint8_t)(127 + v);
00083 break;
00084
00085 case kTTF_Outline:
00086 m_color_outline_y = (uint8_t)(y);
00087 m_color_outline_u = (uint8_t)(127 + u);
00088 m_color_outline_v = (uint8_t)(127 + v);
00089 break;
00090
00091 case kTTF_Shadow:
00092 m_color_shadow_y = (uint8_t)(y);
00093 m_color_shadow_u = (uint8_t)(127 + u);
00094 m_color_shadow_v = (uint8_t)(127 + v);
00095 break;
00096 }
00097 }
00098
00099 Raster_Map *TTFFont::create_font_raster(int width, int height)
00100 {
00101 Raster_Map *rmap;
00102
00103 rmap = new Raster_Map;
00104 rmap->width = (width + 3) & -4;
00105 rmap->rows = height;
00106 rmap->cols = rmap->width;
00107 rmap->size = rmap->rows * rmap->width;
00108 if (rmap->size <= 0)
00109 {
00110 delete rmap;
00111 return NULL;
00112 }
00113 rmap->bitmap = new unsigned char[rmap->size];
00114 if (!rmap->bitmap)
00115 {
00116 delete rmap;
00117 return NULL;
00118 }
00119 memset(rmap->bitmap, 0, rmap->size);
00120 return rmap;
00121 }
00122
00123 Raster_Map *TTFFont::duplicate_raster(FT_BitmapGlyph bmap)
00124 {
00125 Raster_Map *new_rmap;
00126
00127 new_rmap = new Raster_Map;
00128
00129 new_rmap->width = bmap->bitmap.width;
00130 new_rmap->rows = bmap->bitmap.rows;
00131 new_rmap->cols = bmap->bitmap.pitch;
00132 new_rmap->size = new_rmap->cols * new_rmap->rows;
00133
00134 if (new_rmap->size > 0)
00135 {
00136 new_rmap->bitmap = new unsigned char[new_rmap->size];
00137 memcpy(new_rmap->bitmap, bmap->bitmap.buffer, new_rmap->size);
00138 }
00139 else
00140 new_rmap->bitmap = NULL;
00141
00142 return new_rmap;
00143 }
00144
00145 void TTFFont::clear_raster(Raster_Map * rmap)
00146 {
00147 if (rmap->bitmap)
00148 memset(rmap->bitmap, 0, rmap->size);
00149 }
00150
00151 void TTFFont::destroy_font_raster(Raster_Map * rmap)
00152 {
00153 if (!rmap)
00154 return;
00155 if (rmap->bitmap)
00156 delete [] rmap->bitmap;
00157 delete rmap;
00158 }
00159
00160 Raster_Map *TTFFont::calc_size(int *width, int *height,
00161 const QString &text, bool double_size)
00162 {
00163 unsigned int i, pw, ph;
00164 Raster_Map *rtmp;
00165
00166 pw = 0;
00167 ph = ((max_ascent) - max_descent) / 64;
00168 ph = (double_size) ? ph<<1 : ph;
00169
00170 for (i = 0; i < text.length(); i++)
00171 {
00172 unsigned short j = text[i].unicode();
00173
00174 if (!cache_glyph(j))
00175 continue;
00176 if (i == 0)
00177 {
00178 FT_Load_Glyph(face, j, FT_LOAD_DEFAULT);
00179 pw += 2;
00180 }
00181
00182 if ((i + 1) == text.length())
00183 {
00184 FT_BBox bbox;
00185 FT_Glyph_Get_CBox(glyphs[j], ft_glyph_bbox_subpixels, &bbox);
00186 pw += (bbox.xMax / 64);
00187 }
00188 else
00189 {
00190 if (glyphs[j]->advance.x == 0)
00191 pw += 4;
00192 else
00193 pw += glyphs[j]->advance.x / 65535;
00194 }
00195 }
00196 *width = pw + 4;
00197 *height = ph;
00198
00199 rtmp = create_font_raster(face->size->metrics.x_ppem + 32,
00200 face->size->metrics.y_ppem + 32);
00201 return rtmp;
00202 }
00203
00204 void TTFFont::render_text(Raster_Map *rmap, Raster_Map *rchr,
00205 const QString &text, int *xorblah, int *yor,
00206 bool double_size)
00207 {
00208 FT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
00209 FT_BBox bbox;
00210 unsigned int i, ioff, iread;
00211 char *off, *off2, *read, *_off, *_off2, *_read;
00212 int x_offset, y_offset;
00213 unsigned short j, previous;
00214 Raster_Map *rtmp;
00215
00216 j = text[0];
00217 FT_Load_Glyph(face, j, FT_LOAD_DEFAULT);
00218 x_offset = 2;
00219
00220 y_offset = -(max_descent / 64);
00221
00222 *xorblah = x_offset;
00223 *yor = rmap->rows - y_offset;
00224
00225 rtmp = NULL;
00226 previous = 0;
00227
00228 for (i = 0; i < text.length(); i++)
00229 {
00230 j = text[i].unicode();
00231
00232 if (!FT_VALID(glyphs[j]))
00233 continue;
00234
00235 FT_Glyph_Get_CBox(glyphs[j], ft_glyph_bbox_subpixels, &bbox);
00236 xmin = bbox.xMin & -64;
00237 ymin = bbox.yMin & -64;
00238 xmax = (bbox.xMax + 63) & -64;
00239 ymax = (bbox.yMax + 63) & -64;
00240
00241 if (glyphs_cached[j])
00242 rtmp = glyphs_cached[j];
00243 else
00244 {
00245 FT_Vector origin;
00246 FT_BitmapGlyph bmap;
00247
00248 rtmp = rchr;
00249 clear_raster(rtmp);
00250
00251 origin.x = 0;
00252 origin.y = 0;
00253
00254 FT_Glyph_To_Bitmap(&glyphs[j], ft_render_mode_normal, &origin, 1);
00255 bmap = (FT_BitmapGlyph)(glyphs[j]);
00256
00257 glyphs_cached[j] = duplicate_raster(bmap);
00258
00259 rtmp = glyphs_cached[j];
00260 }
00261
00262
00263
00264
00265 #if 0
00266
00267 if (use_kerning && previous && j)
00268 {
00269 FT_Vector delta;
00270 FT_Get_Kerning(face, previous, j, FT_KERNING_DEFAULT, &delta);
00271 x_offset += delta.x >> 6;
00272 }
00273 #endif
00274
00275 xmin = (xmin >> 6) + x_offset;
00276 ymin = (ymin >> 6) + y_offset;
00277 xmax = (xmax >> 6) + x_offset;
00278 ymax = (ymax >> 6) + y_offset;
00279
00280
00281
00282
00283
00284 if (xmin >= (int)rmap->width ||
00285 ymin >= (int)rmap->rows ||
00286 xmax < 0 || ymax < 0)
00287 continue;
00288
00289
00290
00291
00292
00293
00294
00295
00296 if (xmax - xmin + 1 > rtmp->width)
00297 xmax = xmin + rtmp->width - 1;
00298
00299 if (ymax - ymin + 1 > rtmp->rows)
00300 ymax = ymin + rtmp->rows - 1;
00301
00302
00303
00304 iread = 0;
00305 if (ymin < 0)
00306 {
00307 iread -= ymin * rtmp->cols;
00308 ioff = 0;
00309 ymin = 0;
00310 }
00311 else
00312 {
00313 int ym = (double_size) ? (ymin << 1) : ymin;
00314 ioff = (rmap->rows - ym - 1) * rmap->cols;
00315 }
00316
00317 if (ymax >= rmap->rows)
00318 ymax = rmap->rows - 1;
00319
00320 if (xmin < 0)
00321 {
00322 iread -= xmin;
00323 xmin = 0;
00324 }
00325 else
00326 ioff += xmin;
00327
00328 if (xmax >= rmap->width)
00329 xmax = rmap->width - 1;
00330
00331 iread = (ymax - ymin) * rtmp->cols + iread;
00332
00333 _read = (char *)rtmp->bitmap + iread;
00334 _off = (char *)rmap->bitmap + ioff;
00335 _off2 = _off - rmap->cols;
00336
00337 for (y = ymin; y <= ymax; y++)
00338 {
00339 read = _read;
00340 off = _off;
00341 off2 = _off2;
00342
00343 for (x = xmin; x <= xmax; x++)
00344 {
00345 *off = *read;
00346 if (double_size)
00347 {
00348 *off2 = *read;
00349 off2++;
00350 }
00351 off++;
00352 read++;
00353 }
00354 _read -= rtmp->cols;
00355 _off -= rmap->cols;
00356 if (double_size)
00357 {
00358 _off -= rmap->cols;
00359 _off2 -= rmap->cols;
00360 _off2 -= rmap->cols;
00361 }
00362 }
00363 if (glyphs[j]->advance.x == 0)
00364 x_offset += 4;
00365 else
00366 x_offset += (glyphs[j]->advance.x / 65535);
00367 previous = j;
00368 }
00369 }
00370
00371 void TTFFont::merge_text(OSDSurface *surface, Raster_Map * rmap, int offset_x,
00372 int offset_y, int xstart, int ystart, int width,
00373 int height, int alphamod, kTTF_Color k)
00374 {
00375 unsigned char * asrc, * ydst, * udst, * vdst, * adst;
00376 uint8_t color_y = 0, color_u = 0, color_v = 0;
00377
00378 if (xstart < 0)
00379 {
00380 width += xstart;
00381 offset_x -= xstart;
00382 xstart = 0;
00383 }
00384
00385 if (ystart < 0)
00386 {
00387 height += ystart;
00388 offset_y -= ystart;
00389 ystart = 0;
00390 }
00391
00392 if (height + ystart > surface->height)
00393 height = surface->height - ystart;
00394
00395 if (width + xstart > surface->width)
00396 width = surface->width - xstart;
00397
00398 QRect drawRect(xstart, ystart, width, height);
00399 surface->AddRect(drawRect);
00400
00401 asrc = rmap->bitmap + rmap->cols * offset_y + offset_x;
00402 ydst = surface->y + surface->width * ystart + xstart;
00403 adst = surface->alpha + surface->width * ystart + xstart;
00404 udst = surface->u + (surface->width >> 1) * (ystart >> 1) + (xstart >> 1);
00405 vdst = surface->v + (surface->width >> 1) * (ystart >> 1) + (xstart >> 1);
00406
00407 switch(k)
00408 {
00409 case kTTF_Normal:
00410 color_y = m_color_normal_y;
00411 color_u = m_color_normal_u;
00412 color_v = m_color_normal_v;
00413 break;
00414 case kTTF_Outline:
00415 color_y = m_color_outline_y;
00416 color_u = m_color_outline_u;
00417 color_v = m_color_outline_v;
00418 break;
00419 case kTTF_Shadow:
00420 color_y = m_color_shadow_y;
00421 color_u = m_color_shadow_u;
00422 color_v = m_color_shadow_v;
00423 break;
00424 }
00425
00426 (surface->blendcolorfunc) (color_y, color_u, color_v,
00427 asrc, rmap->width, ydst, udst,
00428 vdst, adst, surface->width, width, height,
00429 alphamod, 1, surface->rec_lut,
00430 surface->pow_lut);
00431 }
00432
00433 void TTFFont::DrawString(OSDSurface *surface, int x, int y,
00434 const QString &text, int maxx, int maxy,
00435 int alphamod, bool double_size)
00436 {
00437 int width, height, w, h, inx, iny, clipx, clipy;
00438 Raster_Map *rmap, *rtmp;
00439 char is_pixmap = 0;
00440
00441 if (text.isEmpty())
00442 return;
00443
00444 inx = 0;
00445 iny = 0;
00446
00447 rtmp = calc_size(&w, &h, text, double_size);
00448 if (w <= 0 || h <= 0)
00449 {
00450 destroy_font_raster(rtmp);
00451 return;
00452 }
00453 rmap = create_font_raster(w, h);
00454
00455 render_text(rmap, rtmp, text, &inx, &iny, double_size);
00456
00457 is_pixmap = 1;
00458
00459 y += loadedfontsize;
00460
00461 width = maxx;
00462 height = (double_size) ? maxy<<1 : maxy;
00463
00464 clipx = 0;
00465 clipy = 0;
00466
00467 x = x - inx;
00468 y = y - iny;
00469
00470 width = width - x;
00471 height = height - y;
00472
00473 if (width > w)
00474 width = w;
00475 if (height > h)
00476 height = h;
00477
00478 if (x < 0)
00479 {
00480 clipx -= x;
00481 width += x;
00482 x = 0;
00483 }
00484
00485 if (y < 0)
00486 {
00487 clipy -= y;
00488 height += y;
00489 y = 0;
00490 }
00491
00492 if ((width <= 0) || (height <= 0))
00493 {
00494 destroy_font_raster(rmap);
00495 destroy_font_raster(rtmp);
00496 return;
00497 }
00498
00499 if (m_shadowxoff != 0 || m_shadowyoff != 0)
00500 {
00501 merge_text(surface, rmap, clipx, clipy, x + m_shadowxoff,
00502 y + m_shadowyoff, width, height, alphamod, kTTF_Shadow);
00503 }
00504
00505 if (m_outline)
00506 {
00507 merge_text(surface, rmap, clipx, clipy, x - 1, y - 1, width, height,
00508 alphamod, kTTF_Outline);
00509 merge_text(surface, rmap, clipx, clipy, x + 1, y - 1, width, height,
00510 alphamod, kTTF_Outline);
00511 merge_text(surface, rmap, clipx, clipy, x - 1, y + 1, width, height,
00512 alphamod, kTTF_Outline);
00513 merge_text(surface, rmap, clipx, clipy, x + 1, y + 1, width, height,
00514 alphamod, kTTF_Outline);
00515 }
00516
00517 merge_text(surface, rmap, clipx, clipy, x, y, width, height, alphamod);
00518
00519 destroy_font_raster(rmap);
00520 destroy_font_raster(rtmp);
00521 }
00522
00523 TTFFont::~TTFFont()
00524 {
00525 if (!valid)
00526 return;
00527
00528 KillFace();
00529 }
00530
00531 void TTFFont::KillFace(void)
00532 {
00533 FT_Done_Face(face);
00534 for (QMap<ushort, Raster_Map*>::Iterator it = glyphs_cached.begin();
00535 it != glyphs_cached.end(); it++)
00536 {
00537 destroy_font_raster(it.data());
00538 }
00539 glyphs_cached.clear();
00540
00541 for (QMap<ushort, FT_Glyph>::Iterator it = glyphs.begin();
00542 it != glyphs.end(); it++)
00543 {
00544 FT_Done_Glyph(it.data());
00545 }
00546 glyphs.clear();
00547 }
00548
00549 TTFFont::TTFFont(char *file, int size, float wscale,
00550 float hmult)
00551 {
00552 FT_Error error;
00553
00554 valid = false;
00555 m_size = size;
00556 spacewidth = 0;
00557
00558 m_outline = false;
00559 m_shadowxoff = 0;
00560 m_shadowyoff = 0;
00561
00562 m_color_normal_y = 255;
00563 m_color_normal_u = m_color_normal_v = 128;
00564
00565 m_color_outline_y = 0x40;
00566 m_color_outline_u = m_color_outline_v = 128;
00567
00568 m_color_shadow_y = 0x20;
00569 m_color_shadow_u = m_color_shadow_v = 128;
00570
00571 if (!have_library)
00572 {
00573 error = FT_Init_FreeType(&the_library);
00574 if (error) {
00575 return;
00576 }
00577 have_library++;
00578 }
00579
00580 fontsize = size;
00581 library = the_library;
00582
00583 m_wscale = wscale;
00584 m_file = file;
00585 m_hmult = hmult;
00586
00587 Init();
00588 }
00589
00590 bool TTFFont::cache_glyph(unsigned short c)
00591 {
00592 FT_BBox bbox;
00593 unsigned short code;
00594
00595 if (FT_VALID(glyphs[c]))
00596 return true;
00597
00598 code = FT_Get_Char_Index(face, c);
00599
00600 FT_Load_Glyph(face, code, FT_LOAD_DEFAULT);
00601 FT_Glyph& glyph = glyphs[c];
00602 if (FT_Get_Glyph(face->glyph, &glyph))
00603 {
00604 cerr << "cannot load glyph:" << hex << c << "\n";
00605 return false;
00606 }
00607
00608 FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_subpixels, &bbox);
00609
00610 if ((bbox.yMin & -64) < max_descent)
00611 max_descent = (bbox.yMin & -64);
00612 if (((bbox.yMax + 63) & -64) > max_ascent)
00613 max_ascent = ((bbox.yMax + 63) & -64);
00614
00615 return true;
00616 }
00617
00618 void TTFFont::Init(void)
00619 {
00620 FT_Error error;
00621 FT_CharMap char_map;
00622 int xdpi = 96, ydpi = 96;
00623 unsigned short i, n;
00624
00625 error = FT_New_Face(library, m_file, 0, &face);
00626 if (error)
00627 {
00628 return;
00629 }
00630
00631 loadedfontsize = (int)(fontsize * m_hmult);
00632
00633 FT_Set_Char_Size(face, 0, loadedfontsize * 64, xdpi, ydpi);
00634
00635 FT_Matrix tmatrix;
00636 tmatrix.xx = (FT_Fixed)(m_wscale * (1<<16));
00637 tmatrix.yx = (FT_Fixed)0;
00638 tmatrix.xy = (FT_Fixed)0;
00639 tmatrix.yy = (FT_Fixed)(1<<16);
00640 FT_Set_Transform(face, &tmatrix, 0);
00641
00642 n = face->num_charmaps;
00643
00644 for (i = 0; i < n; i++)
00645 {
00646 char_map = face->charmaps[i];
00647 if ((char_map->platform_id == 3 && char_map->encoding_id == 1) ||
00648 (char_map->platform_id == 0 && char_map->encoding_id == 0))
00649 {
00650 FT_Set_Charmap(face, char_map);
00651 break;
00652 }
00653 }
00654 if (i == n)
00655 FT_Set_Charmap(face, face->charmaps[0]);
00656
00657 max_descent = 0;
00658 max_ascent = 0;
00659
00660
00661 for (i = 32; i < 127; ++i)
00662 cache_glyph(i);
00663
00664 for (i = 160; i < 256; ++i)
00665 cache_glyph(i);
00666
00667 use_kerning = FT_HAS_KERNING(face);
00668
00669 valid = true;
00670
00671 int mwidth, twidth;
00672 CalcWidth("M M", &twidth);
00673 CalcWidth("M", &mwidth);
00674
00675 spacewidth = twidth - (mwidth * 2);
00676 }
00677
00678 void TTFFont::Reinit(float wscale, float hmult)
00679 {
00680 m_wscale = wscale;
00681 m_hmult = hmult;
00682
00683 KillFace();
00684 Init();
00685 }
00686
00687
00688 void TTFFont::CalcWidth(const QString &text, int *width_return)
00689 {
00690 unsigned int i, pw;
00691
00692 pw = 0;
00693
00694 for (i = 0; i < text.length(); i++)
00695 {
00696 unsigned short j = text[i].unicode();
00697
00698 if (!cache_glyph(j))
00699 continue;
00700
00701 if (glyphs[j]->advance.x == 0)
00702 pw += 4;
00703 else
00704 pw += glyphs[j]->advance.x / 65535;
00705 }
00706
00707 if (width_return)
00708 *width_return = pw;
00709 }