Font.cpp 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Deserializer.h"
  25. #include "FileSystem.h"
  26. #include "Font.h"
  27. #include "Graphics.h"
  28. #include "Log.h"
  29. #include "MemoryBuffer.h"
  30. #include "Profiler.h"
  31. #include "ResourceCache.h"
  32. #include "Texture2D.h"
  33. #include "UI.h"
  34. #include "XMLFile.h"
  35. #include <ft2build.h>
  36. #include FT_FREETYPE_H
  37. #include FT_TRUETYPE_TABLES_H
  38. #include "DebugNew.h"
  39. namespace Urho3D
  40. {
  41. static const int MIN_POINT_SIZE = 1;
  42. static const int MAX_POINT_SIZE = 96;
  43. /// FreeType library subsystem.
  44. class FreeTypeLibrary : public Object
  45. {
  46. OBJECT(FreeTypeLibrary);
  47. public:
  48. /// Construct.
  49. FreeTypeLibrary(Context* context) :
  50. Object(context)
  51. {
  52. FT_Error error = FT_Init_FreeType(&library_);
  53. if (error)
  54. LOGERROR("Could not initialize FreeType library");
  55. }
  56. /// Destruct.
  57. virtual ~FreeTypeLibrary()
  58. {
  59. FT_Done_FreeType(library_);
  60. }
  61. FT_Library GetLibrary() const { return library_; }
  62. private:
  63. /// FreeType library.
  64. FT_Library library_;
  65. };
  66. MutableGlyph::MutableGlyph() :
  67. glyphIndex_(M_MAX_UNSIGNED)
  68. {
  69. }
  70. FontGlyph::FontGlyph() :
  71. used_(false),
  72. page_(M_MAX_UNSIGNED)
  73. {
  74. }
  75. FontFace::FontFace(Font* font) :
  76. font_(font),
  77. face_(0),
  78. hasKerning_(false),
  79. bitmapSize_(0)
  80. {
  81. }
  82. FontFace::~FontFace()
  83. {
  84. if (face_)
  85. {
  86. FT_Done_Face((FT_Face)face_);
  87. face_ = 0;
  88. }
  89. if (font_)
  90. {
  91. // When a face is unloaded, deduct the used texture data size from the parent font
  92. unsigned totalTextureSize = 0;
  93. for (unsigned i = 0; i < textures_.Size(); ++i)
  94. totalTextureSize += textures_[i]->GetWidth() * textures_[i]->GetHeight();
  95. font_->SetMemoryUse(font_->GetMemoryUse() - totalTextureSize);
  96. }
  97. for (List<MutableGlyph*>::Iterator i = mutableGlyphs_.Begin(); i != mutableGlyphs_.End(); ++i)
  98. delete *i;
  99. mutableGlyphs_.Clear();
  100. }
  101. const FontGlyph* FontFace::GetGlyph(unsigned c)
  102. {
  103. HashMap<unsigned, unsigned>::ConstIterator i = glyphMapping_.Find(c);
  104. if (i != glyphMapping_.End())
  105. {
  106. FontGlyph& glyph = glyphs_[i->second_];
  107. // Render glyph if not yet resident in a page texture (FreeType mode only)
  108. if (glyph.page_ == M_MAX_UNSIGNED)
  109. RenderGlyph(i->second_);
  110. // If mutable glyphs in use, move to the front of the list
  111. if (mutableGlyphs_.Size() && glyph.iterator_ != mutableGlyphs_.End())
  112. {
  113. MutableGlyph* mutableGlyph = *glyph.iterator_;
  114. mutableGlyphs_.Erase(glyph.iterator_);
  115. mutableGlyphs_.PushFront(mutableGlyph);
  116. glyph.iterator_ = mutableGlyphs_.Begin();
  117. }
  118. glyph.used_ = true;
  119. return &glyph;
  120. }
  121. else
  122. return 0;
  123. }
  124. short FontFace::GetKerning(unsigned c, unsigned d) const
  125. {
  126. if (!hasKerning_)
  127. return 0;
  128. if (c == '\n' || d == '\n')
  129. return 0;
  130. unsigned leftIndex = 0;
  131. unsigned rightIndex = 0;
  132. HashMap<unsigned, unsigned>::ConstIterator leftIt = glyphMapping_.Find(c);
  133. if (leftIt != glyphMapping_.End())
  134. leftIndex = leftIt->second_;
  135. else
  136. return 0;
  137. HashMap<unsigned, unsigned>::ConstIterator rightIt = glyphMapping_.Find(d);
  138. if (rightIt != glyphMapping_.End())
  139. rightIndex = rightIt->second_;
  140. else
  141. return 0;
  142. HashMap<unsigned, unsigned>::ConstIterator kerningIt = glyphs_[leftIndex].kerning_.Find(rightIndex);
  143. if (kerningIt != glyphs_[leftIndex].kerning_.End())
  144. return kerningIt->second_;
  145. else
  146. return 0;
  147. }
  148. bool FontFace::IsDataLost() const
  149. {
  150. for (unsigned i = 0; i < textures_.Size(); ++i)
  151. {
  152. if (textures_[i]->IsDataLost())
  153. return true;
  154. }
  155. return false;
  156. }
  157. bool FontFace::RenderAllGlyphs(int maxWidth, int maxHeight)
  158. {
  159. assert(font_ && face_ && textures_.Empty());
  160. allocator_ = AreaAllocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxWidth, maxHeight);
  161. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  162. {
  163. if (glyphs_[i].width_ && glyphs_[i].height_)
  164. {
  165. int x, y;
  166. // Reserve an empty border between glyphs for filtering
  167. if (allocator_.Allocate(glyphs_[i].width_ + 1, glyphs_[i].height_ + 1, x, y))
  168. {
  169. glyphs_[i].x_ = x;
  170. glyphs_[i].y_ = y;
  171. glyphs_[i].page_ = 0;
  172. }
  173. else
  174. {
  175. // When allocation fails, reset the page of all glyphs allocated so far
  176. for (unsigned j = 0; j <= i; ++j)
  177. glyphs_[j].page_ = M_MAX_UNSIGNED;
  178. return false;
  179. }
  180. }
  181. else
  182. {
  183. glyphs_[i].x_ = 0;
  184. glyphs_[i].y_ = 0;
  185. glyphs_[i].page_ = 0;
  186. }
  187. }
  188. // Create image for rendering all the glyphs, clear to black
  189. SharedPtr<Image> image(new Image(font_->GetContext()));
  190. image->SetSize(allocator_.GetWidth(), allocator_.GetHeight(), 1);
  191. unsigned char* imageData = image->GetData();
  192. memset(imageData, 0, image->GetWidth() * image->GetHeight());
  193. int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  194. // Render glyphs
  195. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  196. RenderGlyphBitmap(i, imageData + glyphs_[i].y_ * image->GetWidth() + glyphs_[i].x_, image->GetWidth(), loadMode);
  197. // Load image into a texture, increment memory usage of the parent font
  198. SharedPtr<Texture2D> texture = font_->LoadFaceTexture(image);
  199. if (!texture)
  200. {
  201. for (unsigned i = 0; i < glyphs_.Size(); ++i)
  202. glyphs_[i].page_ = M_MAX_UNSIGNED;
  203. return false;
  204. }
  205. textures_.Push(texture);
  206. font_->SetMemoryUse(font_->GetMemoryUse() + image->GetWidth() * image->GetHeight());
  207. LOGDEBUGF("Font face %s (%dpt) uses a static page texture of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, texture->GetWidth(), texture->GetHeight());
  208. return true;
  209. }
  210. void FontFace::RenderGlyph(unsigned index)
  211. {
  212. assert(font_ && face_);
  213. FontGlyph& glyph = glyphs_[index];
  214. // If glyph is empty, just set the current page
  215. if (!glyph.width_ || !glyph.height_)
  216. {
  217. glyph.x_ = 0;
  218. glyph.y_ = 0;
  219. glyph.page_ = textures_.Size() - 1;
  220. return;
  221. }
  222. int loadMode = font_->GetSubsystem<UI>()->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  223. if (!mutableGlyphs_.Size())
  224. {
  225. // Not using mutable glyphs: try to allocate from current page, reserve next page if fails
  226. int x, y;
  227. if (!allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
  228. {
  229. SetupNextTexture(textures_[0]->GetWidth(), textures_[0]->GetHeight());
  230. // This always succeeds, as it is the first allocation of an empty page
  231. allocator_.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y);
  232. }
  233. glyph.x_ = x;
  234. glyph.y_ = y;
  235. glyph.page_ = textures_.Size() - 1;
  236. if (!bitmap_ || (int)bitmapSize_ < glyph.width_ * glyph.height_)
  237. {
  238. bitmapSize_ = glyph.width_ * glyph.height_;
  239. bitmap_ = new unsigned char[bitmapSize_];
  240. }
  241. RenderGlyphBitmap(index, bitmap_.Get(), glyph.width_, loadMode);
  242. textures_.Back()->SetData(0, glyph.x_, glyph.y_, glyph.width_, glyph.height_, bitmap_.Get());
  243. }
  244. else
  245. {
  246. // Using mutable glyphs: overwrite the least recently used glyph
  247. List<MutableGlyph*>::Iterator it = --mutableGlyphs_.End();
  248. MutableGlyph* mutableGlyph = *it;
  249. if (mutableGlyph->glyphIndex_ != M_MAX_UNSIGNED)
  250. glyphs_[mutableGlyph->glyphIndex_].page_ = M_MAX_UNSIGNED;
  251. glyph.x_ = mutableGlyph->x_;
  252. glyph.y_ = mutableGlyph->y_;
  253. glyph.page_ = 0;
  254. glyph.iterator_ = it;
  255. mutableGlyph->glyphIndex_ = index;
  256. if (!bitmap_)
  257. {
  258. bitmapSize_ = cellWidth_ * cellHeight_;
  259. bitmap_ = new unsigned char[bitmapSize_];
  260. }
  261. // Clear the cell bitmap before rendering to ensure padding
  262. memset(bitmap_.Get(), 0, cellWidth_ * cellHeight_);
  263. RenderGlyphBitmap(index, bitmap_.Get(), cellWidth_, loadMode);
  264. textures_[0]->SetData(0, glyph.x_, glyph.y_, cellWidth_, cellHeight_, bitmap_.Get());
  265. }
  266. }
  267. void FontFace::RenderGlyphBitmap(unsigned index, unsigned char* dest, unsigned pitch, int loadMode)
  268. {
  269. const FontGlyph& glyph = glyphs_[index];
  270. if (!glyph.width_ || !glyph.height_)
  271. return;
  272. FT_Face face = (FT_Face)face_;
  273. FT_GlyphSlot slot = face->glyph;
  274. FT_Load_Glyph(face, index, loadMode);
  275. FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
  276. if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
  277. {
  278. for (int y = 0; y < slot->bitmap.rows; ++y)
  279. {
  280. unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
  281. unsigned char* rowDest = dest + y * pitch;
  282. for (int x = 0; x < slot->bitmap.width; ++x)
  283. rowDest[x] = (src[x >> 3] & (0x80 >> (x & 7))) ? 255 : 0;
  284. }
  285. }
  286. else
  287. {
  288. for (int y = 0; y < slot->bitmap.rows; ++y)
  289. {
  290. unsigned char* src = slot->bitmap.buffer + slot->bitmap.pitch * y;
  291. unsigned char* rowDest = dest + y * pitch;
  292. for (int x = 0; x < slot->bitmap.width; ++x)
  293. rowDest[x] = src[x];
  294. }
  295. }
  296. }
  297. void FontFace::SetupNextTexture(int width, int height)
  298. {
  299. // If several dynamic textures are needed, use the maximum size to pack as many as possible to one texture
  300. allocator_ = AreaAllocator(width, height);
  301. SharedPtr<Texture2D> texture = font_->CreateFaceTexture();
  302. texture->SetSize(width, height, Graphics::GetAlphaFormat());
  303. SharedArrayPtr<unsigned char> emptyBitmap(new unsigned char[width * height]);
  304. memset(emptyBitmap.Get(), 0, width * height);
  305. texture->SetData(0, 0, 0, width, height, emptyBitmap.Get());
  306. textures_.Push(texture);
  307. font_->SetMemoryUse(font_->GetMemoryUse() + width * height);
  308. LOGDEBUGF("Font face %s (%dpt) is using %d dynamic page textures of size %dx%d", GetFileName(font_->GetName()).CString(), pointSize_, textures_.Size(), width, height);
  309. }
  310. void FontFace::SetupMutableGlyphs(int textureWidth, int textureHeight, int maxWidth, int maxHeight)
  311. {
  312. assert(mutableGlyphs_.Empty());
  313. SetupNextTexture(textureWidth, textureHeight);
  314. cellWidth_ = maxWidth + 1;
  315. cellHeight_ = maxHeight + 1;
  316. // Allocate as many mutable glyphs as possible
  317. int x, y;
  318. while (allocator_.Allocate(cellWidth_, cellHeight_, x, y))
  319. {
  320. MutableGlyph* glyph = new MutableGlyph();
  321. glyph->x_ = x;
  322. glyph->y_ = y;
  323. mutableGlyphs_.Push(glyph);
  324. }
  325. LOGDEBUGF("Font face %s (%dpt) is using %d mutable glyphs", GetFileName(font_->GetName()).CString(), pointSize_, mutableGlyphs_.Size());
  326. }
  327. Font::Font(Context* context) :
  328. Resource(context),
  329. fontDataSize_(0),
  330. fontType_(FONT_NONE)
  331. {
  332. }
  333. Font::~Font()
  334. {
  335. // To ensure FreeType deallocates properly, first clear all faces, then release the raw font data
  336. ReleaseFaces();
  337. fontData_.Reset();
  338. }
  339. void Font::RegisterObject(Context* context)
  340. {
  341. context->RegisterFactory<Font>();
  342. }
  343. bool Font::Load(Deserializer& source)
  344. {
  345. PROFILE(LoadFont);
  346. // In headless mode, do not actually load, just return success
  347. Graphics* graphics = GetSubsystem<Graphics>();
  348. if (!graphics)
  349. return true;
  350. fontType_ = FONT_NONE;
  351. faces_.Clear();
  352. fontDataSize_ = source.GetSize();
  353. if (fontDataSize_)
  354. {
  355. fontData_ = new unsigned char[fontDataSize_];
  356. if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_)
  357. return false;
  358. }
  359. else
  360. {
  361. fontData_.Reset();
  362. return false;
  363. }
  364. String ext = GetExtension(GetName());
  365. if (ext == ".ttf" || ext == ".otf" || ext == ".woff")
  366. fontType_ = FONT_FREETYPE;
  367. else if (ext == ".xml" || ext == ".fnt")
  368. fontType_ = FONT_BITMAP;
  369. SetMemoryUse(fontDataSize_);
  370. return true;
  371. }
  372. bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs)
  373. {
  374. FontFace* fontFace = GetFace(pointSize);
  375. if (!fontFace)
  376. return false;
  377. PROFILE(FontSaveXML);
  378. SharedPtr<FontFace> packedFontFace;
  379. if (usedGlyphs)
  380. {
  381. // Save used glyphs only, try to pack them first
  382. packedFontFace = Pack(fontFace);
  383. if (packedFontFace)
  384. fontFace = packedFontFace;
  385. else
  386. return false;
  387. }
  388. SharedPtr<XMLFile> xml(new XMLFile(context_));
  389. XMLElement rootElem = xml->CreateRoot("font");
  390. // Information
  391. XMLElement childElem = rootElem.CreateChild("info");
  392. String fileName = GetFileName(GetName());
  393. childElem.SetAttribute("face", fileName);
  394. childElem.SetAttribute("size", String(pointSize));
  395. // Common
  396. childElem = rootElem.CreateChild("common");
  397. childElem.SetInt("lineHeight", fontFace->rowHeight_);
  398. unsigned pages = fontFace->textures_.Size();
  399. childElem.SetInt("pages", pages);
  400. // Construct the path to store the texture
  401. String pathName;
  402. File* file = dynamic_cast<File*>(&dest);
  403. if (file)
  404. // If serialize to file, use the file's path
  405. pathName = GetPath(file->GetName());
  406. else
  407. // Otherwise, use the font resource's path
  408. pathName = "Data/" + GetPath(GetName());
  409. // Pages
  410. childElem = rootElem.CreateChild("pages");
  411. for (unsigned i = 0; i < pages; ++i)
  412. {
  413. XMLElement pageElem = childElem.CreateChild("page");
  414. pageElem.SetInt("id", i);
  415. String texFileName = fileName + "_" + String(i) + ".png";
  416. pageElem.SetAttribute("file", texFileName);
  417. // Save the font face texture to image file
  418. SaveFaceTexture(fontFace->textures_[i], pathName + texFileName);
  419. }
  420. // Chars and kernings
  421. XMLElement charsElem = rootElem.CreateChild("chars");
  422. unsigned numGlyphs = fontFace->glyphs_.Size();
  423. charsElem.SetInt("count", numGlyphs);
  424. XMLElement kerningsElem;
  425. bool hasKerning = fontFace->hasKerning_;
  426. if (hasKerning)
  427. kerningsElem = rootElem.CreateChild("kernings");
  428. for (HashMap<unsigned, unsigned>::ConstIterator i = fontFace->glyphMapping_.Begin(); i != fontFace->glyphMapping_.End(); ++i)
  429. {
  430. // Char
  431. XMLElement charElem = charsElem.CreateChild("char");
  432. charElem.SetInt("id", i->first_);
  433. FontGlyph glyph = fontFace->glyphs_[i->second_];
  434. charElem.SetInt("x", glyph.x_);
  435. charElem.SetInt("y", glyph.y_);
  436. charElem.SetInt("width", glyph.width_);
  437. charElem.SetInt("height", glyph.height_);
  438. charElem.SetInt("xoffset", glyph.offsetX_);
  439. charElem.SetInt("yoffset", glyph.offsetY_);
  440. charElem.SetInt("xadvance", glyph.advanceX_);
  441. charElem.SetInt("page", glyph.page_);
  442. // Kerning
  443. if (hasKerning)
  444. {
  445. for (HashMap<unsigned, unsigned>::ConstIterator j = glyph.kerning_.Begin(); j != glyph.kerning_.End(); ++j)
  446. {
  447. // To conserve space, only write when amount is non zero
  448. if (j->second_ == 0)
  449. continue;
  450. XMLElement kerningElem = kerningsElem.CreateChild("kerning");
  451. kerningElem.SetInt("first", i->first_);
  452. kerningElem.SetInt("second", j->first_);
  453. kerningElem.SetInt("amount", j->second_);
  454. }
  455. }
  456. }
  457. return xml->Save(dest);
  458. }
  459. FontFace* Font::GetFace(int pointSize)
  460. {
  461. // In headless mode, always return null
  462. Graphics* graphics = GetSubsystem<Graphics>();
  463. if (!graphics)
  464. return 0;
  465. // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size
  466. if (fontType_ == FONT_BITMAP)
  467. pointSize = 0;
  468. else
  469. pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE);
  470. HashMap<int, SharedPtr<FontFace> >::Iterator i = faces_.Find(pointSize);
  471. if (i != faces_.End())
  472. {
  473. if (!i->second_->IsDataLost())
  474. return i->second_;
  475. else
  476. {
  477. // Erase and reload face if texture data lost (OpenGL mode only)
  478. faces_.Erase(i);
  479. }
  480. }
  481. PROFILE(GetFontFace);
  482. switch (fontType_)
  483. {
  484. case FONT_FREETYPE:
  485. return GetFaceFreeType(pointSize);
  486. case FONT_BITMAP:
  487. return GetFaceBitmap(pointSize);
  488. default:
  489. return 0;
  490. }
  491. }
  492. void Font::ReleaseFaces()
  493. {
  494. faces_.Clear();
  495. }
  496. SharedPtr<Texture2D> Font::CreateFaceTexture()
  497. {
  498. SharedPtr<Texture2D> texture(new Texture2D(context_));
  499. texture->SetMipsToSkip(QUALITY_LOW, 0); // No quality reduction
  500. texture->SetNumLevels(1); // No mipmaps
  501. texture->SetAddressMode(COORD_U, ADDRESS_BORDER);
  502. texture->SetAddressMode(COORD_V, ADDRESS_BORDER),
  503. texture->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
  504. return texture;
  505. }
  506. SharedPtr<Texture2D> Font::LoadFaceTexture(SharedPtr<Image> image)
  507. {
  508. SharedPtr<Texture2D> texture = CreateFaceTexture();
  509. if (!texture->Load(image, true))
  510. {
  511. LOGERROR("Could not load texture from image resource");
  512. return SharedPtr<Texture2D>();
  513. }
  514. return texture;
  515. }
  516. FontFace* Font::GetFaceFreeType(int pointSize)
  517. {
  518. // Create & initialize FreeType library if it does not exist yet
  519. FreeTypeLibrary* freeType = GetSubsystem<FreeTypeLibrary>();
  520. if (!freeType)
  521. context_->RegisterSubsystem(freeType = new FreeTypeLibrary(context_));
  522. // Ensure the FreeType library is kept alive as long as TTF font resources exist
  523. freeType_ = freeType;
  524. UI* ui = GetSubsystem<UI>();
  525. int maxTextureSize = ui->GetMaxFontTextureSize();
  526. FT_Face face;
  527. FT_Error error;
  528. FT_Library library = freeType->GetLibrary();
  529. if (pointSize <= 0)
  530. {
  531. LOGERROR("Zero or negative point size");
  532. return 0;
  533. }
  534. if (!fontDataSize_)
  535. {
  536. LOGERROR("Could not create font face from zero size data");
  537. return 0;
  538. }
  539. error = FT_New_Memory_Face(library, &fontData_[0], fontDataSize_, 0, &face);
  540. if (error)
  541. {
  542. LOGERROR("Could not create font face");
  543. return 0;
  544. }
  545. error = FT_Set_Char_Size(face, 0, pointSize * 64, FONT_DPI, FONT_DPI);
  546. if (error)
  547. {
  548. FT_Done_Face(face);
  549. LOGERROR("Could not set font point size " + String(pointSize));
  550. return 0;
  551. }
  552. SharedPtr<FontFace> newFace(new FontFace(this));
  553. newFace->face_ = face;
  554. FT_GlyphSlot slot = face->glyph;
  555. unsigned numGlyphs = 0;
  556. // Build glyph mapping
  557. FT_UInt glyphIndex;
  558. FT_ULong charCode = FT_Get_First_Char(face, &glyphIndex);
  559. while (glyphIndex != 0)
  560. {
  561. numGlyphs = Max((int)glyphIndex + 1, (int)numGlyphs);
  562. newFace->glyphMapping_[charCode] = glyphIndex;
  563. charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
  564. }
  565. LOGDEBUGF("Font face %s (%dpt) has %d glyphs", GetFileName(GetName()).CString(), pointSize, numGlyphs);
  566. // Load each of the glyphs to see the sizes & store other information
  567. int maxWidth = 0;
  568. int maxHeight = 0;
  569. int loadMode = ui->GetForceAutoHint() ? FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT;
  570. int ascender = face->size->metrics.ascender >> 6;
  571. int descender = face->size->metrics.descender >> 6;
  572. // Check if the font's OS/2 info gives different (larger) values for ascender & descender
  573. TT_OS2* os2Info = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
  574. if (os2Info)
  575. {
  576. ascender = Max(ascender, os2Info->usWinAscent * face->size->metrics.y_ppem / face->units_per_EM);
  577. ascender = Max(ascender, os2Info->sTypoAscender * face->size->metrics.y_ppem / face->units_per_EM);
  578. descender = Max(descender, os2Info->usWinDescent * face->size->metrics.y_ppem / face->units_per_EM);
  579. descender = Max(descender, os2Info->sTypoDescender * face->size->metrics.y_ppem / face->units_per_EM);
  580. }
  581. // Store point size and row height. Use the maximum of ascender + descender, or the face's stored default row height
  582. newFace->pointSize_ = pointSize;
  583. newFace->rowHeight_ = Max(ascender + descender, face->size->metrics.height >> 6);
  584. newFace->glyphs_.Reserve(numGlyphs);
  585. for (unsigned i = 0; i < numGlyphs; ++i)
  586. {
  587. FontGlyph newGlyph;
  588. error = FT_Load_Glyph(face, i, loadMode);
  589. if (!error)
  590. {
  591. // Note: position within texture will be filled later
  592. newGlyph.width_ = (short)Max(slot->metrics.width >> 6, slot->bitmap.width);
  593. newGlyph.height_ = (short)Max(slot->metrics.height >> 6, slot->bitmap.rows);
  594. newGlyph.offsetX_ = (short)(slot->metrics.horiBearingX >> 6);
  595. newGlyph.offsetY_ = (short)(ascender - (slot->metrics.horiBearingY >> 6));
  596. newGlyph.advanceX_ = (short)(slot->metrics.horiAdvance >> 6);
  597. maxWidth = Max(maxWidth, newGlyph.width_);
  598. maxHeight = Max(maxHeight, newGlyph.height_);
  599. }
  600. else
  601. {
  602. newGlyph.width_ = 0;
  603. newGlyph.height_ = 0;
  604. newGlyph.offsetX_ = 0;
  605. newGlyph.offsetY_ = 0;
  606. newGlyph.advanceX_ = 0;
  607. }
  608. newFace->glyphs_.Push(newGlyph);
  609. }
  610. // Store kerning if face has kerning information
  611. if (FT_HAS_KERNING(face))
  612. {
  613. newFace->hasKerning_ = true;
  614. /*
  615. // Would out of memory crash when use large font file, for example these are 29354 glyphs in msyh.ttf
  616. for (unsigned i = 0; i < numGlyphs; ++i)
  617. {
  618. for (unsigned j = 0; j < numGlyphs; ++j)
  619. {
  620. FT_Vector vector;
  621. FT_Get_Kerning(face, i, j, FT_KERNING_DEFAULT, &vector);
  622. newFace->glyphs_[i].kerning_[j] = (short)(vector.x >> 6);
  623. }
  624. }
  625. */
  626. FT_ULong tag = FT_MAKE_TAG('k', 'e', 'r', 'n');
  627. FT_ULong kerningTableSize = 0;
  628. FT_Error error = FT_Load_Sfnt_Table(face, tag, 0, NULL, &kerningTableSize);
  629. if (error)
  630. {
  631. LOGERROR("Could not get kerning table length");
  632. return 0;
  633. }
  634. SharedArrayPtr<unsigned char> kerningTable(new unsigned char[kerningTableSize]);
  635. error = FT_Load_Sfnt_Table(face, tag, 0, kerningTable, &kerningTableSize);
  636. if (error)
  637. {
  638. LOGERROR("Could not load kerning table");
  639. return 0;
  640. }
  641. // Convert big endian to little endian
  642. for (unsigned i = 0; i < kerningTableSize; i += 2)
  643. Swap(kerningTable[i], kerningTable[i + 1]);
  644. MemoryBuffer deserializer(kerningTable, kerningTableSize);
  645. unsigned short version = deserializer.ReadUShort();
  646. if (version == 0)
  647. {
  648. unsigned numKerningTables = deserializer.ReadUShort();
  649. for (unsigned i = 0; i < numKerningTables; ++i)
  650. {
  651. unsigned short version = deserializer.ReadUShort();
  652. unsigned short length = deserializer.ReadUShort();
  653. unsigned short coverage = deserializer.ReadUShort();
  654. if (version == 0 && coverage == 1)
  655. {
  656. unsigned numKerningPairs = deserializer.ReadUShort();
  657. // Skip searchRange, entrySelector & rangeShift
  658. deserializer.Seek(deserializer.GetPosition() + 3 * sizeof(unsigned short));
  659. for (unsigned j = 0; j < numKerningPairs; ++j)
  660. {
  661. unsigned leftIndex = deserializer.ReadUShort();
  662. unsigned rightIndex = deserializer.ReadUShort();
  663. short amount = (short)(deserializer.ReadShort() >> 6);
  664. if (leftIndex < numGlyphs && rightIndex < numGlyphs)
  665. newFace->glyphs_[leftIndex].kerning_[rightIndex] = amount;
  666. else
  667. LOGWARNING("Out of range glyph index in kerning information");
  668. }
  669. }
  670. else
  671. LOGWARNING("Can not read kerning information: unsupported version or coverage");
  672. }
  673. }
  674. else
  675. LOGWARNING("Can not read kerning information: not version 0");
  676. }
  677. // Now try to pack into the smallest possible texture. If face does not fit into one texture, enable dynamic mode where
  678. // glyphs are only created as necessary
  679. if (newFace->RenderAllGlyphs(maxTextureSize, maxTextureSize))
  680. {
  681. FT_Done_Face(face);
  682. newFace->face_ = 0;
  683. }
  684. else
  685. {
  686. if (ui->GetUseMutableGlyphs())
  687. newFace->SetupMutableGlyphs(maxTextureSize, maxTextureSize, maxWidth, maxHeight);
  688. else
  689. newFace->SetupNextTexture(maxTextureSize, maxTextureSize);
  690. }
  691. faces_[pointSize] = newFace;
  692. return newFace;
  693. }
  694. FontFace* Font::GetFaceBitmap(int pointSize)
  695. {
  696. SharedPtr<XMLFile> xmlReader(new XMLFile(context_));
  697. MemoryBuffer memoryBuffer(fontData_, fontDataSize_);
  698. if (!xmlReader->Load(memoryBuffer))
  699. {
  700. LOGERROR("Could not load XML file");
  701. return 0;
  702. }
  703. XMLElement root = xmlReader->GetRoot("font");
  704. if (root.IsNull())
  705. {
  706. LOGERROR("Could not find Font element");
  707. return 0;
  708. }
  709. XMLElement pagesElem = root.GetChild("pages");
  710. if (pagesElem.IsNull())
  711. {
  712. LOGERROR("Could not find Pages element");
  713. return 0;
  714. }
  715. SharedPtr<FontFace> newFace(new FontFace(this));
  716. XMLElement infoElem = root.GetChild("info");
  717. if (!infoElem.IsNull())
  718. newFace->pointSize_ = infoElem.GetInt("size");
  719. XMLElement commonElem = root.GetChild("common");
  720. newFace->rowHeight_ = commonElem.GetInt("lineHeight");
  721. unsigned pages = commonElem.GetInt("pages");
  722. newFace->textures_.Reserve(pages);
  723. ResourceCache* resourceCache = GetSubsystem<ResourceCache>();
  724. String fontPath = GetPath(GetName());
  725. unsigned totalTextureSize = 0;
  726. XMLElement pageElem = pagesElem.GetChild("page");
  727. for (unsigned i = 0; i < pages; ++i)
  728. {
  729. if (pageElem.IsNull())
  730. {
  731. LOGERROR("Could not find Page element for page: " + String(i));
  732. return 0;
  733. }
  734. // Assume the font image is in the same directory as the font description file
  735. String textureFile = fontPath + pageElem.GetAttribute("file");
  736. // Load texture manually to allow controlling the alpha channel mode
  737. SharedPtr<File> fontFile = resourceCache->GetFile(textureFile);
  738. SharedPtr<Image> fontImage(new Image(context_));
  739. if (!fontFile || !fontImage->Load(*fontFile))
  740. {
  741. LOGERROR("Failed to load font image file");
  742. return 0;
  743. }
  744. SharedPtr<Texture2D> texture = LoadFaceTexture(fontImage);
  745. if (!texture)
  746. return 0;
  747. newFace->textures_.Push(texture);
  748. totalTextureSize += fontImage->GetWidth() * fontImage->GetHeight() * fontImage->GetComponents();
  749. pageElem = pageElem.GetNext("page");
  750. }
  751. XMLElement charsElem = root.GetChild("chars");
  752. int count = charsElem.GetInt("count");
  753. newFace->glyphs_.Reserve(count);
  754. unsigned index = 0;
  755. XMLElement charElem = charsElem.GetChild("char");
  756. while (!charElem.IsNull())
  757. {
  758. int id = charElem.GetInt("id");
  759. FontGlyph glyph;
  760. glyph.x_ = charElem.GetInt("x");
  761. glyph.y_ = charElem.GetInt("y");
  762. glyph.width_ = charElem.GetInt("width");
  763. glyph.height_ = charElem.GetInt("height");
  764. glyph.offsetX_ = charElem.GetInt("xoffset");
  765. glyph.offsetY_ = charElem.GetInt("yoffset");
  766. glyph.advanceX_ = charElem.GetInt("xadvance");
  767. glyph.page_ = charElem.GetInt("page");
  768. newFace->glyphs_.Push(glyph);
  769. newFace->glyphMapping_[id] = index++;
  770. charElem = charElem.GetNext("char");
  771. }
  772. XMLElement kerningsElem = root.GetChild("kernings");
  773. if (kerningsElem.IsNull())
  774. newFace->hasKerning_ = false;
  775. else
  776. {
  777. XMLElement kerningElem = kerningsElem.GetChild("kerning");
  778. while (!kerningElem.IsNull())
  779. {
  780. int first = kerningElem.GetInt("first");
  781. HashMap<unsigned, unsigned>::Iterator i = newFace->glyphMapping_.Find(first);
  782. if (i != newFace->glyphMapping_.End())
  783. {
  784. int second = kerningElem.GetInt("second");
  785. int amount = kerningElem.GetInt("amount");
  786. FontGlyph& glyph = newFace->glyphs_[i->second_];
  787. glyph.kerning_[second] = amount;
  788. }
  789. kerningElem = kerningElem.GetNext("kerning");
  790. }
  791. }
  792. LOGDEBUGF("Bitmap font face %s has %d glyphs", GetFileName(GetName()).CString(), count);
  793. SetMemoryUse(GetMemoryUse() + totalTextureSize);
  794. faces_[pointSize] = newFace;
  795. return newFace;
  796. }
  797. unsigned Font::ConvertFormatToNumComponents(unsigned format)
  798. {
  799. if (format == Graphics::GetRGBAFormat())
  800. return 4;
  801. else if (format == Graphics::GetRGBFormat())
  802. return 3;
  803. else if (format == Graphics::GetLuminanceAlphaFormat())
  804. return 2;
  805. else
  806. return 1;
  807. }
  808. SharedPtr<FontFace> Font::Pack(FontFace* fontFace)
  809. {
  810. // Set parent font as null for the packed face so that it does not attempt to manage the font's total memory use
  811. SharedPtr<FontFace> packedFontFace(new FontFace((Font*)0));
  812. int maxTextureSize = GetSubsystem<UI>()->GetMaxFontTextureSize();
  813. // Clone properties
  814. packedFontFace->pointSize_ = fontFace->pointSize_;
  815. packedFontFace->rowHeight_ = fontFace->rowHeight_;
  816. packedFontFace->hasKerning_ = fontFace->hasKerning_;
  817. // Assume that format is the same for all textures and that bitmap font type may have more than one component
  818. unsigned components = ConvertFormatToNumComponents(fontFace->textures_[0]->GetFormat());
  819. // Save the existing textures as image resources
  820. Vector<SharedPtr<Image> > images(fontFace->textures_.Size());
  821. for (unsigned i = 0; i < fontFace->textures_.Size(); ++i)
  822. images[i] = SaveFaceTexture(fontFace->textures_[i]);
  823. // Reallocate used glyphs to new texture(s)
  824. unsigned page = 0;
  825. unsigned index = 0;
  826. unsigned startIndex = 0;
  827. HashMap<unsigned, unsigned>::ConstIterator startIter = fontFace->glyphMapping_.Begin();
  828. HashMap<unsigned, unsigned>::ConstIterator i;
  829. while (startIter != fontFace->glyphMapping_.End())
  830. {
  831. AreaAllocator allocator(FONT_TEXTURE_MIN_SIZE, FONT_TEXTURE_MIN_SIZE, maxTextureSize, maxTextureSize);
  832. for (i = startIter; i != fontFace->glyphMapping_.End(); ++i)
  833. {
  834. FontGlyph glyph = fontFace->glyphs_[i->second_];
  835. if (!glyph.used_)
  836. continue;
  837. if (glyph.width_ && glyph.height_)
  838. {
  839. int x, y;
  840. // Reserve an empty border between glyphs for filtering
  841. if (allocator.Allocate(glyph.width_ + 1, glyph.height_ + 1, x, y))
  842. {
  843. glyph.x_ = x;
  844. glyph.y_ = y;
  845. glyph.page_ = page;
  846. }
  847. else
  848. break;
  849. }
  850. packedFontFace->glyphs_.Push(glyph);
  851. packedFontFace->glyphMapping_[i->first_] = index++;
  852. }
  853. int texWidth = allocator.GetWidth();
  854. int texHeight = allocator.GetHeight();
  855. // Create the image for rendering the fonts
  856. SharedPtr<Image> image(new Image(context_));
  857. image->SetSize(texWidth, texHeight, components);
  858. // First clear the whole image
  859. unsigned char* imageData = image->GetData();
  860. for (int y = 0; y < texHeight; ++y)
  861. {
  862. unsigned char* dest = imageData + components * texWidth * y;
  863. memset(dest, 0, components * texWidth);
  864. }
  865. // Then render the glyphs into new image
  866. for (HashMap<unsigned, unsigned>::ConstIterator j = startIter; j != i; ++j)
  867. {
  868. FontGlyph glyph = fontFace->glyphs_[j->second_];
  869. if (!glyph.used_)
  870. continue;
  871. if (!glyph.width_ || !glyph.height_)
  872. {
  873. ++startIndex;
  874. continue;
  875. }
  876. FontGlyph packedGlyph = packedFontFace->glyphs_[startIndex++];
  877. Image* image = images[glyph.page_];
  878. unsigned char* source = image->GetData() + components * (image->GetWidth() * glyph.y_ + glyph.x_);
  879. unsigned char* destination = imageData + components * (texWidth * packedGlyph.y_ + packedGlyph.x_);
  880. for (int i = 0; i < glyph.height_; ++i)
  881. {
  882. memcpy(destination, source, components * glyph.width_);
  883. source += components * image->GetWidth();
  884. destination += components * texWidth;
  885. }
  886. }
  887. // Finally load image into the texture
  888. SharedPtr<Texture2D> texture = LoadFaceTexture(image);
  889. if (!texture)
  890. return SharedPtr<FontFace>();
  891. packedFontFace->textures_.Push(texture);
  892. ++page;
  893. startIter = i;
  894. assert(index == startIndex);
  895. }
  896. return packedFontFace;
  897. }
  898. SharedPtr<Image> Font::SaveFaceTexture(Texture2D* texture)
  899. {
  900. Image* image = new Image(context_);
  901. image->SetSize(texture->GetWidth(), texture->GetHeight(), ConvertFormatToNumComponents(texture->GetFormat()));
  902. if (!static_cast<Texture2D*>(texture)->GetData(0, image->GetData()))
  903. {
  904. delete image;
  905. LOGERROR("Could not save texture to image resource");
  906. return SharedPtr<Image>();
  907. }
  908. return SharedPtr<Image>(image);
  909. }
  910. bool Font::SaveFaceTexture(Texture2D* texture, const String& fileName)
  911. {
  912. SharedPtr<Image> image = SaveFaceTexture(texture);
  913. return image ? image->SavePNG(fileName) : false;
  914. }
  915. }