YSTest  PreAlpha_b400_20130424
The YSLib Test Project
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 宏定义  
Font.cpp
浏览该文件的文档.
1 /*
2  Copyright by FrankHB 2009 - 2013.
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 "YSLib/Adaptor/Font.h"
29 #include "YSLib/Core/yapp.h"
30 #include "YSLib/Core/yexcept.h"
31 #include "YSLib/Core/yfilesys.h"
32 #include <Helper/GUIApplication.h>
33 #include "YCLib/Debug.h"
34 #include <algorithm> // for std::for_each;
35 //#include FT_BITMAP_H
36 //#include FT_GLYPH_H
37 //#include FT_OUTLINE_H
38 //#include FT_SYNTHESIS_H
39 
40 using namespace ystdex;
41 using namespace platform;
42 
44 
45 using namespace IO;
46 
47 YSL_BEGIN_NAMESPACE(Drawing)
48 
49 
54 ::FT_Error
55 simpleFaceRequester(::FTC_FaceID face_id, ::FT_Library library,
56  ::FT_Pointer, ::FT_Face* aface)
57 {
58  Typeface* fontFace(static_cast<Typeface*>(face_id));
59  ::FT_Face& face(*aface);
60  ::FT_Error error(FT_New_Face(library, fontFace->Path.c_str(),
61  fontFace->face_index, aface));
62 
63  if(YB_LIKELY(!error))
64  {
65  error = ::FT_Select_Charmap(face, FT_ENCODING_UNICODE);
66  if(YB_LIKELY(!error && face))
67  {
68  fontFace->cmap_index = face->charmap
69  ? ::FT_Get_Charmap_Index(face->charmap) : 0;
70 #if 0
71  fontFace->nGlyphs = face->num_glyphs;
72  fontFace->uUnitPerEM = face->units_per_EM;
73  fontFace->nCharmaps = face->num_charmaps;
74  if(FT_IS_SCALABLE(face))
75  fontFace->lUnderlinePos = FT_MulFix(face->underline_position,
76  face->size->metrics.y_scale) >> 6;
77  fontFace->fixSizes.clear();
78  if(face->available_sizes)
79  {
80  ::FT_Int t = face->num_fixed_sizes;
81 
82  fontFace->fixSizes.reserve(t);
83  for(::FT_Int i = 0; i < t; ++i)
84  fontFace->fixSizes.push_back(
85  face->available_sizes[i].size >> 6);
86  }
87 
88 #endif
89  }
90  }
91 #if 0
92  // FIXME: wrong impl;
93  ::FT_GlyphSlot_Embolden(face->glyph);
94  ::FT_GlyphSlot_Oblique(face->glyph);
95  ::FT_Outline_Embolden(&face->glyph->outline, 64);
96  ::FT_Set_Transform(face, &fontFace->matrix, nullptr);
97 #endif
98  if(YB_UNLIKELY(error))
99  platform::yprintf("Face request error: %08x\n", error);
100  return error;
101 }
102 
103 
104 FontFamily::FontFamily(FontCache& cache, const FamilyName& name)
105  : Cache(cache), family_name(name), mFaces()
106 {}
107 
108 void
110 {
111  mFaces.insert(make_pair(face.GetStyleName(), &face));
112 }
113 
114 bool
116 {
117  return mFaces.erase(face.GetStyleName()) != 0;
118 }
119 
120 Typeface*
122 {
123  Typeface* const p(GetTypefacePtr(FetchName(fs)));
124 
125  return p ? p : (fs == FontStyle::Regular ? nullptr
126  : GetTypefacePtr("Regular"));
127 }
128 Typeface*
129 FontFamily::GetTypefacePtr(const StyleName& style_name) const
130 {
131  const auto i(mFaces.find(style_name));
132 
133  return (i == mFaces.cend()) ? nullptr : i->second;
134 }
135 
136 
137 /*const ::FT_Matrix Typeface::MNormal = {0x10000, 0, 0, 0x10000},
138  Typeface::MOblique = {0x10000, 0x5800, 0, 0x10000};*/
139 
140 Typeface::Typeface(FontCache& cache, const FontPath& path, u32 i
141  /*, const bool bb, const bool bi, const bool bu*/)
142  : Path(path), face_index(i), cmap_index(-1)
143 /* , bBold(bb), bOblique(bi), bUnderline(bu),
144  , matrix(bi ? MOblique : MNormal)*/
145 {
146  if(YB_UNLIKELY(cache.sFaces.find(this) != cache.sFaces.end()))
147  throw LoggedEvent("Duplicate typeface found.", 2);
148 
149  ::FTC_FaceID new_face_id(this);
150  ::FT_Face face(nullptr);
151 
152  //读取字型名称并构造名称映射。
153  if(YB_UNLIKELY(FTC_Manager_LookupFace(cache.manager, new_face_id, &face)
154  != 0 || !face))
155  throw LoggedEvent("Face loading failed.", 2);
156 
157  const FamilyName family_name(face->family_name);
158  const auto it(cache.mFamilies.find(family_name));
159  const bool not_found(it == cache.mFamilies.end());
160 
161  yunseq(pFontFamily = not_found ? ynew FontFamily(cache, family_name)
162  : it->second, style_name = face->style_name);
163  if(YB_LIKELY(not_found))
164  cache += *pFontFamily;
165  *pFontFamily += *this;
166 }
167 
168 bool
170 {
171  return Path == rhs.Path && face_index == rhs.face_index;
172 }
173 bool
174 Typeface::operator<(const Typeface& rhs) const
175 {
176  return Path < rhs.Path
177  || (Path == rhs.Path && face_index < rhs.face_index);
178 }
179 
180 
181 const Typeface&
183 {
184  const Typeface* const pDefaultTypeface(
185  FetchDefaultFontCache().GetDefaultTypefacePtr());
186 
187  if(YB_UNLIKELY(!pDefaultTypeface))
188  throw LoggedEvent("Null default font face pointer found.");
189  return *pDefaultTypeface;
190 }
191 
192 
193 FontCache::FontCache(size_t cache_size)
194  : pDefaultFace()
195 {
196  ::FT_Error error;
197 
198  if(YB_LIKELY((error = ::FT_Init_FreeType(&library)) == 0
199  && (error = ::FTC_Manager_New(library, 0, 0, cache_size,
200  &simpleFaceRequester, nullptr, &manager)) == 0
201  && (error = ::FTC_SBitCache_New(manager, &sbitCache)) == 0
202  && (error = ::FTC_CMapCache_New(manager, &cmapCache)) == 0))
203  {
204  // TODO: Write log on success.
205  }
206  else
207  {
208  // TODO: Format without allocating memory.
209  throw LoggedEvent(
210  ystdex::sfmt("Font init failed: %08x\n;", error).c_str(), 1);
211  }
212 }
214 {
215  ::FTC_Manager_Done(manager);
216  ::FT_Done_FreeType(library);
217  ClearContainers();
218 }
219 
220 const FontFamily*
221 FontCache::GetFontFamilyPtr(const FamilyName& family_name) const
222 {
223  const auto i(mFamilies.find(family_name));
224 
225  return (i == mFamilies.cend()) ? nullptr : i->second;
226 }
227 
228 const Typeface*
230 {
231  // NOTE: Guaranteed to be non-null for default typeface in default cache.
232  return pDefaultFace ? pDefaultFace
233  : FetchDefaultFontCache().GetDefaultTypefacePtr();
234 }
235 const Typeface*
237  const StyleName& style_name) const
238 {
239  const FontFamily* f(GetFontFamilyPtr(family_name));
240 
241  if(YB_UNLIKELY(!f))
242  return nullptr;
243  return f->GetTypefacePtr(style_name);
244 }
245 ::FT_Face
247 {
248  ::FT_Face face(nullptr);
249 
250  if(YB_LIKELY(pFace))
251  ::FTC_Manager_LookupFace(manager, pFace, &face);
252  return face;
253 }
254 
255 void
257 {
258  mFamilies.insert(make_pair(family.GetFamilyName(), &family));
259 }
260 void
261 FontCache::operator+=(Typeface& face)
262 {
263  sFaces.insert(&face);
264 }
265 
266 bool
267 FontCache::operator-=(FontFamily& family)
268 {
269  return mFamilies.erase(family.GetFamilyName()) != 0;
270 }
271 bool
272 FontCache::operator-=(Typeface& face)
273 {
274  return &face != pDefaultFace && sFaces.erase(&face) != 0;
275 }
276 
277 void
279 {
280  ClearContainers();
281  FTC_Manager_Reset(manager);
282 }
283 
284 void
286 {
287  std::for_each(sFaces.begin(), sFaces.end(), delete_obj());
288  sFaces.clear();
289  std::for_each(mFamilies.begin(), mFamilies.end(), delete_second_mem());
290  mFamilies.clear();
291 }
292 
293 void
294 FontCache::LoadTypeface(const FontPath& path, size_t idx) ynothrow
295 {
296  try
297  {
298  *this += *(ynew Typeface(*this, path, idx));
299  }
300  catch(...)
301  {}
302 }
303 
304 size_t
306 {
307  if(GetFileNameOf(path.c_str()) && fexists(path.c_str()))
308  {
309  ::FT_Face face(nullptr);
310 
311  if(::FT_New_Face(library, path.c_str(), -1, &face) != 0)
312  return 0;
313 
314  const auto face_num(face->num_faces);
315 
316  ::FT_Done_Face(face);
317  if(face_num < 0)
318  return 0;
319 
320  const size_t face_n(face_num);
321 
322  for(size_t i(0); i < face_n; ++i)
323  LoadTypeface(path, i);
324  return face_n;
325  }
326  return 0;
327 }
328 
329 void
331 {
332  if(YB_LIKELY(!(pDefaultFace || sFaces.empty())))
333  pDefaultFace = *sFaces.begin();
334 }
335 
336 
337 Font::Font(const FontFamily& family, const FontSize size, FontStyle fs)
338  : scaler{family.GetTypefacePtr(fs), size, size, 1, 0, 0}, style(fs)
339 {
340  if(YB_UNLIKELY(!scaler.face_id))
341  throw LoggedEvent("Bad font found.");
342 }
343 
344 s8
345 Font::GetAdvance(ucs4_t c, FTC_SBit sbit) const
346 {
347  if(YB_UNLIKELY(c == '\t'))
348  return GetAdvance(' ') << 2;
349  if(!sbit)
350  sbit = GetGlyph(c, FT_LOAD_DEFAULT);
351  if(YB_LIKELY(sbit))
352  return sbit->xadvance;
353  return 0;
354 }
355 s8
357 {
358  return GetInternalInfo().metrics.ascender >> 6;
359 }
360 s8
362 {
363  return GetInternalInfo().metrics.descender >> 6;
364 }
366 Font::GetGlyph(ucs4_t c, ::FT_UInt flags) const
367 {
368  auto pFace(&GetTypeface());
369  auto& cache(GetCache());
370  FTC_SBit sbit;
371 
372  ::FTC_SBitCache_LookupScaler(cache.sbitCache, &scaler, flags,
373  ::FTC_CMapCache_Lookup(cache.cmapCache, scaler.face_id,
374  pFace->GetCMapIndex(), c), &sbit, nullptr);
375  return sbit;
376 }
377 FontSize
379 {
380  return GetInternalInfo().metrics.height >> 6;
381 }
382 FT_SizeRec&
384 {
385  ::FT_Size size(nullptr);
386 
387  if(YB_UNLIKELY(::FTC_Manager_LookupSize(GetCache().manager, &scaler, &size)
388  != 0))
389  throw LoggedEvent("Size lookup failed.");
390  return *size;
391 }
392 
393 void
395 {
396  if(YB_LIKELY(s >= MinimalSize && s <= MaximalSize))
397  yunseq(scaler.width = s, scaler.height = s);
398 }
399 bool
401 {
402  auto pFace(GetFontFamily().GetTypefacePtr(fs));
403 
404  if(pFace)
405  {
406  scaler.face_id = pFace;
407  return true;
408  }
409  return false;
410 }
411 
412 YSL_END_NAMESPACE(Drawing)
413 
414 YSL_END
415