dynamic_font.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149
  1. /*************************************************************************/
  2. /* dynamic_font.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifdef FREETYPE_ENABLED
  31. #include "dynamic_font.h"
  32. #include "core/os/file_access.h"
  33. #include "core/os/os.h"
  34. #include FT_STROKER_H
  35. #define __STDC_LIMIT_MACROS
  36. #include <stdint.h>
  37. bool DynamicFontData::CacheID::operator<(CacheID right) const {
  38. return key < right.key;
  39. }
  40. Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(CacheID p_cache_id) {
  41. if (size_cache.has(p_cache_id)) {
  42. return Ref<DynamicFontAtSize>(size_cache[p_cache_id]);
  43. }
  44. Ref<DynamicFontAtSize> dfas;
  45. dfas.instance();
  46. dfas->font = Ref<DynamicFontData>(this);
  47. size_cache[p_cache_id] = dfas.ptr();
  48. dfas->id = p_cache_id;
  49. dfas->_load();
  50. return dfas;
  51. }
  52. void DynamicFontData::set_font_ptr(const uint8_t *p_font_mem, int p_font_mem_size) {
  53. font_mem = p_font_mem;
  54. font_mem_size = p_font_mem_size;
  55. }
  56. void DynamicFontData::set_font_path(const String &p_path) {
  57. font_path = p_path;
  58. }
  59. String DynamicFontData::get_font_path() const {
  60. return font_path;
  61. }
  62. void DynamicFontData::set_force_autohinter(bool p_force) {
  63. force_autohinter = p_force;
  64. }
  65. void DynamicFontData::_bind_methods() {
  66. ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &DynamicFontData::set_antialiased);
  67. ClassDB::bind_method(D_METHOD("is_antialiased"), &DynamicFontData::is_antialiased);
  68. ClassDB::bind_method(D_METHOD("set_font_path", "path"), &DynamicFontData::set_font_path);
  69. ClassDB::bind_method(D_METHOD("get_font_path"), &DynamicFontData::get_font_path);
  70. ClassDB::bind_method(D_METHOD("set_hinting", "mode"), &DynamicFontData::set_hinting);
  71. ClassDB::bind_method(D_METHOD("get_hinting"), &DynamicFontData::get_hinting);
  72. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "is_antialiased");
  73. ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
  74. BIND_ENUM_CONSTANT(HINTING_NONE);
  75. BIND_ENUM_CONSTANT(HINTING_LIGHT);
  76. BIND_ENUM_CONSTANT(HINTING_NORMAL);
  77. ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_path", PROPERTY_HINT_FILE, "*.ttf,*.otf"), "set_font_path", "get_font_path");
  78. }
  79. DynamicFontData::DynamicFontData() {
  80. antialiased = true;
  81. force_autohinter = false;
  82. hinting = DynamicFontData::HINTING_NORMAL;
  83. font_mem = NULL;
  84. font_mem_size = 0;
  85. }
  86. DynamicFontData::~DynamicFontData() {
  87. }
  88. ////////////////////
  89. HashMap<String, Vector<uint8_t> > DynamicFontAtSize::_fontdata;
  90. Error DynamicFontAtSize::_load() {
  91. int error = FT_Init_FreeType(&library);
  92. ERR_EXPLAIN(TTR("Error initializing FreeType."));
  93. ERR_FAIL_COND_V(error != 0, ERR_CANT_CREATE);
  94. // FT_OPEN_STREAM is extremely slow only on Android.
  95. if (OS::get_singleton()->get_name() == "Android" && font->font_mem == NULL && font->font_path != String()) {
  96. // cache font only once for each font->font_path
  97. if (_fontdata.has(font->font_path)) {
  98. font->set_font_ptr(_fontdata[font->font_path].ptr(), _fontdata[font->font_path].size());
  99. } else {
  100. FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ);
  101. ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
  102. size_t len = f->get_len();
  103. _fontdata[font->font_path] = Vector<uint8_t>();
  104. Vector<uint8_t> &fontdata = _fontdata[font->font_path];
  105. fontdata.resize(len);
  106. f->get_buffer(fontdata.ptrw(), len);
  107. font->set_font_ptr(fontdata.ptr(), len);
  108. f->close();
  109. }
  110. }
  111. if (font->font_mem == NULL && font->font_path != String()) {
  112. FileAccess *f = FileAccess::open(font->font_path, FileAccess::READ);
  113. ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
  114. memset(&stream, 0, sizeof(FT_StreamRec));
  115. stream.base = NULL;
  116. stream.size = f->get_len();
  117. stream.pos = 0;
  118. stream.descriptor.pointer = f;
  119. stream.read = _ft_stream_io;
  120. stream.close = _ft_stream_close;
  121. FT_Open_Args fargs;
  122. memset(&fargs, 0, sizeof(FT_Open_Args));
  123. fargs.flags = FT_OPEN_STREAM;
  124. fargs.stream = &stream;
  125. error = FT_Open_Face(library, &fargs, 0, &face);
  126. } else if (font->font_mem) {
  127. memset(&stream, 0, sizeof(FT_StreamRec));
  128. stream.base = (unsigned char *)font->font_mem;
  129. stream.size = font->font_mem_size;
  130. stream.pos = 0;
  131. FT_Open_Args fargs;
  132. memset(&fargs, 0, sizeof(FT_Open_Args));
  133. fargs.memory_base = (unsigned char *)font->font_mem;
  134. fargs.memory_size = font->font_mem_size;
  135. fargs.flags = FT_OPEN_MEMORY;
  136. fargs.stream = &stream;
  137. error = FT_Open_Face(library, &fargs, 0, &face);
  138. } else {
  139. ERR_EXPLAIN("DynamicFont uninitialized");
  140. ERR_FAIL_V(ERR_UNCONFIGURED);
  141. }
  142. //error = FT_New_Face( library, src_path.utf8().get_data(),0,&face );
  143. if (error == FT_Err_Unknown_File_Format) {
  144. ERR_EXPLAIN(TTR("Unknown font format."));
  145. FT_Done_FreeType(library);
  146. } else if (error) {
  147. ERR_EXPLAIN(TTR("Error loading font."));
  148. FT_Done_FreeType(library);
  149. }
  150. ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN);
  151. /*error = FT_Set_Char_Size(face,0,64*size,512,512);
  152. if ( error ) {
  153. FT_Done_FreeType( library );
  154. ERR_EXPLAIN(TTR("Invalid font size."));
  155. ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
  156. }*/
  157. if (FT_HAS_COLOR(face)) {
  158. int best_match = 0;
  159. int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width));
  160. scale_color_font = float(id.size) / face->available_sizes[0].width;
  161. for (int i = 1; i < face->num_fixed_sizes; i++) {
  162. int ndiff = ABS(id.size - ((int64_t)face->available_sizes[i].width));
  163. if (ndiff < diff) {
  164. best_match = i;
  165. diff = ndiff;
  166. scale_color_font = float(id.size) / face->available_sizes[i].width;
  167. }
  168. }
  169. FT_Select_Size(face, best_match);
  170. } else {
  171. FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
  172. }
  173. ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font;
  174. descent = (-face->size->metrics.descender / 64.0) / oversampling * scale_color_font;
  175. linegap = 0;
  176. texture_flags = 0;
  177. if (id.mipmaps)
  178. texture_flags |= Texture::FLAG_MIPMAPS;
  179. if (id.filter)
  180. texture_flags |= Texture::FLAG_FILTER;
  181. valid = true;
  182. return OK;
  183. }
  184. float DynamicFontAtSize::font_oversampling = 1.0;
  185. float DynamicFontAtSize::get_height() const {
  186. return ascent + descent;
  187. }
  188. float DynamicFontAtSize::get_ascent() const {
  189. return ascent;
  190. }
  191. float DynamicFontAtSize::get_descent() const {
  192. return descent;
  193. }
  194. const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
  195. const Character *chr = char_map.getptr(p_char);
  196. ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
  197. if (!chr->found) {
  198. //not found, try in fallbacks
  199. for (int i = 0; i < p_fallbacks.size(); i++) {
  200. DynamicFontAtSize *fb = const_cast<DynamicFontAtSize *>(p_fallbacks[i].ptr());
  201. if (!fb->valid)
  202. continue;
  203. fb->_update_char(p_char);
  204. const Character *fallback_chr = fb->char_map.getptr(p_char);
  205. ERR_CONTINUE(!fallback_chr);
  206. if (!fallback_chr->found)
  207. continue;
  208. return Pair<const Character *, DynamicFontAtSize *>(fallback_chr, fb);
  209. }
  210. //not found, try 0xFFFD to display 'not found'.
  211. const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD);
  212. chr = char_map.getptr(0xFFFD);
  213. ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
  214. }
  215. return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this));
  216. }
  217. Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
  218. if (!valid)
  219. return Size2(1, 1);
  220. const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
  221. Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks);
  222. const Character *ch = char_pair_with_font.first;
  223. ERR_FAIL_COND_V(!ch, Size2());
  224. Size2 ret(0, get_height());
  225. if (ch->found) {
  226. ret.x = ch->advance;
  227. }
  228. return ret;
  229. }
  230. void DynamicFontAtSize::set_texture_flags(uint32_t p_flags) {
  231. texture_flags = p_flags;
  232. for (int i = 0; i < textures.size(); i++) {
  233. Ref<ImageTexture> &tex = textures.write[i].texture;
  234. if (!tex.is_null())
  235. tex->set_flags(p_flags);
  236. }
  237. }
  238. float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only) const {
  239. if (!valid)
  240. return 0;
  241. const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
  242. Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks);
  243. const Character *ch = char_pair_with_font.first;
  244. DynamicFontAtSize *font = char_pair_with_font.second;
  245. ERR_FAIL_COND_V(!ch, 0.0);
  246. float advance = 0.0;
  247. if (ch->found) {
  248. ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= font->textures.size(), 0);
  249. if (!p_advance_only && ch->texture_idx != -1) {
  250. Point2 cpos = p_pos;
  251. cpos.x += ch->h_align;
  252. cpos.y -= font->get_ascent();
  253. cpos.y += ch->v_align;
  254. Color modulate = p_modulate;
  255. if (FT_HAS_COLOR(face)) {
  256. modulate.r = modulate.g = modulate.b = 1.0;
  257. }
  258. RID texture = font->textures[ch->texture_idx].texture->get_rid();
  259. VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), false);
  260. }
  261. advance = ch->advance;
  262. }
  263. return advance;
  264. }
  265. unsigned long DynamicFontAtSize::_ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) {
  266. FileAccess *f = (FileAccess *)stream->descriptor.pointer;
  267. if (f->get_position() != offset) {
  268. f->seek(offset);
  269. }
  270. if (count == 0)
  271. return 0;
  272. return f->get_buffer(buffer, count);
  273. }
  274. void DynamicFontAtSize::_ft_stream_close(FT_Stream stream) {
  275. FileAccess *f = (FileAccess *)stream->descriptor.pointer;
  276. f->close();
  277. memdelete(f);
  278. }
  279. DynamicFontAtSize::Character DynamicFontAtSize::Character::not_found() {
  280. Character ch;
  281. ch.texture_idx = -1;
  282. ch.advance = 0;
  283. ch.h_align = 0;
  284. ch.v_align = 0;
  285. ch.found = false;
  286. return ch;
  287. }
  288. DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
  289. TexturePosition ret;
  290. ret.index = -1;
  291. ret.x = 0;
  292. ret.y = 0;
  293. int mw = p_width;
  294. int mh = p_height;
  295. for (int i = 0; i < textures.size(); i++) {
  296. const CharTexture &ct = textures[i];
  297. if (ct.texture->get_format() != p_image_format)
  298. continue;
  299. if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture
  300. continue;
  301. ret.y = 0x7FFFFFFF;
  302. ret.x = 0;
  303. for (int j = 0; j < ct.texture_size - mw; j++) {
  304. int max_y = 0;
  305. for (int k = j; k < j + mw; k++) {
  306. int y = ct.offsets[k];
  307. if (y > max_y)
  308. max_y = y;
  309. }
  310. if (max_y < ret.y) {
  311. ret.y = max_y;
  312. ret.x = j;
  313. }
  314. }
  315. if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size)
  316. continue; //fail, could not fit it here
  317. ret.index = i;
  318. break;
  319. }
  320. if (ret.index == -1) {
  321. //could not find texture to fit, create one
  322. ret.x = 0;
  323. ret.y = 0;
  324. int texsize = MAX(id.size * oversampling * 8, 256);
  325. if (mw > texsize)
  326. texsize = mw; //special case, adapt to it?
  327. if (mh > texsize)
  328. texsize = mh; //special case, adapt to it?
  329. texsize = next_power_of_2(texsize);
  330. texsize = MIN(texsize, 4096);
  331. CharTexture tex;
  332. tex.texture_size = texsize;
  333. tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha
  334. {
  335. //zero texture
  336. PoolVector<uint8_t>::Write w = tex.imgdata.write();
  337. ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
  338. for (int i = 0; i < texsize * texsize * p_color_size; i++) {
  339. w[i] = 0;
  340. }
  341. }
  342. tex.offsets.resize(texsize);
  343. for (int i = 0; i < texsize; i++) //zero offsets
  344. tex.offsets.write[i] = 0;
  345. textures.push_back(tex);
  346. ret.index = textures.size() - 1;
  347. }
  348. return ret;
  349. }
  350. DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance) {
  351. int w = bitmap.width;
  352. int h = bitmap.rows;
  353. int mw = w + rect_margin * 2;
  354. int mh = h + rect_margin * 2;
  355. ERR_FAIL_COND_V(mw > 4096, Character::not_found());
  356. ERR_FAIL_COND_V(mh > 4096, Character::not_found());
  357. int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
  358. Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
  359. TexturePosition tex_pos = _find_texture_pos_for_glyph(color_size, require_format, mw, mh);
  360. ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found());
  361. //fit character in char texture
  362. CharTexture &tex = textures.write[tex_pos.index];
  363. {
  364. PoolVector<uint8_t>::Write wr = tex.imgdata.write();
  365. for (int i = 0; i < h; i++) {
  366. for (int j = 0; j < w; j++) {
  367. int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size;
  368. ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found());
  369. switch (bitmap.pixel_mode) {
  370. case FT_PIXEL_MODE_MONO: {
  371. int byte = i * bitmap.pitch + (j >> 3);
  372. int bit = 1 << (7 - (j % 8));
  373. wr[ofs + 0] = 255; //grayscale as 1
  374. wr[ofs + 1] = bitmap.buffer[byte] & bit ? 255 : 0;
  375. } break;
  376. case FT_PIXEL_MODE_GRAY:
  377. wr[ofs + 0] = 255; //grayscale as 1
  378. wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
  379. break;
  380. case FT_PIXEL_MODE_BGRA: {
  381. int ofs_color = i * bitmap.pitch + (j << 2);
  382. wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
  383. wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
  384. wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
  385. wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
  386. } break;
  387. // TODO: FT_PIXEL_MODE_LCD
  388. default:
  389. ERR_EXPLAIN("Font uses unsupported pixel format: " + itos(bitmap.pixel_mode));
  390. ERR_FAIL_V(Character::not_found());
  391. break;
  392. }
  393. }
  394. }
  395. }
  396. //blit to image and texture
  397. {
  398. Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
  399. if (tex.texture.is_null()) {
  400. tex.texture.instance();
  401. tex.texture->create_from_image(img, Texture::FLAG_VIDEO_SURFACE | texture_flags);
  402. } else {
  403. tex.texture->set_data(img); //update
  404. }
  405. }
  406. // update height array
  407. for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
  408. tex.offsets.write[k] = tex_pos.y + mh;
  409. }
  410. Character chr;
  411. chr.h_align = xofs * scale_color_font / oversampling;
  412. chr.v_align = ascent - (yofs * scale_color_font / oversampling); // + ascent - descent;
  413. chr.advance = advance * scale_color_font / oversampling;
  414. chr.texture_idx = tex_pos.index;
  415. chr.found = true;
  416. chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h);
  417. chr.rect = chr.rect_uv;
  418. chr.rect.position /= oversampling;
  419. chr.rect.size = chr.rect.size * scale_color_font / oversampling;
  420. return chr;
  421. }
  422. DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_char) {
  423. Character ret = Character::not_found();
  424. if (FT_Load_Char(face, p_char, FT_LOAD_NO_BITMAP | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)) != 0)
  425. return ret;
  426. FT_Stroker stroker;
  427. if (FT_Stroker_New(library, &stroker) != 0)
  428. return ret;
  429. FT_Stroker_Set(stroker, (int)(id.outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
  430. FT_Glyph glyph;
  431. FT_BitmapGlyph glyph_bitmap;
  432. if (FT_Get_Glyph(face->glyph, &glyph) != 0)
  433. goto cleanup_stroker;
  434. if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0)
  435. goto cleanup_glyph;
  436. if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1) != 0)
  437. goto cleanup_glyph;
  438. glyph_bitmap = (FT_BitmapGlyph)glyph;
  439. ret = _bitmap_to_character(glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, glyph->advance.x / 65536.0);
  440. cleanup_glyph:
  441. FT_Done_Glyph(glyph);
  442. cleanup_stroker:
  443. FT_Stroker_Done(stroker);
  444. return ret;
  445. }
  446. void DynamicFontAtSize::_update_char(CharType p_char) {
  447. if (char_map.has(p_char))
  448. return;
  449. _THREAD_SAFE_METHOD_
  450. Character character = Character::not_found();
  451. FT_GlyphSlot slot = face->glyph;
  452. if (FT_Get_Char_Index(face, p_char) == 0) {
  453. char_map[p_char] = character;
  454. return;
  455. }
  456. int ft_hinting;
  457. switch (font->hinting) {
  458. case DynamicFontData::HINTING_NONE:
  459. ft_hinting = FT_LOAD_NO_HINTING;
  460. break;
  461. case DynamicFontData::HINTING_LIGHT:
  462. ft_hinting = FT_LOAD_TARGET_LIGHT;
  463. break;
  464. default:
  465. ft_hinting = FT_LOAD_TARGET_NORMAL;
  466. break;
  467. }
  468. int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0) | ft_hinting);
  469. if (error) {
  470. char_map[p_char] = character;
  471. return;
  472. }
  473. if (id.outline_size > 0) {
  474. character = _make_outline_char(p_char);
  475. } else {
  476. error = FT_Render_Glyph(face->glyph, font->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
  477. if (!error)
  478. character = _bitmap_to_character(slot->bitmap, slot->bitmap_top, slot->bitmap_left, slot->advance.x / 64.0);
  479. }
  480. char_map[p_char] = character;
  481. }
  482. void DynamicFontAtSize::update_oversampling() {
  483. if (oversampling == font_oversampling || !valid)
  484. return;
  485. FT_Done_FreeType(library);
  486. textures.clear();
  487. char_map.clear();
  488. oversampling = font_oversampling;
  489. valid = false;
  490. _load();
  491. }
  492. DynamicFontAtSize::DynamicFontAtSize() {
  493. valid = false;
  494. rect_margin = 1;
  495. ascent = 1;
  496. descent = 1;
  497. linegap = 1;
  498. texture_flags = 0;
  499. oversampling = font_oversampling;
  500. scale_color_font = 1;
  501. }
  502. DynamicFontAtSize::~DynamicFontAtSize() {
  503. if (valid) {
  504. FT_Done_FreeType(library);
  505. }
  506. font->size_cache.erase(id);
  507. font.unref();
  508. }
  509. /////////////////////////
  510. void DynamicFont::_reload_cache() {
  511. ERR_FAIL_COND(cache_id.size < 1);
  512. if (!data.is_valid()) {
  513. data_at_size.unref();
  514. outline_data_at_size.unref();
  515. fallback_data_at_size.resize(0);
  516. fallback_outline_data_at_size.resize(0);
  517. return;
  518. }
  519. data_at_size = data->_get_dynamic_font_at_size(cache_id);
  520. if (outline_cache_id.outline_size > 0) {
  521. outline_data_at_size = data->_get_dynamic_font_at_size(outline_cache_id);
  522. fallback_outline_data_at_size.resize(fallback_data_at_size.size());
  523. } else {
  524. outline_data_at_size.unref();
  525. fallback_outline_data_at_size.resize(0);
  526. }
  527. for (int i = 0; i < fallbacks.size(); i++) {
  528. fallback_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(cache_id);
  529. if (outline_cache_id.outline_size > 0)
  530. fallback_outline_data_at_size.write[i] = fallbacks.write[i]->_get_dynamic_font_at_size(outline_cache_id);
  531. }
  532. emit_changed();
  533. _change_notify();
  534. }
  535. void DynamicFont::set_font_data(const Ref<DynamicFontData> &p_data) {
  536. data = p_data;
  537. _reload_cache();
  538. emit_changed();
  539. _change_notify();
  540. }
  541. Ref<DynamicFontData> DynamicFont::get_font_data() const {
  542. return data;
  543. }
  544. void DynamicFont::set_size(int p_size) {
  545. if (cache_id.size == p_size)
  546. return;
  547. cache_id.size = p_size;
  548. outline_cache_id.size = p_size;
  549. _reload_cache();
  550. }
  551. int DynamicFont::get_size() const {
  552. return cache_id.size;
  553. }
  554. void DynamicFont::set_outline_size(int p_size) {
  555. if (outline_cache_id.outline_size == p_size)
  556. return;
  557. ERR_FAIL_COND(p_size < 0 || p_size > UINT8_MAX);
  558. outline_cache_id.outline_size = p_size;
  559. _reload_cache();
  560. }
  561. int DynamicFont::get_outline_size() const {
  562. return outline_cache_id.outline_size;
  563. }
  564. void DynamicFont::set_outline_color(Color p_color) {
  565. if (p_color != outline_color) {
  566. outline_color = p_color;
  567. emit_changed();
  568. _change_notify();
  569. }
  570. }
  571. Color DynamicFont::get_outline_color() const {
  572. return outline_color;
  573. }
  574. bool DynamicFont::get_use_mipmaps() const {
  575. return cache_id.mipmaps;
  576. }
  577. void DynamicFont::set_use_mipmaps(bool p_enable) {
  578. if (cache_id.mipmaps == p_enable)
  579. return;
  580. cache_id.mipmaps = p_enable;
  581. outline_cache_id.mipmaps = p_enable;
  582. _reload_cache();
  583. }
  584. bool DynamicFont::get_use_filter() const {
  585. return cache_id.filter;
  586. }
  587. void DynamicFont::set_use_filter(bool p_enable) {
  588. if (cache_id.filter == p_enable)
  589. return;
  590. cache_id.filter = p_enable;
  591. outline_cache_id.filter = p_enable;
  592. _reload_cache();
  593. }
  594. bool DynamicFontData::is_antialiased() const {
  595. return antialiased;
  596. }
  597. void DynamicFontData::set_antialiased(bool p_antialiased) {
  598. if (antialiased == p_antialiased)
  599. return;
  600. antialiased = p_antialiased;
  601. }
  602. DynamicFontData::Hinting DynamicFontData::get_hinting() const {
  603. return hinting;
  604. }
  605. void DynamicFontData::set_hinting(Hinting p_hinting) {
  606. if (hinting == p_hinting)
  607. return;
  608. hinting = p_hinting;
  609. }
  610. int DynamicFont::get_spacing(int p_type) const {
  611. if (p_type == SPACING_TOP) {
  612. return spacing_top;
  613. } else if (p_type == SPACING_BOTTOM) {
  614. return spacing_bottom;
  615. } else if (p_type == SPACING_CHAR) {
  616. return spacing_char;
  617. } else if (p_type == SPACING_SPACE) {
  618. return spacing_space;
  619. }
  620. return 0;
  621. }
  622. void DynamicFont::set_spacing(int p_type, int p_value) {
  623. if (p_type == SPACING_TOP) {
  624. spacing_top = p_value;
  625. } else if (p_type == SPACING_BOTTOM) {
  626. spacing_bottom = p_value;
  627. } else if (p_type == SPACING_CHAR) {
  628. spacing_char = p_value;
  629. } else if (p_type == SPACING_SPACE) {
  630. spacing_space = p_value;
  631. }
  632. emit_changed();
  633. _change_notify();
  634. }
  635. float DynamicFont::get_height() const {
  636. if (!data_at_size.is_valid())
  637. return 1;
  638. return data_at_size->get_height() + spacing_top + spacing_bottom;
  639. }
  640. float DynamicFont::get_ascent() const {
  641. if (!data_at_size.is_valid())
  642. return 1;
  643. return data_at_size->get_ascent() + spacing_top;
  644. }
  645. float DynamicFont::get_descent() const {
  646. if (!data_at_size.is_valid())
  647. return 1;
  648. return data_at_size->get_descent() + spacing_bottom;
  649. }
  650. Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const {
  651. if (!data_at_size.is_valid())
  652. return Size2(1, 1);
  653. Size2 ret = data_at_size->get_char_size(p_char, p_next, fallback_data_at_size);
  654. if (p_char == ' ')
  655. ret.width += spacing_space + spacing_char;
  656. else if (p_next)
  657. ret.width += spacing_char;
  658. return ret;
  659. }
  660. bool DynamicFont::is_distance_field_hint() const {
  661. return false;
  662. }
  663. bool DynamicFont::has_outline() const {
  664. return outline_cache_id.outline_size > 0;
  665. }
  666. float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
  667. const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size;
  668. if (!font_at_size.is_valid())
  669. return 0;
  670. const Vector<Ref<DynamicFontAtSize> > &fallbacks = p_outline && outline_cache_id.outline_size > 0 ? fallback_outline_data_at_size : fallback_data_at_size;
  671. Color color = p_outline && outline_cache_id.outline_size > 0 ? p_modulate * outline_color : p_modulate;
  672. // If requested outline draw, but no outline is present, simply return advance without drawing anything
  673. bool advance_only = p_outline && outline_cache_id.outline_size == 0;
  674. return font_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, color, fallbacks, advance_only) + spacing_char;
  675. }
  676. void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) {
  677. ERR_FAIL_COND(p_data.is_null());
  678. ERR_FAIL_INDEX(p_idx, fallbacks.size());
  679. fallbacks.write[p_idx] = p_data;
  680. fallback_data_at_size.write[p_idx] = fallbacks.write[p_idx]->_get_dynamic_font_at_size(cache_id);
  681. }
  682. void DynamicFont::add_fallback(const Ref<DynamicFontData> &p_data) {
  683. ERR_FAIL_COND(p_data.is_null());
  684. fallbacks.push_back(p_data);
  685. fallback_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(cache_id)); //const..
  686. if (outline_cache_id.outline_size > 0)
  687. fallback_outline_data_at_size.push_back(fallbacks.write[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id));
  688. _change_notify();
  689. emit_changed();
  690. _change_notify();
  691. }
  692. int DynamicFont::get_fallback_count() const {
  693. return fallbacks.size();
  694. }
  695. Ref<DynamicFontData> DynamicFont::get_fallback(int p_idx) const {
  696. ERR_FAIL_INDEX_V(p_idx, fallbacks.size(), Ref<DynamicFontData>());
  697. return fallbacks[p_idx];
  698. }
  699. void DynamicFont::remove_fallback(int p_idx) {
  700. ERR_FAIL_INDEX(p_idx, fallbacks.size());
  701. fallbacks.remove(p_idx);
  702. fallback_data_at_size.remove(p_idx);
  703. emit_changed();
  704. _change_notify();
  705. }
  706. bool DynamicFont::_set(const StringName &p_name, const Variant &p_value) {
  707. String str = p_name;
  708. if (str.begins_with("fallback/")) {
  709. int idx = str.get_slicec('/', 1).to_int();
  710. Ref<DynamicFontData> fd = p_value;
  711. if (fd.is_valid()) {
  712. if (idx == fallbacks.size()) {
  713. add_fallback(fd);
  714. return true;
  715. } else if (idx >= 0 && idx < fallbacks.size()) {
  716. set_fallback(idx, fd);
  717. return true;
  718. } else {
  719. return false;
  720. }
  721. } else if (idx >= 0 && idx < fallbacks.size()) {
  722. remove_fallback(idx);
  723. return true;
  724. }
  725. }
  726. return false;
  727. }
  728. bool DynamicFont::_get(const StringName &p_name, Variant &r_ret) const {
  729. String str = p_name;
  730. if (str.begins_with("fallback/")) {
  731. int idx = str.get_slicec('/', 1).to_int();
  732. if (idx == fallbacks.size()) {
  733. r_ret = Ref<DynamicFontData>();
  734. return true;
  735. } else if (idx >= 0 && idx < fallbacks.size()) {
  736. r_ret = get_fallback(idx);
  737. return true;
  738. }
  739. }
  740. return false;
  741. }
  742. void DynamicFont::_get_property_list(List<PropertyInfo> *p_list) const {
  743. for (int i = 0; i < fallbacks.size(); i++) {
  744. p_list->push_back(PropertyInfo(Variant::OBJECT, "fallback/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"));
  745. }
  746. p_list->push_back(PropertyInfo(Variant::OBJECT, "fallback/" + itos(fallbacks.size()), PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"));
  747. }
  748. void DynamicFont::_bind_methods() {
  749. ClassDB::bind_method(D_METHOD("set_font_data", "data"), &DynamicFont::set_font_data);
  750. ClassDB::bind_method(D_METHOD("get_font_data"), &DynamicFont::get_font_data);
  751. ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size);
  752. ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size);
  753. ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &DynamicFont::set_outline_size);
  754. ClassDB::bind_method(D_METHOD("get_outline_size"), &DynamicFont::get_outline_size);
  755. ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &DynamicFont::set_outline_color);
  756. ClassDB::bind_method(D_METHOD("get_outline_color"), &DynamicFont::get_outline_color);
  757. ClassDB::bind_method(D_METHOD("set_use_mipmaps", "enable"), &DynamicFont::set_use_mipmaps);
  758. ClassDB::bind_method(D_METHOD("get_use_mipmaps"), &DynamicFont::get_use_mipmaps);
  759. ClassDB::bind_method(D_METHOD("set_use_filter", "enable"), &DynamicFont::set_use_filter);
  760. ClassDB::bind_method(D_METHOD("get_use_filter"), &DynamicFont::get_use_filter);
  761. ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &DynamicFont::set_spacing);
  762. ClassDB::bind_method(D_METHOD("get_spacing", "type"), &DynamicFont::get_spacing);
  763. ClassDB::bind_method(D_METHOD("add_fallback", "data"), &DynamicFont::add_fallback);
  764. ClassDB::bind_method(D_METHOD("set_fallback", "idx", "data"), &DynamicFont::set_fallback);
  765. ClassDB::bind_method(D_METHOD("get_fallback", "idx"), &DynamicFont::get_fallback);
  766. ClassDB::bind_method(D_METHOD("remove_fallback", "idx"), &DynamicFont::remove_fallback);
  767. ClassDB::bind_method(D_METHOD("get_fallback_count"), &DynamicFont::get_fallback_count);
  768. ADD_GROUP("Settings", "");
  769. ADD_PROPERTY(PropertyInfo(Variant::INT, "size", PROPERTY_HINT_RANGE, "1,255,1"), "set_size", "get_size");
  770. ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size", PROPERTY_HINT_RANGE, "0,255,1"), "set_outline_size", "get_outline_size");
  771. ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color");
  772. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "get_use_mipmaps");
  773. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_filter"), "set_use_filter", "get_use_filter");
  774. ADD_GROUP("Extra Spacing", "extra_spacing");
  775. ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_top"), "set_spacing", "get_spacing", SPACING_TOP);
  776. ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_bottom"), "set_spacing", "get_spacing", SPACING_BOTTOM);
  777. ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_char"), "set_spacing", "get_spacing", SPACING_CHAR);
  778. ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE);
  779. ADD_GROUP("Font", "");
  780. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font_data", PROPERTY_HINT_RESOURCE_TYPE, "DynamicFontData"), "set_font_data", "get_font_data");
  781. BIND_ENUM_CONSTANT(SPACING_TOP);
  782. BIND_ENUM_CONSTANT(SPACING_BOTTOM);
  783. BIND_ENUM_CONSTANT(SPACING_CHAR);
  784. BIND_ENUM_CONSTANT(SPACING_SPACE);
  785. }
  786. Mutex *DynamicFont::dynamic_font_mutex = NULL;
  787. SelfList<DynamicFont>::List *DynamicFont::dynamic_fonts = NULL;
  788. DynamicFont::DynamicFont() :
  789. font_list(this) {
  790. cache_id.size = 16;
  791. outline_cache_id.size = 16;
  792. spacing_top = 0;
  793. spacing_bottom = 0;
  794. spacing_char = 0;
  795. spacing_space = 0;
  796. outline_color = Color(1, 1, 1);
  797. if (dynamic_font_mutex) {
  798. dynamic_font_mutex->lock();
  799. dynamic_fonts->add(&font_list);
  800. dynamic_font_mutex->unlock();
  801. }
  802. }
  803. DynamicFont::~DynamicFont() {
  804. if (dynamic_font_mutex) {
  805. dynamic_font_mutex->lock();
  806. dynamic_fonts->remove(&font_list);
  807. dynamic_font_mutex->unlock();
  808. }
  809. }
  810. void DynamicFont::initialize_dynamic_fonts() {
  811. dynamic_fonts = memnew(SelfList<DynamicFont>::List());
  812. dynamic_font_mutex = Mutex::create();
  813. }
  814. void DynamicFont::finish_dynamic_fonts() {
  815. memdelete(dynamic_font_mutex);
  816. dynamic_font_mutex = NULL;
  817. memdelete(dynamic_fonts);
  818. dynamic_fonts = NULL;
  819. }
  820. void DynamicFont::update_oversampling() {
  821. Vector<Ref<DynamicFont> > changed;
  822. if (dynamic_font_mutex)
  823. dynamic_font_mutex->lock();
  824. SelfList<DynamicFont> *E = dynamic_fonts->first();
  825. while (E) {
  826. if (E->self()->data_at_size.is_valid()) {
  827. E->self()->data_at_size->update_oversampling();
  828. if (E->self()->outline_data_at_size.is_valid()) {
  829. E->self()->outline_data_at_size->update_oversampling();
  830. }
  831. for (int i = 0; i < E->self()->fallback_data_at_size.size(); i++) {
  832. if (E->self()->fallback_data_at_size[i].is_valid()) {
  833. E->self()->fallback_data_at_size.write[i]->update_oversampling();
  834. if (E->self()->has_outline() && E->self()->fallback_outline_data_at_size[i].is_valid()) {
  835. E->self()->fallback_outline_data_at_size.write[i]->update_oversampling();
  836. }
  837. }
  838. }
  839. changed.push_back(Ref<DynamicFont>(E->self()));
  840. }
  841. E = E->next();
  842. }
  843. if (dynamic_font_mutex)
  844. dynamic_font_mutex->unlock();
  845. for (int i = 0; i < changed.size(); i++) {
  846. changed.write[i]->emit_changed();
  847. }
  848. }
  849. /////////////////////////
  850. RES ResourceFormatLoaderDynamicFont::load(const String &p_path, const String &p_original_path, Error *r_error) {
  851. if (r_error)
  852. *r_error = ERR_FILE_CANT_OPEN;
  853. Ref<DynamicFontData> dfont;
  854. dfont.instance();
  855. dfont->set_font_path(p_path);
  856. if (r_error)
  857. *r_error = OK;
  858. return dfont;
  859. }
  860. void ResourceFormatLoaderDynamicFont::get_recognized_extensions(List<String> *p_extensions) const {
  861. p_extensions->push_back("ttf");
  862. p_extensions->push_back("otf");
  863. }
  864. bool ResourceFormatLoaderDynamicFont::handles_type(const String &p_type) const {
  865. return (p_type == "DynamicFontData");
  866. }
  867. String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const {
  868. String el = p_path.get_extension().to_lower();
  869. if (el == "ttf" || el == "otf")
  870. return "DynamicFontData";
  871. return "";
  872. }
  873. #endif