00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #ifdef _MSC_VER
00040 # pragma warning (disable: 4786)
00041 #endif
00042
00043 #include "OSGTextFT2Backend.h"
00044 #include <OSGBaseTypes.h>
00045
00046
00047 #ifdef FT2_LIB
00048
00049
00050 #include "OSGTextPixmapFace.h"
00051 #include "OSGTextPixmapGlyph.h"
00052 #include "OSGTextVectorFace.h"
00053 #include "OSGTextVectorGlyph.h"
00054 #include "OSGTextTXFFace.h"
00055 #include "OSGTextTXFGlyph.h"
00056 #include "OSGTextLayoutParam.h"
00057 #include "OSGTextLayoutResult.h"
00058
00059 #include <iostream>
00060 #include <algorithm>
00061 #include <set>
00062 #ifdef FONTCONFIG_LIB
00063 # include <fontconfig/fontconfig.h>
00064 #else
00065 # ifdef _WIN32
00066 # include <windows.h>
00067 # else
00068 # include <dirent.h>
00069 # endif
00070 #endif
00071
00072
00073 #ifdef _MSC_VER
00074 # include <freetype/ftoutln.h>
00075 #else
00076 # include FT_OUTLINE_H
00077 #endif
00078
00079
00080 using namespace std;
00081
00082
00083 OSG_BEGIN_NAMESPACE
00084
00085
00086
00087
00088
00089
00090 class TextFT2VectorFace: public TextVectorFace
00091 {
00092 public:
00093
00094
00095 TextFT2VectorFace(FT_Face face);
00096
00097
00098 virtual ~TextFT2VectorFace();
00099
00100
00101 virtual void layout(const wstring &text, const TextLayoutParam ¶m,
00102 TextLayoutResult &layoutResult);
00103
00104 protected:
00105
00106
00107 virtual auto_ptr<TextVectorGlyph> createGlyph(TextGlyph::Index glyphIndex);
00108
00109 private:
00110
00111
00112 FT_Face _face;
00113 };
00114
00115
00116
00117
00118
00119
00120 class TextFT2VectorGlyph: public TextVectorGlyph
00121 {
00122 public:
00123
00124
00125 TextFT2VectorGlyph(Index glyphIndex, Real32 scale, FT_GlyphSlot glyphSlot);
00126
00127
00128 virtual ~TextFT2VectorGlyph();
00129 };
00130
00131
00132
00133
00134
00135
00136 class TextFT2PixmapFace: public TextPixmapFace
00137 {
00138 public:
00139
00140
00141 TextFT2PixmapFace(FT_Face face, UInt32 size);
00142
00143
00144 virtual ~TextFT2PixmapFace();
00145
00146
00147 virtual void layout(const wstring &text, const TextLayoutParam ¶m,
00148 TextLayoutResult &layoutResult);
00149
00150 protected:
00151
00152
00153 virtual auto_ptr<TextPixmapGlyph> createGlyph(TextGlyph::Index glyphIndex);
00154
00155 private:
00156
00157
00158 FT_Face _face;
00159 };
00160
00161
00162
00163
00164
00165
00166 class TextFT2PixmapGlyph: public TextPixmapGlyph
00167 {
00168 public:
00169
00170
00171 TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot);
00172
00173
00174 virtual ~TextFT2PixmapGlyph();
00175 };
00176
00177
00178
00179
00180
00181
00182 class TextFT2TXFFace: public TextTXFFace
00183 {
00184 public:
00185
00186
00187 TextFT2TXFFace(FT_Face face, const TextTXFParam ¶m);
00188
00189
00190 virtual ~TextFT2TXFFace();
00191 };
00192
00193
00194
00195
00196
00197
00198 class TextFT2TXFGlyph: public TextTXFGlyph
00199 {
00200 public:
00201
00202
00203 TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
00204 Real32 scale, FT_GlyphSlot glyphSlot);
00205
00206
00207 virtual ~TextFT2TXFGlyph();
00208 };
00209
00210
00211
00212
00213
00214
00215 TextFT2Backend::TextFT2Backend()
00216 : TextBackend(), _library(0)
00217 #ifndef FONTCONFIG_LIB
00218 ,
00219 # ifdef FONT_SEARCHPATH
00220 _pathList(FONT_SEARCHPATH),
00221 #else
00222 _pathList(),
00223 #endif
00224 _scanForFonts(true), _fontMap()
00225 #endif
00226 {
00227
00228 FT_Error error = FT_Init_FreeType(&_library);
00229 if (error)
00230
00231
00232 _library = 0;
00233
00234 #ifdef FONTCONFIG_LIB
00235
00236
00237 FcInit();
00238
00239
00240 #endif // FONTCONFIG_LIB
00241
00242 }
00243
00244
00245
00246
00247
00248
00249 TextFT2Backend::~TextFT2Backend()
00250 {
00251
00252 if (_library != 0)
00253 FT_Done_FreeType(_library);
00254
00255 #ifdef FONTCONFIG_LIB
00256
00257
00258
00259
00260
00261
00262
00263 #endif // FONTCONFIG_LIB
00264 }
00265
00266
00267
00268
00269
00270
00271 bool TextFT2Backend::findPath(const string &family, TextFace::Style style,
00272 string &path, int &index)
00273 {
00274
00275 path.erase();
00276 index = -1;
00277
00278 #ifdef FONTCONFIG_LIB
00279
00280
00281 string f;
00282 if (family == "SERIF")
00283 f = "serif";
00284 else if (family == "SANS")
00285 f = "sans-serif";
00286 else if (family == "TYPEWRITER")
00287 f = "monospace";
00288 else
00289 f = family;
00290
00291
00292 FcPattern *pattern = FcPatternCreate();
00293 if (pattern == 0)
00294 return false;
00295
00296
00297 if (FcPatternAddBool(pattern, FC_OUTLINE, FcTrue) == FcFalse)
00298 {
00299 FcPatternDestroy(pattern);
00300 return false;
00301 }
00302
00303
00304 if (FcPatternAddString(pattern, FC_FAMILY, (const FcChar8*)f.c_str()) == FcFalse)
00305 {
00306 FcPatternDestroy(pattern);
00307 return false;
00308 }
00309
00310
00311 int slant;
00312 int weight;
00313 switch (style)
00314 {
00315 default:
00316 case TextFace::STYLE_PLAIN:
00317 slant = FC_SLANT_ROMAN;
00318 weight = FC_WEIGHT_MEDIUM;
00319 break;
00320 case TextFace::STYLE_BOLD:
00321 slant = FC_SLANT_ROMAN;
00322 weight = FC_WEIGHT_BOLD;
00323 break;
00324 case TextFace::STYLE_ITALIC:
00325 slant = FC_SLANT_ITALIC;
00326 weight = FC_WEIGHT_MEDIUM;
00327 break;
00328 case TextFace::STYLE_BOLDITALIC:
00329 slant = FC_SLANT_ITALIC;
00330 weight = FC_WEIGHT_BOLD;
00331 break;
00332 }
00333 if (FcPatternAddInteger(pattern, FC_SLANT, slant) == FcFalse)
00334 {
00335 FcPatternDestroy(pattern);
00336 return false;
00337 }
00338 if (FcPatternAddInteger(pattern, FC_WEIGHT, weight) == FcFalse)
00339 {
00340 FcPatternDestroy(pattern);
00341 return false;
00342 }
00343
00344
00345 if (FcConfigSubstitute(0, pattern, FcMatchPattern) == FcFalse)
00346 {
00347 FcPatternDestroy(pattern);
00348 return false;
00349 }
00350 FcDefaultSubstitute(pattern);
00351
00352
00353 FcResult result;
00354 FcPattern *match = FcFontMatch(0, pattern, &result);
00355
00356 FcPatternDestroy(pattern);
00357 if (match == 0)
00358 return false;
00359
00360
00361 FcChar8 *pathPtr;
00362 if (FcPatternGetString(match, FC_FILE, 0, &pathPtr) != FcResultMatch)
00363 {
00364 FcPatternDestroy(match);
00365 return false;
00366 }
00367 path = (const char *)pathPtr;
00368
00369
00370 if (FcPatternGetInteger(match, FC_INDEX, 0, &index) != FcResultMatch)
00371 {
00372 FcPatternDestroy(match);
00373 return false;
00374 }
00375
00376
00377 FcPatternDestroy(match);
00378
00379 #else // !FONTCONFIG_LIB
00380
00381
00382 scanForFonts();
00383
00384
00385 FontMap::const_iterator it, bestMatchIt = _fontMap.end();
00386 pair<FontMap::const_iterator, FontMap::const_iterator> range;
00387
00388
00389 range = _fontMap.equal_range(family);
00390 for (it = range.first; it != range.second; ++it)
00391 {
00392 if (it->second.style == style)
00393 {
00394 bestMatchIt = it;
00395 break;
00396 }
00397 }
00398 if (bestMatchIt == _fontMap.end())
00399 return false;
00400 path = bestMatchIt->second.path;
00401 index = bestMatchIt->second.index;
00402
00403 #endif // !FONTCONFIG_LIB
00404
00405 return true;
00406 }
00407
00408
00409
00410
00411
00412
00413 FT_Face TextFT2Backend::createFace(const string &family, TextFace::Style style, FT_UInt size)
00414 {
00415
00416 if (_library == 0)
00417 return 0;
00418
00419
00420 string path;
00421 int index;
00422 if (findPath(family, style, path, index) == false)
00423 return 0;
00424
00425
00426 FT_Face face;
00427 FT_Error error = FT_New_Face(_library, path.c_str(), index, &face);
00428 if (error)
00429 return 0;
00430
00431
00432
00433 if(face->family_name == NULL)
00434 face->family_name = strdup(family.c_str());
00435
00436
00437
00438
00439 error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
00440
00441
00442
00443 if (size > 0)
00444 error = FT_Set_Pixel_Sizes(face, 0, size);
00445
00446
00447
00448 string::size_type pos = path.rfind('.');
00449 if (pos != string::npos)
00450 {
00451 string suffix = path.substr(pos + 1);
00452 transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
00453 if ((suffix == "pfb") || (suffix == "pfa"))
00454 {
00455 string addPath = path.substr(0, pos + 1);
00456 addPath.append("afm");
00457 error = FT_Attach_File(face, addPath.c_str());
00458
00459 }
00460 }
00461
00462 return face;
00463 }
00464
00465
00466
00467
00468
00469
00470 TextVectorFace*
00471 TextFT2Backend::createVectorFace(const string &family, TextFace::Style style)
00472 {
00473
00474 FT_Face face = createFace(family, style, 0);
00475 if (face == 0)
00476 return 0;
00477
00478
00479 return new TextFT2VectorFace(face);
00480 }
00481
00482
00483
00484
00485
00486
00487 TextPixmapFace*
00488 TextFT2Backend::createPixmapFace(const string &family, TextFace::Style style, UInt32 size)
00489 {
00490
00491 FT_Face face = createFace(family, style, size);
00492 if (face == 0)
00493 return 0;
00494
00495
00496 return new TextFT2PixmapFace(face, size);
00497 }
00498
00499
00500
00501
00502
00503
00504 TextTXFFace*
00505 TextFT2Backend::createTXFFace(const string &family, TextFace::Style style, const TextTXFParam ¶m)
00506 {
00507
00508 FT_Face face = createFace(family, style, param.size);
00509 if (face == 0)
00510 return 0;
00511
00512
00513 return new TextFT2TXFFace(face, param);
00514 }
00515
00516
00517
00518
00519
00520
00521 void TextFT2Backend::getFontFamilies(vector<string> &families)
00522 {
00523
00524 families.clear();
00525
00526 #ifdef FONTCONFIG_LIB
00527
00528
00529 FcPattern *pattern = FcPatternCreate();
00530 if (pattern == 0)
00531 return;
00532
00533
00534 FcObjectSet *objectSet = FcObjectSetBuild(FC_FAMILY, 0);
00535 if (objectSet == 0)
00536 {
00537 FcPatternDestroy(pattern);
00538 return;
00539 }
00540
00541
00542 FcFontSet *fontSet = FcFontList(0, pattern, objectSet);
00543 if (fontSet != 0)
00544 {
00545 int i;
00546 set<string> familySet;
00547 for (i = 0; i < fontSet->nfont; ++i)
00548 {
00549 FcChar8 *family;
00550 if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &family) == FcResultMatch)
00551 familySet.insert(reinterpret_cast<char*>(family));
00552 }
00553
00554
00555 families.resize(familySet.size());
00556 copy(familySet.begin(), familySet.end(), families.begin());
00557 FcFontSetDestroy(fontSet);
00558 }
00559
00560
00561 FcObjectSetDestroy(objectSet);
00562 FcPatternDestroy(pattern);
00563
00564 #else // !FONTCONFIG_LIB
00565
00566
00567 scanForFonts();
00568
00569
00570 families.reserve(_fontMap.size());
00571 FontMap::const_iterator it;
00572 for (it = _fontMap.begin(); it != _fontMap.end(); ++it)
00573 families.push_back(it->first);
00574 unique(families.begin(), families.end());
00575
00576 #endif // !FONTCONFIG_LIB
00577 }
00578
00579
00580
00581
00582
00583
00584 #ifndef FONTCONFIG_LIB
00585 void TextFT2Backend::scanForFonts()
00586 {
00587
00588 if (_scanForFonts == true)
00589 {
00590 _scanForFonts = false;
00591
00592
00593 string::size_type start = 0;
00594 while (true)
00595 {
00596 #ifdef _WIN32
00597 string::size_type end = _pathList.find(';', start);
00598 #else
00599 string::size_type end = _pathList.find(':', start);
00600 #endif
00601 string path = end == string::npos ? _pathList.substr(start) : _pathList.substr(start, end - start);
00602
00603
00604 string::size_type wsPos = path.find_first_not_of(" \t\r\n");
00605 if (wsPos != string::npos)
00606 {
00607 path.erase(0, wsPos);
00608 wsPos = path.find_last_not_of(" \t\r\n");
00609 path.erase(wsPos + 1);
00610
00611
00612 scanDir(path);
00613 }
00614
00615 if (end == string::npos)
00616 break;
00617 start = end + 1;
00618 }
00619 }
00620 }
00621 #endif // !FONTCONFIG_LIB
00622
00623
00624
00625
00626
00627
00628 #ifndef FONTCONFIG_LIB
00629 void TextFT2Backend::scanDir(const string &path)
00630 {
00631 #ifdef _WIN32
00632
00633
00634 string p = path;
00635 if ((p.length() < 1) || ((p[p.length() - 1] != '/') && (p[p.length() - 1] != '\\')))
00636 p.append(1, '\\');
00637
00638
00639 string pattern = p;
00640 pattern.append(1, '*');
00641 WIN32_FIND_DATA findFileData;
00642 HANDLE hFind = FindFirstFile(pattern.c_str(), &findFileData);
00643 if (hFind == INVALID_HANDLE_VALUE)
00644 return;
00645
00646 while (true)
00647 {
00648
00649 string name = findFileData.cFileName;
00650 string fullname = p;
00651 fullname.append(name);
00652
00653 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
00654 {
00655
00656 if ((name != ".") && (name != ".."))
00657 scanDir(fullname);
00658 }
00659 else
00660
00661 checkFile(fullname);
00662
00663
00664 if (FindNextFile(hFind, &findFileData) == FALSE)
00665 break;
00666 }
00667
00668
00669 FindClose(hFind);
00670
00671 #else // !_WIN32
00672
00673
00674 DIR *dir = opendir(path.c_str());
00675 if (dir == 0)
00676 return;
00677
00678
00679 string p = path;
00680 if ((p.length() < 1) || (p[p.length() - 1] != '/'))
00681 p.append(1, '/');
00682
00683 struct dirent entry, *result;
00684 while (true)
00685 {
00686
00687 if (readdir_r(dir, &entry, &result) != 0)
00688 return;
00689 if (result == 0)
00690 break;
00691
00692
00693 string name = entry.d_name;
00694 string fullname = p;
00695 fullname.append(name);
00696 switch (entry.d_type)
00697 {
00698 case DT_DIR:
00699
00700 if ((name != ".") && (name != ".."))
00701 scanDir(fullname);
00702 break;
00703 case DT_REG:
00704
00705 checkFile(fullname);
00706 break;
00707 default:
00708 break;
00709 }
00710 }
00711
00712
00713 closedir(dir);
00714
00715 #endif // !_WIN32
00716
00717 }
00718 #endif // !FONTCONFIG_LIB
00719
00720
00721
00722
00723
00724
00725 #ifndef FONTCONFIG_LIB
00726 void TextFT2Backend::checkFile(const string &fullname)
00727 {
00728
00729 FT_Long index = 0;
00730 FT_Long numFaces = 1;
00731 while (index < numFaces)
00732 {
00733 FT_Face face;
00734 FT_Error error = FT_New_Face(_library, fullname.c_str(), index, &face);
00735 if (error)
00736 break;
00737
00738
00739 numFaces = face->num_faces;
00740 FontInfo fontInfo;
00741 fontInfo.path = fullname;
00742 fontInfo.index = index;
00743 if (face->style_flags & FT_STYLE_FLAG_BOLD)
00744 fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
00745 else
00746 fontInfo.style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
00747 string family = face->family_name;
00748
00749 _fontMap.insert(FontMap::value_type(family, fontInfo));
00750 FT_Done_Face(face);
00751
00752 ++index;
00753 }
00754 }
00755 #endif // !FONTCONFIG_LIB
00756
00757
00758
00759
00760
00761
00762 static void getFaceInfo(FT_Face face, string &family, TextFace::Style &style)
00763 {
00764
00765 family = face->family_name;
00766
00767
00768 if (face->style_flags & FT_STYLE_FLAG_BOLD)
00769 style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_BOLDITALIC : TextFace::STYLE_BOLD;
00770 else
00771 style = face->style_flags & FT_STYLE_FLAG_ITALIC ? TextFace::STYLE_ITALIC : TextFace::STYLE_PLAIN;
00772 }
00773
00774
00775
00776
00777
00778
00779 TextFT2VectorFace::TextFT2VectorFace(FT_Face face)
00780 : TextVectorFace(), _face(face)
00781 {
00782
00783 getFaceInfo(_face, _family, _style);
00784
00785
00786 _scale = 1.f / static_cast<Real32>(_face->ascender - _face->descender);
00787
00788
00789 _horiAscent = static_cast<Real32>(_face->ascender) * _scale;
00790 _vertAscent = -0.5f;
00791
00792
00793 _horiDescent = static_cast<Real32>(_face->descender) * _scale;
00794 _vertDescent = 0.5f;
00795 }
00796
00797
00798
00799
00800
00801
00802 TextFT2VectorFace::~TextFT2VectorFace()
00803 {
00804
00805 FT_Done_Face(_face);
00806 }
00807
00808
00809
00810
00811
00812
00813 void TextFT2VectorFace::layout(const wstring &text, const TextLayoutParam ¶m,
00814 TextLayoutResult &layoutResult)
00815 {
00816
00817 layoutResult.clear();
00818
00819
00820 FT_UInt previousGlyphIndex = 0;
00821 Vec2f currPos;
00822 size_t i, len = text.length();
00823 layoutResult.indices.reserve(len);
00824 layoutResult.positions.reserve(len);
00825 vector<UInt32> spaceIndices;
00826 bool justify = param.getLength(0) > 0.f;
00827 for (i = 0; i < len; ++i)
00828 {
00829
00830 FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
00831 const TextGlyph &glyph = getGlyph(glyphIndex);
00832 if ((justify == true) && (text[i] == ' '))
00833 spaceIndices.push_back(layoutResult.indices.size());
00834
00835
00836 Vec2f pos;
00837 if (param.horizontal == true)
00838 {
00839 if (param.leftToRight == true)
00840 {
00841 FT_Vector kerning;
00842 FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_unscaled, &kerning);
00843 currPos[0] += static_cast<float>(kerning.x) * _scale;
00844 pos = currPos;
00845 pos[0] += glyph.getHoriBearingX();
00846 pos[1] += glyph.getHoriBearingY();
00847 currPos[0] += glyph.getHoriAdvance();
00848 }
00849 else
00850 {
00851 FT_Vector kerning;
00852 FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_unscaled, &kerning);
00853 currPos[0] -= static_cast<float>(kerning.x) * _scale + glyph.getHoriAdvance();
00854 pos = currPos;
00855 pos[0] += glyph.getHoriBearingX();
00856 pos[1] += glyph.getHoriBearingY();
00857 }
00858 previousGlyphIndex = glyphIndex;
00859 }
00860 else
00861 {
00862 if (param.topToBottom == true)
00863 {
00864 pos = currPos;
00865 pos[0] += glyph.getVertBearingX();
00866 pos[1] += glyph.getVertBearingY();
00867 currPos[1] += glyph.getVertAdvance();
00868 }
00869 else
00870 {
00871 currPos[1] -= glyph.getVertAdvance();
00872 pos = currPos;
00873 pos[0] += glyph.getVertBearingX();
00874 pos[1] += glyph.getVertBearingY();
00875 }
00876 }
00877
00878 layoutResult.indices.push_back(glyphIndex);
00879 layoutResult.positions.push_back(pos);
00880 }
00881
00882
00883 if (justify == true)
00884 justifyLine(param, spaceIndices, currPos, layoutResult);
00885
00886
00887 adjustLineOrigin(param, currPos, layoutResult);
00888
00889
00890 if (param.horizontal == true)
00891 layoutResult.textBounds.setValues(osgabs(currPos.x()), _horiAscent - _horiDescent);
00892 else
00893 layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgabs(currPos.y()));
00894 layoutResult.lineBounds.push_back(layoutResult.textBounds);
00895 }
00896
00897
00898
00899
00900
00901
00902 typedef struct UserData
00903 {
00904 Real32 scale;
00905 Vec2f offset;
00906 TextVectorGlyph::Outline &outline;
00907 inline UserData(Real32 s, const Vec2f &off, TextVectorGlyph::Outline &o)
00908 : scale(s), offset(off), outline(o)
00909 {}
00910 }
00911 UserData;
00912
00913
00914
00915
00916
00917
00918 static int moveToFunc(FT_Vector *to, void *user)
00919 {
00920 UserData *userData = reinterpret_cast<UserData*>(user);
00921
00922
00923
00924 if (userData->outline.empty() == false)
00925 if (userData->outline.back().size() < 3)
00926 userData->outline.erase(userData->outline.end() - 1);
00927
00928
00929 userData->outline.push_back(TextVectorGlyph::Contour());
00930
00931
00932 Vec2f p(to->x, to->y);
00933 p *= userData->scale;
00934 p -= userData->offset;
00935 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00936
00937
00938 return 0;
00939 }
00940
00941
00942
00943
00944
00945
00946 static int lineToFunc(FT_Vector *to, void *user)
00947 {
00948 UserData *userData = reinterpret_cast<UserData*>(user);
00949
00950
00951 Vec2f p(to->x, to->y);
00952 p *= userData->scale;
00953 p -= userData->offset;
00954 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00955
00956
00957 return 0;
00958 }
00959
00960
00961
00962
00963
00964
00965 static int conicToFunc(FT_Vector *control, FT_Vector *to, void *user)
00966 {
00967 UserData *userData = reinterpret_cast<UserData*>(user);
00968
00969
00970 Vec2f p(control->x, control->y);
00971 p *= userData->scale;
00972 p -= userData->offset;
00973 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_QUAD));
00974 p.setValues(to->x, to->y);
00975 p *= userData->scale;
00976 p -= userData->offset;
00977 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
00978
00979
00980 return 0;
00981 }
00982
00983
00984
00985
00986
00987
00988 static int cubicToFunc(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *user)
00989 {
00990 UserData *userData = reinterpret_cast<UserData*>(user);
00991
00992
00993 Vec2f p(control1->x, control1->y);
00994 p *= userData->scale;
00995 p -= userData->offset;
00996 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
00997 p.setValues(control2->x, control2->y);
00998 p *= userData->scale;
00999 p -= userData->offset;
01000 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_CUBIC));
01001 p.setValues(to->x, to->y);
01002 p *= userData->scale;
01003 p -= userData->offset;
01004 userData->outline.back().push_back(TextVectorGlyph::Point(p, TextVectorGlyph::Point::PT_ON));
01005
01006
01007 return 0;
01008 }
01009
01010
01011
01012
01013
01014
01015 auto_ptr<TextVectorGlyph> TextFT2VectorFace::createGlyph(TextGlyph::Index glyphIndex)
01016 {
01017
01018 if (glyphIndex == TextGlyph::INVALID_INDEX)
01019 return auto_ptr<TextVectorGlyph>();
01020
01021
01022 FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_NO_SCALE);
01023 if (error)
01024 return auto_ptr<TextVectorGlyph>();
01025
01026
01027 FT_GlyphSlot glyphSlot = _face->glyph;
01028 if (glyphSlot->format != ft_glyph_format_outline)
01029 return auto_ptr<TextVectorGlyph>();
01030
01031
01032 return auto_ptr<TextVectorGlyph>(new TextFT2VectorGlyph(glyphIndex, _scale, glyphSlot));
01033 }
01034
01035
01036
01037
01038
01039
01040 TextFT2VectorGlyph::TextFT2VectorGlyph(Index glyphIndex, float scale, FT_GlyphSlot glyphSlot)
01041 : TextVectorGlyph()
01042 {
01043 _glyphIndex = glyphIndex;
01044 _width = static_cast<Real32>(glyphSlot->metrics.width) * scale;
01045 _height = static_cast<Real32>(glyphSlot->metrics.height) * scale;
01046
01047
01048 _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) * scale;
01049 _horiBearingX = static_cast<Real32>(glyphSlot->metrics.horiBearingX) * scale;
01050 _horiBearingY = static_cast<Real32>(glyphSlot->metrics.horiBearingY) * scale;
01051
01052
01053
01054
01055
01056
01057
01058 _vertAdvance = -_height - 1.f / 10.f;
01059 _vertBearingX = -_width / 2.f;
01060 _vertBearingY = -1.f / 20.f;
01061
01062
01063 FT_Outline_Funcs func_interface =
01064 {
01065 moveToFunc,
01066 lineToFunc,
01067 conicToFunc,
01068 cubicToFunc,
01069 0,
01070 0
01071 };
01072 UserData userData(scale, Vec2f(_horiBearingX, _horiBearingY), _outline);
01073 FT_Outline_Decompose(&(glyphSlot->outline), &func_interface, &userData);
01074
01075
01076
01077 if (_outline.empty() == false)
01078 if (_outline.back().size() < 3)
01079 _outline.erase(_outline.end() - 1);
01080 }
01081
01082
01083
01084
01085
01086
01087 TextFT2VectorGlyph::~TextFT2VectorGlyph() {}
01088
01089
01090
01091
01092
01093
01094 TextFT2PixmapFace::TextFT2PixmapFace(FT_Face face, UInt32 size)
01095 : TextPixmapFace(), _face(face)
01096 {
01097
01098 getFaceInfo(_face, _family, _style);
01099
01100
01101 _size = size;
01102
01103
01104 _horiAscent = static_cast<Real32>(_face->size->metrics.ascender) / 64.f;
01105 _vertAscent = -static_cast<Real32>(_size) / 2.f;
01106
01107
01108 _horiDescent = static_cast<Real32>(_face->size->metrics.descender) / 64.f;
01109 _vertDescent = static_cast<Real32>(_size) / 2.f;
01110 }
01111
01112
01113
01114
01115
01116
01117 TextFT2PixmapFace::~TextFT2PixmapFace()
01118 {
01119
01120 FT_Done_Face(_face);
01121 }
01122
01123
01124
01125
01126
01127
01128 void TextFT2PixmapFace::layout(const wstring &text, const TextLayoutParam ¶m,
01129 TextLayoutResult &layoutResult)
01130 {
01131
01132 layoutResult.clear();
01133
01134
01135 FT_UInt previousGlyphIndex = 0;
01136 Vec2f currPos;
01137 size_t i, len = text.length();
01138 layoutResult.indices.reserve(len);
01139 layoutResult.positions.reserve(len);
01140 vector<UInt32> spaceIndices;
01141 bool justify = param.getLength(0) > 0.f;
01142 for (i = 0; i < len; ++i)
01143 {
01144
01145 FT_UInt glyphIndex = FT_Get_Char_Index(_face, text[i]);
01146 const TextGlyph &glyph = getGlyph(glyphIndex);
01147 if ((justify == true) && (text[i] == ' '))
01148 spaceIndices.push_back(layoutResult.indices.size());
01149
01150
01151 Vec2f pos;
01152 if (param.horizontal == true)
01153 {
01154 if (param.leftToRight == true)
01155 {
01156 FT_Vector kerning;
01157 FT_Get_Kerning(_face, previousGlyphIndex, glyphIndex, ft_kerning_default, &kerning);
01158 currPos[0] += static_cast<float>(kerning.x) / 64.f;
01159 pos[0] = currPos.x() + glyph.getHoriBearingX();
01160 pos[1] = currPos.y() + glyph.getHoriBearingY();
01161 currPos[0] += glyph.getHoriAdvance();
01162 }
01163 else
01164 {
01165 FT_Vector kerning;
01166 FT_Get_Kerning(_face, glyphIndex, previousGlyphIndex, ft_kerning_default, &kerning);
01167 currPos[0] -= static_cast<float>(kerning.x) / 64.f + glyph.getHoriAdvance();
01168 pos[0] = currPos[0] + glyph.getHoriBearingX();
01169 pos[1] = currPos[1] + glyph.getHoriBearingY();
01170 }
01171 previousGlyphIndex = glyphIndex;
01172 }
01173 else
01174 {
01175 if (param.topToBottom == true)
01176 {
01177 pos[0] = currPos.x() + glyph.getVertBearingX();
01178 pos[1] = currPos.y() + glyph.getVertBearingY();
01179 currPos[1] += glyph.getVertAdvance();
01180 }
01181 else
01182 {
01183 currPos[1] -= glyph.getVertAdvance();
01184 pos[0] = currPos.x() + glyph.getVertBearingX();
01185 pos[1] = currPos.y() + glyph.getVertBearingY();
01186 }
01187 }
01188
01189 layoutResult.indices.push_back(glyphIndex);
01190 layoutResult.positions.push_back(pos);
01191 }
01192
01193
01194 if (justify == true)
01195 justifyLine(param, spaceIndices, currPos, layoutResult);
01196
01197
01198 adjustLineOrigin(param, currPos, layoutResult);
01199
01200
01201 if (param.horizontal == true)
01202 layoutResult.textBounds.setValues(osgabs(currPos.x()), _horiAscent - _horiDescent);
01203 else
01204 layoutResult.textBounds.setValues(_vertDescent - _vertAscent, osgabs(currPos.y()));
01205 layoutResult.lineBounds.push_back(layoutResult.textBounds);
01206 }
01207
01208
01209
01210
01211
01212
01213 auto_ptr<TextPixmapGlyph> TextFT2PixmapFace::createGlyph(TextGlyph::Index glyphIndex)
01214 {
01215
01216 if (glyphIndex == TextGlyph::INVALID_INDEX)
01217 return auto_ptr<TextPixmapGlyph>();
01218
01219
01220 FT_Error error = FT_Load_Glyph(_face, glyphIndex, FT_LOAD_DEFAULT);
01221 if (error)
01222 return auto_ptr<TextPixmapGlyph>();
01223
01224
01225 FT_GlyphSlot glyphSlot = _face->glyph;
01226 if (glyphSlot->format != ft_glyph_format_bitmap)
01227 {
01228 error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal);
01229 if (error)
01230 return auto_ptr<TextPixmapGlyph>();
01231 }
01232
01233
01234 return auto_ptr<TextPixmapGlyph>(new TextFT2PixmapGlyph(glyphIndex, this, glyphSlot));
01235 }
01236
01237
01238
01239
01240
01241
01242 TextFT2PixmapGlyph::TextFT2PixmapGlyph(Index glyphIndex, TextFT2PixmapFace *face, FT_GlyphSlot glyphSlot)
01243 : TextPixmapGlyph()
01244 {
01245 _glyphIndex = glyphIndex;
01246 _width = glyphSlot->bitmap.width;
01247 _pitch = glyphSlot->bitmap.pitch;
01248 _height = glyphSlot->bitmap.rows;
01249
01250
01251 _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f;
01252 _horiBearingX = glyphSlot->bitmap_left;
01253 _horiBearingY = glyphSlot->bitmap_top;
01254
01255
01256
01257
01258
01259
01260
01261 _vertBearingX = -static_cast<Int32>(_width >> 1);
01262 _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / 20.f);
01263 if (_vertBearingY > -1)
01264 _vertBearingY = -1;
01265 Int32 vertAdvanceOffset = _vertBearingY << 1;
01266 _vertAdvance = -static_cast<Int32>(_height) + vertAdvanceOffset;
01267
01268 unsigned int size = glyphSlot->bitmap.pitch * glyphSlot->bitmap.rows;
01269 if ((size == 0) || (glyphSlot->bitmap.buffer == 0))
01270 _pixmap = 0;
01271 else
01272 {
01273 _pixmap = new unsigned char[size];
01274 memcpy(_pixmap, glyphSlot->bitmap.buffer, size);
01275 flipPixmap();
01276 }
01277 }
01278
01279
01280
01281
01282
01283
01284 TextFT2PixmapGlyph::~TextFT2PixmapGlyph() {}
01285
01286
01287
01288
01289
01290
01291 TextFT2TXFFace::TextFT2TXFFace(FT_Face face, const TextTXFParam ¶m)
01292 {
01293
01294 getFaceInfo(face, _family, _style);
01295
01296
01297 _param = param;
01298
01299
01300 _horiAscent = static_cast<Real32>(face->size->metrics.ascender) / 64.f;
01301 _vertAscent = -0.5f;
01302
01303
01304 _horiDescent = static_cast<Real32>(face->size->metrics.descender) / 64.f;
01305 _vertDescent = 0.5f;
01306
01307
01308 _scale = 1.f / (_horiAscent - _horiDescent);
01309 _horiAscent *= _scale;
01310 _horiDescent *= _scale;
01311
01312
01313 wstring::const_iterator it;
01314 for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
01315 {
01316 FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
01317 if (glyphIndex == 0)
01318 continue;
01319 FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
01320 if (error)
01321 continue;
01322 FT_GlyphSlot glyphSlot = face->glyph;
01323 if (glyphSlot->format != ft_glyph_format_bitmap)
01324 {
01325 error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal);
01326 if (error)
01327 continue;
01328 }
01329 _glyphMap.insert(GlyphMap::value_type(*it, new TextFT2TXFGlyph(*it, this, _scale, face->glyph)));
01330 }
01331
01332
01333 prepareTexture(param);
01334 assert(_texture != NullFC);
01335 assert(_texture->getSize() == static_cast<UInt32>(_texture->getWidth() * _texture->getHeight()));
01336
01337
01338 beginEditCP(_texture);
01339 for (it = param.getCharacters().begin(); it != param.getCharacters().end(); ++it)
01340 {
01341 GlyphMap::iterator gIt = _glyphMap.find(*it);
01342 if (gIt == _glyphMap.end())
01343 continue;
01344 assert(gIt->second != 0);
01345 TextTXFGlyph *glyph = gIt->second;
01346 FT_UInt glyphIndex = FT_Get_Char_Index(face, *it);
01347 if (glyphIndex == 0)
01348 continue;
01349 FT_Error error = FT_Load_Glyph(face, glyphIndex, FT_LOAD_DEFAULT);
01350 if (error)
01351 continue;
01352 FT_GlyphSlot glyphSlot = face->glyph;
01353 if (glyphSlot->format != ft_glyph_format_bitmap)
01354 {
01355 error = FT_Render_Glyph(glyphSlot, ft_render_mode_normal);
01356 if (error)
01357 continue;
01358 }
01359 unsigned char *src = glyphSlot->bitmap.buffer;
01360 if (src == 0)
01361 continue;
01362 int bpl = glyphSlot->bitmap.pitch;
01363 src += bpl * (glyph->getPixmapHeight() - 1);
01364 unsigned char *src2;
01365 UInt8 *dst = _texture->getData() + glyph->getX() + glyph->getY() * _texture->getWidth();
01366 UInt32 dstPitch = _texture->getWidth() - glyph->getPixmapWidth();
01367 UInt32 x, y;
01368 for (y = 0; y < glyph->getPixmapHeight(); ++y)
01369 {
01370 src2 = src;
01371 for (x = 0; x < glyph->getPixmapWidth(); ++x)
01372 *dst++ = *src2++;
01373 src -= bpl;
01374 dst += dstPitch;
01375 }
01376 }
01377 beginEditCP(_texture);
01378
01379
01380 FT_Done_Face(face);
01381 }
01382
01383
01384
01385
01386
01387
01388 TextFT2TXFFace::~TextFT2TXFFace() {}
01389
01390
01391
01392
01393
01394
01395 TextFT2TXFGlyph::TextFT2TXFGlyph(Index glyphIndex, TextFT2TXFFace *face,
01396 Real32 scale, FT_GlyphSlot glyphSlot)
01397 : TextTXFGlyph()
01398 {
01399 _glyphIndex = glyphIndex;
01400 _scale = scale;
01401 _width = glyphSlot->bitmap.width;
01402 _height = glyphSlot->bitmap.rows;
01403
01404
01405 _horiAdvance = static_cast<Real32>(glyphSlot->metrics.horiAdvance) / 64.f * _scale;
01406 _horiBearingX = glyphSlot->bitmap_left;
01407 _horiBearingY = glyphSlot->bitmap_top;
01408
01409
01410
01411
01412
01413
01414
01415 _vertBearingX = -static_cast<Int32>(_width >> 1);
01416 if (glyphIndex == 32)
01417 {
01418 _vertBearingY = -_horiBearingX;
01419 _vertAdvance = -_horiAdvance;
01420 }
01421 else
01422 {
01423 _vertBearingY = static_cast<Int32>(-(face->getHoriAscent() - face->getHoriDescent()) / _scale / 20.f);
01424 if (_vertBearingY > -1)
01425 _vertBearingY = -1;
01426 Real32 vertAdvanceOffset = static_cast<Real32>(_vertBearingY) * 2.f * _scale;
01427 _vertAdvance = -static_cast<Real32>(_height) * _scale + vertAdvanceOffset;
01428 }
01429 }
01430
01431
01432
01433
01434
01435
01436 TextFT2TXFGlyph::~TextFT2TXFGlyph() {}
01437
01438
01439 OSG_END_NAMESPACE
01440
01441
01442 #endif // FT2_LIB
01443
01444
01445
01446
01447
01448 #ifdef OSG_SGI_CC
01449 #pragma set woff 1174
01450 #endif
01451
01452 #ifdef OSG_LINUX_ICC
01453 #pragma warning( disable : 177 )
01454 #endif
01455
01456 namespace
01457 {
01458 static OSG::Char8 cvsid_cpp[] = "@(#)$Id: OSGTextFT2Backend.cpp,v 1.3 2005/06/29 21:10:43 dirk Exp $";
01459 static OSG::Char8 cvsid_hpp[] = OSGTEXTFT2BACKEND_HEADER_CVSID;
01460 static OSG::Char8 cvsid_inl[] = OSGTEXTFT2BACKEND_INLINE_CVSID;
01461 }
01462
01463 #ifdef __sgi
01464 #pragma reset woff 1174
01465 #endif