YSTest: Font.cpp 源文件

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
43 YSL_BEGIN
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
109 FontFamily::operator+=(Typeface& face)
110 {
111 mFaces.insert(make_pair(face.GetStyleName(), &face));
112 }
113
114 bool
115 FontFamily::operator-=(Typeface& face)
116 {
117 return mFaces.erase(face.GetStyleName()) != 0;
118 }
119
120 Typeface*
121 FontFamily::GetTypefacePtr(FontStyle fs) const
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
169 Typeface::operator==(const Typeface& rhs) const
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&
182 FetchDefaultTypeface() ythrow(LoggedEvent)
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 }
213 FontCache::~FontCache()
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*
229 FontCache::GetDefaultTypefacePtr() const ythrow(LoggedEvent)
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*
236 FontCache::GetTypefacePtr(const FamilyName& family_name,
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
246 FontCache::GetNativeFace(Typeface* pFace) const
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
256 FontCache::operator+=(FontFamily& family)
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
278 FontCache::ClearCache()
279 {
280 ClearContainers();
281 FTC_Manager_Reset(manager);
282 }
283
284 void
285 FontCache::ClearContainers()
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
305 FontCache::LoadTypefaces(const FontPath& path)
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
330 FontCache::InitializeDefaultTypeface()
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
356 Font::GetAscender() const
357 {
358 return GetInternalInfo().metrics.ascender >> 6;
359 }
360 s8
361 Font::GetDescender() const
362 {
363 return GetInternalInfo().metrics.descender >> 6;
364 }
365 CharBitmap
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
378 Font::GetHeight() const ynothrow
379 {
380 return GetInternalInfo().metrics.height >> 6;
381 }
382 FT_SizeRec&
383 Font::GetInternalInfo() const
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
394 Font::SetSize(FontSize s)
395 {
396 if(YB_LIKELY(s >= MinimalSize && s <= MaximalSize))
397 yunseq(scaler.width = s, scaler.height = s);
398 }
399 bool
400 Font::SetStyle(FontStyle fs)
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