YSTest  PreAlpha_b500_20140530
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
Font.cpp
浏览该文件的文档.
1 /*
2  © 2009-2014 FrankHB.
3 
4  This file is part of the YSLib project, and may only be used,
5  modified, and distributed under the terms of the YSLib project
6  license, LICENSE.TXT. By continuing to use, modify, or distribute
7  this file you indicate that you have read the license and
8  understand and accept it fully.
9 */
10 
28 #include "Helper/YModules.h"
29 #include YFM_YSLib_Adaptor_Font
30 #include YFM_YSLib_Core_YApplication
31 #include YFM_YSLib_Service_FileSystem
32 #include YFM_Helper_Initialization
33 #include YFM_YCLib_Debug
34 #include <algorithm> // for std::for_each;
35 #include FT_SIZES_H
36 #include FT_BITMAP_H
37 //#include FT_GLYPH_H
38 //#include FT_OUTLINE_H
39 //#include FT_SYNTHESIS_H
40 #include <internal/internal.h> // for FreeType internal macros;
41 #include FT_INTERNAL_OBJECTS_H // for FT_Face_InternalRec_;
42 #include FT_INTERNAL_TRUETYPE_TYPES_H // for TT_Face, TT_FaceRec_;
43 
44 using namespace ystdex;
45 using namespace platform;
46 
47 namespace YSLib
48 {
49 
50 using namespace IO;
51 
52 namespace Drawing
53 {
54 
56 namespace
57 {
58 
60 ::FT_Error
61 N_SetPixelSizes(::FT_FaceRec& face, ::FT_UInt s) ynothrow
62 {
63  ::FT_Size_RequestRec req{FT_SIZE_REQUEST_TYPE_NOMINAL, ::FT_Long(s << 6),
64  ::FT_Long(s << 6), 0, 0};
65 
66  return ::FT_Request_Size(&face, &req);
67 }
68 
73 ::FT_Matrix italic_matrix{0x10000L, 0x0366AL, 0x0000L, 0x10000L};
74 
75 } // unnamed namespace;
76 
77 
78 NativeFontSize::NativeFontSize(::FT_FaceRec& face, FontSize s)
79  : size()
80 {
81  if(const auto err = ::FT_New_Size(&face, &size))
82  throw FontException(err, "Native font size creation failed.");
83  Activate();
84  if(const auto err = N_SetPixelSizes(face, s))
85  throw FontException(err, "Native font setting size failed.");
86 }
88  : size(ns.size)
89 {
90  ns.size = {};
91 }
93 {
94  ::FT_Done_Size(size);
95 }
96 
97 ::FT_SizeRec&
99 {
100  if(YB_UNLIKELY(!size))
101  throw LoggedEvent("Invalid native size found.", Critical);
102  return *size;
103 }
104 
105 void
107 {
109 
110  auto face(size->face);
111 
113  face->size = size;
114 }
115 
116 
118  : Cache(cache), family_name(name), mFaces()
119 {}
120 
121 void
123 {
124  mFaces.insert(make_pair(face.GetStyleName(), &face));
125 }
126 
127 bool
129 {
130  return mFaces.erase(face.GetStyleName()) != 0;
131 }
132 
133 Typeface*
135 {
136  Typeface* const p(GetTypefacePtr(FetchName(fs)));
137 
138  return p ? p : (fs == FontStyle::Regular ? nullptr
139  : GetTypefacePtr("Regular"));
140 }
141 Typeface*
142 FontFamily::GetTypefacePtr(const StyleName& style_name) const
143 {
144  const auto i(mFaces.find(style_name));
145 
146  return (i == mFaces.cend()) ? nullptr : i->second;
147 }
148 Typeface&
150 {
151  const auto p(GetTypefacePtr(fs));
152 
153  if(YB_UNLIKELY(!p))
154  throw LoggedEvent("No matching face found.", Critical);
155  return *p;
156 }
157 Typeface&
158 FontFamily::GetTypefaceRef(const StyleName& style_name) const
159 {
160  const auto p(GetTypefacePtr(style_name));
161 
162  if(YB_UNLIKELY(!p))
163  throw LoggedEvent("No matching face found.", Critical);
164  return *p;
165 }
166 
167 
169 {
170  if(slot && slot->format == FT_GLYPH_FORMAT_BITMAP)
171  {
172  auto& bitmap(slot->bitmap);
173 
174  if(bool(style & FontStyle::Bold))
175  {
176  const auto library(slot->library);
177  const auto face(slot->face);
178  ::FT_Pos xstr(FT_MulFix(face->units_per_EM,
179  face->size->metrics.y_scale) / 24 & ~63), ystr(xstr);
180 
181  if(xstr == 0)
182  xstr = 1 << 6;
183  if(::FT_GlyphSlot_Own_Bitmap(slot) == FT_Err_Ok
184  && ::FT_Bitmap_Embolden(library, &bitmap, xstr, ystr)
185  == FT_Err_Ok)
186  {
187  if(slot->advance.x)
188  slot->advance.x += xstr;
189  if(slot->advance.y)
190  slot->advance.y += ystr;
191  {
192  auto& metrics(slot->metrics);
193 
194  yunseq(metrics.width += xstr, metrics.height += ystr,
195  metrics.horiAdvance += xstr,
196  metrics.vertAdvance += ystr);
197  }
198  slot->bitmap_top += ::FT_Int(ystr >> 6);
199  }
200  }
201 
202  const ::FT_Pos xadvance((slot->advance.x + 32) >> 6),
203  yadvance((slot->advance.y + 32) >> 6);
204  ::FT_Int temp;
205 
206 #define SBIT_CHECK_CHAR(d) (temp = ::FT_Char(d), temp == d)
207 #define SBIT_CHECK_BYTE(d) (temp = ::FT_Byte(d), temp == d)
208  if(SBIT_CHECK_BYTE(bitmap.rows) && SBIT_CHECK_BYTE(bitmap.width)
209  && SBIT_CHECK_CHAR(bitmap.pitch)
210  && SBIT_CHECK_CHAR(slot->bitmap_left)
211  && SBIT_CHECK_CHAR(slot->bitmap_top) && SBIT_CHECK_CHAR(xadvance)
212  && SBIT_CHECK_CHAR(yadvance))
213  {
214  sbit = {::FT_Byte(bitmap.width), ::FT_Byte(bitmap.rows),
215  ::FT_Char(slot->bitmap_left), ::FT_Char(slot->bitmap_top),
216  ::FT_Byte(bitmap.pixel_mode), ::FT_Byte(bitmap.num_grays - 1),
217  ::FT_Char(bitmap.pitch), ::FT_Char(xadvance),
218  ::FT_Char(yadvance), bitmap.buffer};
219  bitmap.buffer = {};
220  // XXX: Moving instead of copying should be safe if the library
221  // memory handlers are not customized.
222  // NOTE: Be cautious for DLLs. For documented default behavior, see:
223  // http://www.freetype.org/freetype2/docs/design/design-4.html .
224  return;
225  }
226 #undef SBIT_CHECK_CHAR
227 #undef SBIT_CHECK_BYTE
228  }
229  sbit = {255, 0, 0, 0, 0, 0, 0, 0, 0, nullptr};
230 }
232  : sbit(sbit_dat.sbit)
233 {
234  sbit_dat.sbit.buffer = {};
235 }
237 {
238  // NOTE: See constructor.
239  std::free(sbit.buffer);
240 }
241 
242 
244  : Path(path), face_index(i), cmap_index(-1), style_name(), ref([&, this]{
245  if(YB_UNLIKELY(ystdex::exists(cache.sFaces, this)))
246  throw LoggedEvent("Duplicate typeface found.", Critical);
247 
248  ::FT_Face face;
249  auto error(::FT_New_Face(cache.library, Path.c_str(), face_index,
250  &face));
251 
252  if(YB_LIKELY(!error))
253  if(YB_LIKELY(!(error = ::FT_Select_Charmap(face,
254  FT_ENCODING_UNICODE)) && face))
255  cmap_index = face->charmap
256  ? ::FT_Get_Charmap_Index(face->charmap) : 0;
258  {
259  platform::yprintf("Face request error: %08x\n", error);
260  throw LoggedEvent("Face loading failed.", Critical);
261  }
262 
263  const FamilyName family_name(face->family_name);
264  auto& p_ff(cache.mFamilies[family_name]);
265 
266  if(!p_ff)
267  p_ff.reset(new FontFamily(cache, family_name));
268  return pair<std::reference_wrapper<FontFamily>,
269  std::reference_wrapper<::FT_FaceRec_>>(*p_ff.get(), *face);
271 {
272  YAssert(::FT_UInt(cmap_index) < ::FT_UInt(ref.second.get().num_charmaps),
273  "Invalid CMap index found.");
274  style_name = ref.second.get().style_name;
275  ref.first.get() += *this;
276 }
278 {
279  size_cache.clear();
280  glyph_index_cache.clear();
281  bitmap_cache.clear();
282  ref.first.get() -= *this;
283 
284  const auto face(&ref.second.get());
285 
286  YAssertNonnull(face);
287  YAssert(face->internal->refcount == 1,
288  "Invalid face reference count found.");
289  // XXX: Hack for using %ttmtx.c and %sfobjs.c of FreeType 2.4.11.
290  if(FT_IS_SFNT(face))
291  {
292  const auto ttface(reinterpret_cast<::TT_Face>(face));
293 
294  // NOTE: See %Typeface::SmallBitmapData::SmallBitmapData.
295  // NOTE: %sfnt_done_face in "sfobjs.c" still releases vertical metrics.
296  std::free(ttface->horizontal.long_metrics),
297  std::free(ttface->horizontal.short_metrics);
298  }
299  ::FT_Done_Face(face);
300 }
301 
302 bool
304 {
305  return Path == rhs.Path && face_index == rhs.face_index;
306 }
307 bool
308 Typeface::operator<(const Typeface& rhs) const
309 {
310  return Path < rhs.Path
311  || (Path == rhs.Path && face_index < rhs.face_index);
312 }
313 
316 {
317  return CacheLookup(bitmap_cache, key, [&]{
318  LookupSize(key.Size).Activate();
319  ::FT_Set_Transform(&ref.second.get(),
320  bool(key.Style & FontStyle::Italic) ? &italic_matrix : nullptr, {});
321 
322  return SmallBitmapData(::FT_Load_Glyph(&ref.second.get(),
323  key.GlyphIndex, key.Flags | FT_LOAD_RENDER) == 0
324  ? ref.second.get().glyph : nullptr, key.Style);
325  });
326 }
327 
328 ::FT_UInt
330 {
331  auto i(glyph_index_cache.find(c));
332 
333  if(i == glyph_index_cache.end())
334  {
335  if(cmap_index > 0)
336  ::FT_Set_Charmap(&ref.second.get(),
337  ref.second.get().charmaps[cmap_index]);
338 
339  const auto pr(glyph_index_cache.emplace(c, ::FT_Get_Char_Index(
340  &ref.second.get(), ::FT_ULong(c))));
341 
342  if(YB_UNLIKELY(!pr.second))
343  throw LoggedEvent("Glyph index cache insertion failed.", Alert);
344  i = pr.first;
345  }
346  return i->second;
347 }
348 
351 {
352  auto i(size_cache.find(s));
353 
354  if(i == size_cache.end())
355  {
356  const auto pr(size_cache.emplace(s, NativeFontSize(ref.second, s)));
357 
358  if(YB_UNLIKELY(!pr.second))
359  throw LoggedEvent("Bitmap cache insertion failed.", Alert);
360  i = pr.first;
361  }
362  return i->second;
363 }
364 
365 
366 const Typeface&
368 {
369  const Typeface* const pDefaultTypeface(
370  FetchDefaultFontCache().GetDefaultTypefacePtr());
371 
372  if(YB_UNLIKELY(!pDefaultTypeface))
373  throw LoggedEvent("Null default font face pointer found.", Critical);
374  return *pDefaultTypeface;
375 }
376 
377 
378 FontCache::FontCache(size_t /*cache_size*/)
379  : pDefaultFace()
380 {
381  ::FT_Error error;
382 
383  if(YB_LIKELY((error = ::FT_Init_FreeType(&library)) == 0))
384  // TODO: Write log on success.
385  ;
386  else
387  {
388  // TODO: Format without allocating memory.
389  throw LoggedEvent(
390  ystdex::sfmt("Font init failed: %08x\n;", error).c_str(), Alert);
391  }
392 }
394 {
395  ClearContainers();
396  ::FT_Done_FreeType(library);
397 }
398 
399 const FontFamily*
401 {
402  const auto i(mFamilies.find(family_name));
403 
404  return (i == mFamilies.cend()) ? nullptr : i->second.get();
405 }
406 
407 const Typeface*
409 {
410  // NOTE: Guaranteed to be non-null for default typeface in default cache.
411  return pDefaultFace ? pDefaultFace
413 }
414 const Typeface*
416  const StyleName& style_name) const
417 {
418  const FontFamily* f(GetFontFamilyPtr(family_name));
419 
420  if(YB_UNLIKELY(!f))
421  return nullptr;
422  return f->GetTypefacePtr(style_name);
423 }
424 
425 void
426 FontCache::operator+=(unique_ptr<FontFamily> p_family)
427 {
428  mFamilies.emplace(p_family->GetFamilyName(), std::move(p_family));
429 }
430 void
432 {
433  sFaces.insert(&face);
434 }
435 
436 bool
438 {
439  return mFamilies.erase(family.GetFamilyName()) != 0;
440 }
441 bool
443 {
444  return &face != pDefaultFace && sFaces.erase(&face) != 0;
445 }
446 
447 void
449 {
450  std::for_each(sFaces.begin(), sFaces.end(), delete_obj());
451  sFaces.clear();
452  mFamilies.clear();
453 }
454 
455 size_t
457 {
458  if(ufexists(path.c_str()) && !IO::VerifyDirectory(path))
459  {
460  ::FT_Face face(nullptr);
461 
462  if(::FT_New_Face(library, path.c_str(), -1, &face) != 0)
463  return 0;
464 
465  const auto face_num(face->num_faces);
466 
467  ::FT_Done_Face(face);
468  if(face_num < 0)
469  return 0;
470 
471  const size_t face_n(face_num);
472 
473  for(size_t i(0); i < face_n; ++i)
474  try
475  {
476  *this += *(ynew Typeface(*this, path, i));
477  }
478  catch(...)
479  {}
480  return face_n;
481  }
482  return 0;
483 }
484 
485 void
487 {
488  if(YB_LIKELY(!(pDefaultFace || sFaces.empty())))
489  pDefaultFace = *sFaces.begin();
490 }
491 
492 
493 Font::Font(const FontFamily& family, const FontSize size, FontStyle fs)
494  : typeface(family.GetTypefaceRef(fs)), font_size(size), style(fs)
495 {}
496 
497 s8
498 Font::GetAdvance(ucs4_t c, ::FTC_SBit sbit) const
499 {
500  if(YB_UNLIKELY(c == '\t'))
501  return GetAdvance(' ') << 2;
502  if(!sbit)
503  sbit = GetGlyph(c, FT_LOAD_DEFAULT);
504  if(YB_LIKELY(sbit))
505  return sbit->xadvance;
506  return 0;
507 }
508 s8
510 {
511  return GetInternalInfo().ascender >> 6;
512 }
513 s8
514 Font::GetDescender() const
515 {
516  return GetInternalInfo().descender >> 6;
517 }
519 Font::GetGlyph(ucs4_t c, ::FT_UInt flags) const
520 {
521  const auto& typeface(GetTypeface());
522 
523  return &typeface.LookupBitmap(Typeface::BitmapKey{flags,
524  typeface.LookupGlyphIndex(c), font_size, style}).sbit;
525 }
526 FontSize
528 {
529  return GetInternalInfo().height >> 6;
530 }
531 ::FT_Size_Metrics
532 Font::GetInternalInfo() const
533 {
534  return GetTypeface().LookupSize(GetSize()).GetSizeRec().metrics;
535 }
536 
537 void
539 {
540  if(YB_LIKELY(s >= MinimalSize && s <= MaximalSize))
541  font_size = s;
542 }
543 bool
545 {
546  auto p(GetFontFamily().GetTypefacePtr(fs));
547 
548  if(p)
549  {
550  yunseq(typeface = std::ref(*p), style = fs);
551  return true;
552  }
553  return false;
554 }
555 
556 } // namespace Drawing;
557 
558 } // namespace YSLib;
559 
s8 GetAscender() const
取升部。
Definition: Font.cpp:509
void InitializeDefaultTypeface()
初始化默认字型。
Definition: Font.cpp:486
FamilyMap mFamilies
字型家族组索引。
Definition: Font.h:443
std::string FamilyName
字型家族名称。
Definition: Font.h:73
glyph_index_cache()
Definition: Font.cpp:270
void Activate() const
激活当前大小。
Definition: Font.cpp:106
~FontCache()
析构:释放空间。
Definition: Font.cpp:393
NativeFontSize & LookupSize(FontSize) const
since build 420
Definition: Font.cpp:350
bool operator<(const Typeface &) const
比较:严格递增偏序关系。
Definition: Font.cpp:308
friend class Typeface
Definition: Font.h:418
std::uint32_t u32
Definition: yadaptor.h:69
static yconstexpr FontSize MinimalSize
Definition: Font.h:550
bitmap_cache(2047U)
#define SBIT_CHECK_BYTE(d)
一般路径模板。
Definition: path.hpp:149
NativeFontSize(::FT_FaceRec &, FontSize)
Definition: Font.cpp:78
YF_API bool ufexists(const char *) ynothrow
判断指定 UTF-8 文件名的文件是否存在。
FontFamily(FontCache &, const FamilyName &)
使用字体缓存引用和名称构造字型家族。
Definition: Font.cpp:117
::FT_UInt LookupGlyphIndex(ucs4_t) const
Definition: Font.cpp:329
字体异常。
Definition: Font.h:119
const FontFamily font_size::FT_UInt flags
Definition: Font.h:626
::FT_Library library
库实例。
Definition: Font.h:439
#define SBIT_CHECK_CHAR(d)
#define delete_obj
Definition: ycutil.h:438
Typeface * pDefaultFace
默认字型指针。
Definition: Font.h:445
#define ynew
Definition: ynew.h:205
Typeface & GetTypefaceRef(FontStyle) const
Definition: Font.cpp:149
GMRUCache< BitmapKey, SmallBitmapData, BitmapKeyHash > bitmap_cache
Definition: Font.h:277
pair< std::reference_wrapper< FontFamily >, std::reference_wrapper<::FT_FaceRec_ > > ref
Definition: Font.h:274
本机字体大小。
Definition: Font.h:141
bool SetStyle(FontStyle)
设置样式。
Definition: Font.cpp:544
字符位图。
Definition: Font.h:357
const FontFamily GetTypeface()) DefGetter(const ynothrow
SmallBitmapData(::FT_GlyphSlot, FontStyle)
Definition: Font.cpp:168
#define YB_UNLIKELY(expr)
分支预测提示。
Definition: ydef.h:298
sizeof(AlphaType)*GetAreaOf(GetSize())) using CompactPixmap void SetSize(const Size &) override
重新设置缓冲区大小。
#define yunseq
无序列依赖表达式组求值。
Definition: ydef.h:748
std::string StyleName
字型样式名称。
Definition: Font.h:78
pixmap bitmap
Definition: Image.cpp:317
Typeface * GetTypefacePtr(const StyleName &) const
取指定样式名称的字型指针。
Definition: Font.cpp:134
字体缓存。
Definition: Font.h:415
字型标识。
Definition: Font.h:227
#define ynothrow
YSLib 无异常抛出保证:若支持 noexcept 关键字, 指定特定的 noexcept 异常规范。
Definition: ydef.h:514
yconstfn const string & name
Definition: Loader.h:110
FaceMap mFaces
字型组索引类型。
Definition: Font.h:181
YF_API Drawing::FontCache & FetchDefaultFontCache()
取默认字体缓存。
FontCache(size_t=DefaultGlyphCacheSize)
构造:分配指定大小的字形缓存空间。
Definition: Font.cpp:378
bool operator-=(Typeface &)
从字型组和字型组索引中移除指定字型对象。
Definition: Font.cpp:128
std::int8_t s8
Definition: yadaptor.h:71
const FamilyMap mFamilies const FontFamily * GetFontFamilyPtr(const FamilyName &) const
< 取字型家族组索引。
Definition: Font.cpp:400
FontStyle
字体样式。
Definition: Font.h:85
FontStyle style
字体样式。
Definition: Font.h:561
FontSize font_size
Definition: Font.h:556
#define YAssertNonnull(_expr)
Definition: cassert.h:81
::FT_Long face_index
Definition: Font.h:269
YF_API const Typeface & FetchDefaultTypeface()
取默认字型引用。
Definition: Font.cpp:367
std::reference_wrapper< Typeface > typeface
Definition: Font.h:554
_tWidget _fCallable && f
Definition: ywgtevt.h:597
auto CacheLookup(_tMap &cache, const _tKey &key, _fCallable init, _tParams &&...args) -> decltype((cache.begin() ->second))
以指定的关键字查找作为缓存的无序关联容器, 若没有找到使用指定的可调用对象和参数初始化内容。 ...
Definition: Cache.hpp:182
auto error(::FT_New_Face(cache.library, Path.c_str(), face_index,&face))
Typeface(FontCache &, const FontPath &, u32=0)
使用字体缓存引用在指定字体文件路径读取指定索引的字型并构造对象。
void operator+=(Typeface &)
向字型组和字型组索引添加字型对象。
Definition: Font.cpp:122
YF_API int yprintf(const char *,...)
调试模式 printf :显示控制台格式化输出 ,按键继续。
Definition: Debug.cpp:102
::FT_Int cmap_index
Definition: Font.h:270
size_t LoadTypefaces(const FontPath &)
从字体文件组中载入字型信息。
Definition: Font.cpp:456
记录日志的异常事件类。
Definition: yexcept.h:58
bool operator==(const Typeface &) const
比较:相等关系。
Definition: Font.cpp:303
static yconstexpr FontSize MaximalSize
Definition: Font.h:550
std::string FontPath
字体文件路径。
Definition: Font.h:68
unordered_map< FontSize, NativeFontSize > size_cache
Definition: Font.h:281
Typeface::Typeface(FontCache &cache, const FontPath &path, u32 i)::FT_Face face
Definition: Font.cpp:243
char32_t ucs4_t
UCS-4 字符类型。
Definition: chrdef.h:45
~Typeface()
since build 461
Definition: Font.cpp:277
bool exists(const _tCon &con, const _tKey &key)
判断指定的容器中存在指定的键。
Definition: container.hpp:373
#define YB_LIKELY(expr)
Definition: ydef.h:297
std::basic_string< _tChar > sfmt(const _tChar *fmt,...)
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:399
FontSize GetHeight() const ynothrow
取字体对应的字符高度。
Definition: Font.cpp:527
Font()
默认构造:使用默认字型家族、大小和样式的字体对象。
Definition: Font.h:568
const FontPath Path
Definition: Font.h:233
SmallBitmapData & LookupBitmap(const BitmapKey &) const
Definition: Font.cpp:315
auto & p_ff(cache.mFamilies[family_name])
FaceSet sFaces
字型组。
Definition: Font.h:442
unordered_map< ucs4_t,::FT_UInt > glyph_index_cache
Definition: Font.h:279
字型家族 (Typeface Family) 标识。
Definition: Font.h:170
::FT_SizeRec & GetSizeRec() const
Definition: Font.cpp:98
const Typeface * GetTypefacePtr(const FamilyName &, const StyleName &) const
取指定名称的字型指针。
Definition: Font.cpp:415
bool operator-=(FontFamily &)
从字型家族组中移除指定字型对象。
Definition: Font.cpp:437
#define YAssert(_expr, _msg)
Definition: cassert.h:73
u8 FontSize
字体大小。
Definition: Font.h:63
void operator+=(unique_ptr< FontFamily >)
向字型家族组添加字型家族。
Definition: Font.cpp:426
const Typeface * GetDefaultTypefacePtr() const
取默认字型指针。
Definition: Font.cpp:408
void ClearContainers()
清除容器。
Definition: Font.cpp:448