| 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | #include "FreeTypeLibrary.h" |
|---|
| 15 | #include <osg/Notify> |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| 19 | #ifdef PRINT_OUT_FONT_DETAILS |
|---|
| 20 | #include <ftsnames.h> |
|---|
| 21 | #endif |
|---|
| 22 | |
|---|
| 23 | #include FT_TRUETYPE_IDS_H |
|---|
| 24 | |
|---|
| 25 | FreeTypeLibrary::FreeTypeLibrary() |
|---|
| 26 | { |
|---|
| 27 | osg::notify(osg::INFO) << "FreeTypeLibrary::FreeTypeLibrary()" << std::endl; |
|---|
| 28 | FT_Error error = FT_Init_FreeType( &_ftlibrary ); |
|---|
| 29 | if (error) |
|---|
| 30 | { |
|---|
| 31 | osg::notify(osg::WARN)<<"Warning: an error occurred during FT_Init_FreeType(..) initialisation, error code = "<<std::hex<<error<<std::dec<<std::endl; |
|---|
| 32 | } |
|---|
| 33 | |
|---|
| 34 | } |
|---|
| 35 | |
|---|
| 36 | FreeTypeLibrary::~FreeTypeLibrary() |
|---|
| 37 | { |
|---|
| 38 | |
|---|
| 39 | |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | while(!_fontImplementationSet.empty()) |
|---|
| 44 | { |
|---|
| 45 | FreeTypeFont* fontImplementation = *_fontImplementationSet.begin(); |
|---|
| 46 | _fontImplementationSet.erase(_fontImplementationSet.begin()); |
|---|
| 47 | osgText::Font* font = fontImplementation->_facade; |
|---|
| 48 | if (font) font->setImplementation(0); |
|---|
| 49 | else fontImplementation->_facade = 0; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | while(!_font3DImplementationSet.empty()) |
|---|
| 53 | { |
|---|
| 54 | FreeTypeFont3D* font3DImplementation = *_font3DImplementationSet.begin(); |
|---|
| 55 | _font3DImplementationSet.erase(_font3DImplementationSet.begin()); |
|---|
| 56 | osgText::Font3D* font3D = font3DImplementation->_facade; |
|---|
| 57 | if (font3D) font3D->setImplementation(0); |
|---|
| 58 | else font3DImplementation->_facade = 0; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | FT_Done_FreeType( _ftlibrary); |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | FreeTypeLibrary* FreeTypeLibrary::instance() |
|---|
| 65 | { |
|---|
| 66 | static osg::ref_ptr<FreeTypeLibrary> s_library = new FreeTypeLibrary; |
|---|
| 67 | return s_library.get(); |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | bool FreeTypeLibrary::getFace(const std::string& fontfile,unsigned int index, FT_Face & face) |
|---|
| 71 | { |
|---|
| 72 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 73 | |
|---|
| 74 | FT_Error error = FT_New_Face( _ftlibrary, fontfile.c_str(), index, &face ); |
|---|
| 75 | if (error == FT_Err_Unknown_File_Format) |
|---|
| 76 | { |
|---|
| 77 | osg::notify(osg::WARN)<<" .... the font file could be opened and read, but it appears"<<std::endl; |
|---|
| 78 | osg::notify(osg::WARN)<<" .... that its font format is unsupported"<<std::endl; |
|---|
| 79 | return false; |
|---|
| 80 | } |
|---|
| 81 | else if (error) |
|---|
| 82 | { |
|---|
| 83 | osg::notify(osg::WARN)<<" .... another error code means that the font file could not"<<std::endl; |
|---|
| 84 | osg::notify(osg::WARN)<<" .... be opened, read or simply that it is broken.."<<std::endl; |
|---|
| 85 | return false; |
|---|
| 86 | } |
|---|
| 87 | |
|---|
| 88 | #ifdef PRINT_OUT_FONT_DETAILS |
|---|
| 89 | |
|---|
| 90 | osg::notify(osg::NOTICE)<<"Face"<<face<<std::endl; |
|---|
| 91 | unsigned int count = FT_Get_Sfnt_Name_Count(face); |
|---|
| 92 | for(unsigned int i=0; i<count; ++i) |
|---|
| 93 | { |
|---|
| 94 | FT_SfntName names; |
|---|
| 95 | FT_Error error = FT_Get_Sfnt_Name(face, i, &names); |
|---|
| 96 | |
|---|
| 97 | std::string name((char*)names.string, (char*)names.string + names.string_len); |
|---|
| 98 | |
|---|
| 99 | osg::notify(osg::NOTICE)<<"names "<<name<<std::endl; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | osg::notify(osg::NOTICE)<<std::endl; |
|---|
| 103 | #endif |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | |
|---|
| 108 | verifyCharacterMap(face); |
|---|
| 109 | |
|---|
| 110 | return true; |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | FT_Byte* FreeTypeLibrary::getFace(std::istream& fontstream, unsigned int index, FT_Face & face) |
|---|
| 114 | { |
|---|
| 115 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 116 | |
|---|
| 117 | FT_Open_Args args; |
|---|
| 118 | |
|---|
| 119 | std::streampos start = fontstream.tellg(); |
|---|
| 120 | fontstream.seekg(0, std::ios::end); |
|---|
| 121 | std::streampos end = fontstream.tellg(); |
|---|
| 122 | fontstream.seekg(start, std::ios::beg); |
|---|
| 123 | std::streampos length = end - start; |
|---|
| 124 | |
|---|
| 125 | |
|---|
| 126 | FT_Byte *buffer = new FT_Byte[length]; |
|---|
| 127 | fontstream.read(reinterpret_cast<char*>(buffer), length); |
|---|
| 128 | if (!fontstream || (static_cast<std::streampos>(fontstream.gcount()) != length)) |
|---|
| 129 | { |
|---|
| 130 | osg::notify(osg::WARN)<<" .... the font file could not be read from its stream"<<std::endl; |
|---|
| 131 | return 0; |
|---|
| 132 | } |
|---|
| 133 | args.flags = FT_OPEN_MEMORY; |
|---|
| 134 | args.memory_base = buffer; |
|---|
| 135 | args.memory_size = length; |
|---|
| 136 | |
|---|
| 137 | FT_Error error = FT_Open_Face( _ftlibrary, &args, index, &face ); |
|---|
| 138 | |
|---|
| 139 | if (error == FT_Err_Unknown_File_Format) |
|---|
| 140 | { |
|---|
| 141 | osg::notify(osg::WARN)<<" .... the font file could be opened and read, but it appears"<<std::endl; |
|---|
| 142 | osg::notify(osg::WARN)<<" .... that its font format is unsupported"<<std::endl; |
|---|
| 143 | return 0; |
|---|
| 144 | } |
|---|
| 145 | else if (error) |
|---|
| 146 | { |
|---|
| 147 | osg::notify(osg::WARN)<<" .... another error code means that the font file could not"<<std::endl; |
|---|
| 148 | osg::notify(osg::WARN)<<" .... be opened, read or simply that it is broken..."<<std::endl; |
|---|
| 149 | return 0; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | |
|---|
| 155 | verifyCharacterMap(face); |
|---|
| 156 | |
|---|
| 157 | return buffer; |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | osgText::Font* FreeTypeLibrary::getFont(const std::string& fontfile, unsigned int index, unsigned int flags) |
|---|
| 162 | { |
|---|
| 163 | FT_Face face; |
|---|
| 164 | if (getFace(fontfile, index, face) == false) return (0); |
|---|
| 165 | |
|---|
| 166 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 167 | |
|---|
| 168 | FreeTypeFont* fontImp = new FreeTypeFont(fontfile,face,flags); |
|---|
| 169 | osgText::Font* font = new osgText::Font(fontImp); |
|---|
| 170 | |
|---|
| 171 | _fontImplementationSet.insert(fontImp); |
|---|
| 172 | |
|---|
| 173 | return font; |
|---|
| 174 | } |
|---|
| 175 | osgText::Font* FreeTypeLibrary::getFont(std::istream& fontstream, unsigned int index, unsigned int flags) |
|---|
| 176 | { |
|---|
| 177 | FT_Face face = 0; |
|---|
| 178 | FT_Byte * buffer = getFace(fontstream, index, face); |
|---|
| 179 | if (face == 0) return (0); |
|---|
| 180 | |
|---|
| 181 | |
|---|
| 182 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 183 | |
|---|
| 184 | FreeTypeFont* fontImp = new FreeTypeFont(buffer,face,flags); |
|---|
| 185 | osgText::Font* font = new osgText::Font(fontImp); |
|---|
| 186 | |
|---|
| 187 | _fontImplementationSet.insert(fontImp); |
|---|
| 188 | |
|---|
| 189 | return font; |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | osgText::Font3D* FreeTypeLibrary::getFont3D(const std::string& fontfile, unsigned int index, unsigned int flags) |
|---|
| 193 | { |
|---|
| 194 | FT_Face face; |
|---|
| 195 | if (getFace(fontfile, index, face) == false) return (0); |
|---|
| 196 | |
|---|
| 197 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 198 | |
|---|
| 199 | FreeTypeFont3D* font3DImp = new FreeTypeFont3D(fontfile,face,flags); |
|---|
| 200 | osgText::Font3D* font3D = new osgText::Font3D(font3DImp); |
|---|
| 201 | |
|---|
| 202 | _font3DImplementationSet.insert(font3DImp); |
|---|
| 203 | |
|---|
| 204 | return font3D; |
|---|
| 205 | } |
|---|
| 206 | osgText::Font3D* FreeTypeLibrary::getFont3D(std::istream& fontstream, unsigned int index, unsigned int flags) |
|---|
| 207 | { |
|---|
| 208 | |
|---|
| 209 | FT_Face face = 0; |
|---|
| 210 | FT_Byte * buffer = getFace(fontstream, index, face); |
|---|
| 211 | if (face == 0) return (0); |
|---|
| 212 | |
|---|
| 213 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getMutex()); |
|---|
| 214 | |
|---|
| 215 | FreeTypeFont3D* font3DImp = new FreeTypeFont3D(buffer,face,flags); |
|---|
| 216 | osgText::Font3D* font3D = new osgText::Font3D(font3DImp); |
|---|
| 217 | |
|---|
| 218 | _font3DImplementationSet.insert(font3DImp); |
|---|
| 219 | |
|---|
| 220 | return font3D; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | void FreeTypeLibrary::verifyCharacterMap(FT_Face face) |
|---|
| 224 | { |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | FT_CharMap charmap; |
|---|
| 230 | if (face->charmap == NULL) |
|---|
| 231 | { |
|---|
| 232 | for (int n = 0; n < face->num_charmaps; n++) |
|---|
| 233 | { |
|---|
| 234 | charmap = face->charmaps[n]; |
|---|
| 235 | if (charmap->platform_id == TT_PLATFORM_MICROSOFT) |
|---|
| 236 | { |
|---|
| 237 | FT_Set_Charmap(face, charmap); |
|---|
| 238 | break; |
|---|
| 239 | } |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | } |
|---|