00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026
00027 #if defined (HAVE_FREETYPE)
00028
00029 #if defined (HAVE_FONTCONFIG)
00030 #include <fontconfig/fontconfig.h>
00031 #endif
00032
00033 #include <iostream>
00034
00035 #include "singleton-cleanup.h"
00036
00037 #include "error.h"
00038 #include "pr-output.h"
00039 #include "txt-eng-ft.h"
00040
00041
00042
00043
00044 static void
00045 gripe_missing_glyph (char c)
00046 {
00047 warning_with_id ("Octave:missing-glyph",
00048 "ft_render: skipping missing glyph for character '%c'",
00049 c);
00050 }
00051
00052 static void
00053 gripe_glyph_render (char c)
00054 {
00055 warning_with_id ("Octave:glyph-render",
00056 "ft_render: unable to render glyph for character '%c'",
00057 c);
00058 }
00059
00060 #ifdef _MSC_VER
00061
00062
00063
00064
00065 #include "PermMatrix.h"
00066 #endif
00067
00068 class
00069 ft_manager
00070 {
00071 public:
00072 static bool instance_ok (void)
00073 {
00074 bool retval = true;
00075
00076 if (! instance)
00077 {
00078 instance = new ft_manager ();
00079
00080 if (instance)
00081 singleton_cleanup_list::add (cleanup_instance);
00082 }
00083
00084 if (! instance)
00085 {
00086 ::error ("unable to create ft_manager!");
00087
00088 retval = false;
00089 }
00090
00091 return retval;
00092 }
00093
00094 static void cleanup_instance (void) { delete instance; instance = 0; }
00095
00096 static FT_Face get_font (const std::string& name, const std::string& weight,
00097 const std::string& angle, double size)
00098 { return (instance_ok ()
00099 ? instance->do_get_font (name, weight, angle, size)
00100 : 0); }
00101
00102 private:
00103
00104 static ft_manager *instance;
00105
00106 private:
00107
00108
00109
00110 ft_manager (const ft_manager&);
00111
00112 ft_manager& operator = (const ft_manager&);
00113
00114 ft_manager (void)
00115 : library (), freetype_initialized (false), fontconfig_initialized (false)
00116 {
00117 if (FT_Init_FreeType (&library))
00118 ::error ("unable to initialize freetype library");
00119 else
00120 freetype_initialized = true;
00121
00122 #if defined (HAVE_FONTCONFIG)
00123 if (! FcInit ())
00124 ::error ("unable to initialize fontconfig library");
00125 else
00126 fontconfig_initialized = true;
00127 #endif
00128 }
00129
00130 ~ft_manager (void)
00131 {
00132 if (freetype_initialized)
00133 FT_Done_FreeType (library);
00134
00135 #if defined (HAVE_FONTCONFIG)
00136
00137
00138
00139
00140
00141
00142
00143 #endif
00144 }
00145
00146
00147 FT_Face do_get_font (const std::string& name, const std::string& weight,
00148 const std::string& angle, double size)
00149 {
00150 FT_Face retval = 0;
00151
00152 std::string file;
00153
00154 #if defined (HAVE_FONTCONFIG)
00155 if (fontconfig_initialized)
00156 {
00157 int fc_weight, fc_angle;
00158
00159 if (weight == "bold")
00160 fc_weight = FC_WEIGHT_BOLD;
00161 else if (weight == "light")
00162 fc_weight = FC_WEIGHT_LIGHT;
00163 else if (weight == "demi")
00164 fc_weight = FC_WEIGHT_DEMIBOLD;
00165 else
00166 fc_weight = FC_WEIGHT_NORMAL;
00167
00168 if (angle == "italic")
00169 fc_angle = FC_SLANT_ITALIC;
00170 else if (angle == "oblique")
00171 fc_angle = FC_SLANT_OBLIQUE;
00172 else
00173 fc_angle = FC_SLANT_ROMAN;
00174
00175 FcPattern *pat = FcPatternCreate ();
00176
00177 FcPatternAddString (pat, FC_FAMILY,
00178 (reinterpret_cast<const FcChar8*>
00179 (name == "*" ? "sans" : name.c_str ())));
00180
00181 FcPatternAddInteger (pat, FC_WEIGHT, fc_weight);
00182 FcPatternAddInteger (pat, FC_SLANT, fc_angle);
00183 FcPatternAddDouble (pat, FC_PIXEL_SIZE, size);
00184
00185 if (FcConfigSubstitute (0, pat, FcMatchPattern))
00186 {
00187 FcResult res;
00188 FcPattern *match;
00189
00190 FcDefaultSubstitute (pat);
00191 match = FcFontMatch (0, pat, &res);
00192
00193
00194
00195 if (match)
00196 {
00197 unsigned char *tmp;
00198
00199 FcPatternGetString (match, FC_FILE, 0, &tmp);
00200 file = reinterpret_cast<char*> (tmp);
00201 }
00202 else
00203 ::warning ("could not match any font: %s-%s-%s-%g",
00204 name.c_str (), weight.c_str (), angle.c_str (),
00205 size);
00206
00207 if (match)
00208 FcPatternDestroy (match);
00209 }
00210
00211 FcPatternDestroy (pat);
00212 }
00213 #endif
00214
00215 if (file.empty ())
00216 {
00217 #ifdef __WIN32__
00218 file = "C:/WINDOWS/Fonts/verdana.ttf";
00219 #else
00220
00221 #endif
00222 }
00223
00224 if (! file.empty () && FT_New_Face (library, file.c_str (), 0, &retval))
00225 ::warning ("ft_manager: unable to load font: %s", file.c_str ());
00226
00227 return retval;
00228 }
00229
00230 private:
00231 FT_Library library;
00232 bool freetype_initialized;
00233 bool fontconfig_initialized;
00234 };
00235
00236 ft_manager* ft_manager::instance = 0;
00237
00238
00239
00240 ft_render::ft_render (void)
00241 : text_processor (), face (0), bbox (1, 4, 0.0),
00242 xoffset (0), yoffset (0), multiline_halign (0),
00243 multiline_align_xoffsets(), mode (MODE_BBOX),
00244 red (0), green (0), blue (0)
00245 {
00246 }
00247
00248 ft_render::~ft_render (void)
00249 {
00250 if (face)
00251 FT_Done_Face (face);
00252 }
00253
00254 void
00255 ft_render::set_font (const std::string& name, const std::string& weight,
00256 const std::string& angle, double size)
00257 {
00258 if (face)
00259 FT_Done_Face (face);
00260
00261
00262 face = ft_manager::get_font (name, weight, angle, size);
00263
00264 if (face)
00265 {
00266 if (FT_Set_Char_Size (face, 0, size*64, 0, 0))
00267 ::warning ("ft_render: unable to set font size to %d", size);
00268 }
00269 else
00270 ::warning ("ft_render: unable to load appropriate font");
00271 }
00272
00273 void
00274 ft_render::set_mode (int m)
00275 {
00276 mode = m;
00277
00278 switch (mode)
00279 {
00280 case MODE_BBOX:
00281 xoffset = yoffset = 0;
00282 bbox = Matrix (1, 4, 0.0);
00283 break;
00284 case MODE_RENDER:
00285 if (bbox.numel () != 4)
00286 {
00287 ::warning ("ft_render: invalid bounding box, cannot render");
00288
00289 xoffset = yoffset = 0;
00290 pixels = uint8NDArray ();
00291 }
00292 else
00293 {
00294 pixels = uint8NDArray (dim_vector (4, bbox(2), bbox(3)),
00295 static_cast<uint8_t> (0));
00296 xoffset = 0;
00297 yoffset = -bbox(1)-1;
00298 }
00299 break;
00300 default:
00301 ::error ("ft_render: invalid mode '%d'", mode);
00302 break;
00303 }
00304 }
00305
00306 void
00307 ft_render::visit (text_element_string& e)
00308 {
00309 if (face)
00310 {
00311 int line_index = 0;
00312 FT_UInt box_line_width = 0;
00313 std::string str = e.string_value ();
00314 FT_UInt glyph_index, previous = 0;
00315
00316 if (mode == MODE_BBOX)
00317 multiline_align_xoffsets.clear();
00318 else if (mode == MODE_RENDER)
00319 xoffset += multiline_align_xoffsets[line_index];
00320
00321 for (size_t i = 0; i < str.length (); i++)
00322 {
00323 glyph_index = FT_Get_Char_Index (face, str[i]);
00324
00325 if (str[i] != '\n'
00326 && (! glyph_index
00327 || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
00328 gripe_missing_glyph (str[i]);
00329 else
00330 {
00331 switch (mode)
00332 {
00333 case MODE_RENDER:
00334 if (str[i] == '\n')
00335 {
00336 glyph_index = FT_Get_Char_Index(face, ' ');
00337 if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
00338 {
00339 gripe_missing_glyph (' ');
00340 }
00341 else
00342 {
00343 line_index++;
00344 xoffset = multiline_align_xoffsets[line_index];
00345 yoffset -= (face->size->metrics.height >> 6);
00346 }
00347 }
00348 else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
00349 {
00350 gripe_glyph_render (str[i]);
00351 }
00352 else
00353 {
00354 FT_Bitmap& bitmap = face->glyph->bitmap;
00355 int x0, y0;
00356
00357 if (previous)
00358 {
00359 FT_Vector delta;
00360
00361 FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
00362 xoffset += (delta.x >> 6);
00363 }
00364
00365 x0 = xoffset+face->glyph->bitmap_left;
00366 y0 = yoffset+face->glyph->bitmap_top;
00367
00368
00369
00370
00371
00372 if (x0 < 0)
00373 x0 = 0;
00374
00375 for (int r = 0; r < bitmap.rows; r++)
00376 for (int c = 0; c < bitmap.width; c++)
00377 {
00378 unsigned char pix = bitmap.buffer[r*bitmap.width+c];
00379 if (x0+c < 0 || x0+c >= pixels.dim2()
00380 || y0-r < 0 || y0-r >= pixels.dim3())
00381 {
00382
00383 }
00384 else if (pixels(3, x0+c, y0-r).value () == 0)
00385 {
00386 pixels(0, x0+c, y0-r) = red;
00387 pixels(1, x0+c, y0-r) = green;
00388 pixels(2, x0+c, y0-r) = blue;
00389 pixels(3, x0+c, y0-r) = pix;
00390 }
00391 }
00392
00393 xoffset += (face->glyph->advance.x >> 6);
00394 }
00395 break;
00396
00397 case MODE_BBOX:
00398 if (str[i] == '\n')
00399 {
00400 glyph_index = FT_Get_Char_Index(face, ' ');
00401 if (! glyph_index
00402 || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
00403 {
00404 gripe_missing_glyph (' ');
00405 }
00406 else
00407 {
00408 multiline_align_xoffsets.push_back(box_line_width);
00409
00410
00411
00412 box_line_width = 0;
00413 bbox(1) -= (face->size->metrics.height >> 6);
00414 }
00415 }
00416 else
00417 {
00418
00419 if (previous)
00420 {
00421 FT_Vector delta;
00422
00423 FT_Get_Kerning (face, previous, glyph_index,
00424 FT_KERNING_DEFAULT, &delta);
00425
00426 box_line_width += (delta.x >> 6);
00427 }
00428
00429 box_line_width += (face->glyph->advance.x >> 6);
00430
00431 int asc, desc;
00432
00433 if (false )
00434 {
00435 desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
00436 asc = face->glyph->metrics.horiBearingY;
00437 }
00438 else
00439 {
00440 asc = face->size->metrics.ascender;
00441 desc = face->size->metrics.descender;
00442 }
00443
00444 asc = yoffset + (asc >> 6);
00445 desc = yoffset + (desc >> 6);
00446
00447 if (desc < bbox(1))
00448 {
00449 bbox(3) += (bbox(1) - desc);
00450 bbox(1) = desc;
00451 }
00452 if (asc > (bbox(3)+bbox(1)))
00453 bbox(3) = asc-bbox(1);
00454 if (bbox(2) < box_line_width)
00455 bbox(2) = box_line_width;
00456 }
00457 break;
00458 }
00459 if (str[i] == '\n')
00460 previous = 0;
00461 else
00462 previous = glyph_index;
00463 }
00464 }
00465 if (mode == MODE_BBOX)
00466 {
00467
00468 multiline_align_xoffsets.push_back(box_line_width);
00469
00470 for (unsigned int i = 0; i < multiline_align_xoffsets.size(); i++)
00471 {
00472
00473 if (multiline_halign == 1)
00474 multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2;
00475
00476 else if (multiline_halign == 2)
00477 multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]);
00478
00479 else
00480 multiline_align_xoffsets[i] = 0;
00481 }
00482 }
00483 }
00484 }
00485
00486 void
00487 ft_render::reset (void)
00488 {
00489 set_mode (MODE_BBOX);
00490 set_color (Matrix (1, 3, 0.0));
00491 }
00492
00493 void
00494 ft_render::set_color (Matrix c)
00495 {
00496 if (c.numel () == 3)
00497 {
00498 red = static_cast<uint8_t> (c(0)*255);
00499 green = static_cast<uint8_t> (c(1)*255);
00500 blue = static_cast<uint8_t> (c(2)*255);
00501 }
00502 else
00503 ::warning ("ft_render::set_color: invalid color");
00504 }
00505
00506 uint8NDArray
00507 ft_render::render (text_element* elt, Matrix& box, int rotation)
00508 {
00509 set_mode (MODE_BBOX);
00510 elt->accept (*this);
00511 box = bbox;
00512
00513 set_mode (MODE_RENDER);
00514 if (pixels.numel () > 0)
00515 {
00516 elt->accept (*this);
00517
00518 switch (rotation)
00519 {
00520 case ROTATION_0:
00521 break;
00522 case ROTATION_90:
00523 {
00524 Array<octave_idx_type> perm (dim_vector (3, 1));
00525 perm(0) = 0;
00526 perm(1) = 2;
00527 perm(2) = 1;
00528 pixels = pixels.permute (perm);
00529
00530 Array<idx_vector> idx (dim_vector (3, 1));
00531 idx(0) = idx_vector (':');
00532 idx(1) = idx_vector (pixels.dim2()-1, -1, -1);
00533 idx(2) = idx_vector (':');
00534 pixels = uint8NDArray (pixels.index (idx));
00535 }
00536 break;
00537 case ROTATION_180:
00538 {
00539 Array<idx_vector> idx (dim_vector (3, 1));
00540 idx(0) = idx_vector (':');
00541 idx(1) = idx_vector (pixels.dim2()-1, -1, -1);
00542 idx(2)= idx_vector (pixels.dim3()-1, -1, -1);
00543 pixels = uint8NDArray (pixels.index (idx));
00544 }
00545 break;
00546 case ROTATION_270:
00547 {
00548 Array<octave_idx_type> perm (dim_vector (3, 1));
00549 perm(0) = 0;
00550 perm(1) = 2;
00551 perm(2) = 1;
00552 pixels = pixels.permute (perm);
00553
00554 Array<idx_vector> idx (dim_vector (3, 1));
00555 idx(0) = idx_vector (':');
00556 idx(1) = idx_vector (':');
00557 idx(2) = idx_vector (pixels.dim3()-1, -1, -1);
00558 pixels = uint8NDArray (pixels.index (idx));
00559 }
00560 break;
00561 }
00562 }
00563
00564 return pixels;
00565 }
00566
00567 Matrix
00568 ft_render::get_extent (text_element *elt, double rotation)
00569 {
00570 set_mode (MODE_BBOX);
00571 elt->accept (*this);
00572
00573 Matrix extent (1, 2, 0.0);
00574
00575 switch (rotation_to_mode (rotation))
00576 {
00577 case ROTATION_0:
00578 case ROTATION_180:
00579 extent(0) = bbox(2);
00580 extent(1) = bbox(3);
00581 break;
00582 case ROTATION_90:
00583 case ROTATION_270:
00584 extent(0) = bbox(3);
00585 extent(1) = bbox(2);
00586 }
00587
00588 return extent;
00589 }
00590
00591 Matrix
00592 ft_render::get_extent (const std::string& txt, double rotation)
00593 {
00594 text_element *elt = text_parser_none ().parse (txt);
00595 Matrix extent = get_extent (elt, rotation);
00596 delete elt;
00597
00598 return extent;
00599 }
00600
00601 int
00602 ft_render::rotation_to_mode (double rotation) const
00603 {
00604 if (rotation == 0.0)
00605 return ROTATION_0;
00606 else if (rotation == 90.0)
00607 return ROTATION_90;
00608 else if (rotation == 180.0)
00609 return ROTATION_180;
00610 else if (rotation == 270.0)
00611 return ROTATION_270;
00612 else
00613 return ROTATION_0;
00614 }
00615
00616 void
00617 ft_render::text_to_pixels (const std::string& txt,
00618 uint8NDArray& pixels_, Matrix& box,
00619 int halign, int valign, double rotation)
00620 {
00621
00622 int rot_mode = rotation_to_mode (rotation);
00623
00624 multiline_halign = halign;
00625
00626 text_element *elt = text_parser_none ().parse (txt);
00627 pixels_ = render (elt, box, rot_mode);
00628 delete elt;
00629
00630 if (pixels_.numel () == 0)
00631 {
00632
00633 return;
00634 }
00635
00636 switch (halign)
00637 {
00638 default: box(0) = 0; break;
00639 case 1: box(0) = -box(2)/2; break;
00640 case 2: box(0) = -box(2); break;
00641 }
00642 switch (valign)
00643 {
00644 default: box(1) = 0; break;
00645 case 1: box(1) = -box(3)/2; break;
00646 case 2: box(1) = -box(3); break;
00647 case 3: break;
00648 }
00649
00650 switch (rot_mode)
00651 {
00652 case ROTATION_90:
00653 std::swap (box(0), box(1));
00654 std::swap (box(2), box(3));
00655 box(0) = -box(0)-box(2);
00656 break;
00657 case ROTATION_180:
00658 box(0) = -box(0)-box(2);
00659 box(1) = -box(1)-box(3);
00660 break;
00661 case ROTATION_270:
00662 std::swap (box(0), box(1));
00663 std::swap (box(2), box(3));
00664 box(1) = -box(1)-box(3);
00665 break;
00666 }
00667 }
00668
00669 #endif // HAVE_FREETYPE