a174a3c5 |
1 | // Created on: 2013-01-28 |
2 | // Created by: Kirill GAVRILOV |
d5f74e42 |
3 | // Copyright (c) 2013-2014 OPEN CASCADE SAS |
a174a3c5 |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
a174a3c5 |
6 | // |
d5f74e42 |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
a174a3c5 |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
a174a3c5 |
15 | |
16 | #include <Font_FTFont.hxx> |
f9801cf9 |
17 | |
18 | #include <Font_FTLibrary.hxx> |
b514beda |
19 | #include <Font_FontMgr.hxx> |
317d68c9 |
20 | #include <Font_TextFormatter.hxx> |
1bbd7c79 |
21 | #include <Message.hxx> |
22 | #include <Message_Messenger.hxx> |
317d68c9 |
23 | |
912761ea |
24 | #include <algorithm> |
25 | |
f9801cf9 |
26 | #include <ft2build.h> |
27 | #include FT_FREETYPE_H |
a174a3c5 |
28 | |
92efcf78 |
29 | IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient) |
30 | |
a174a3c5 |
31 | // ======================================================================= |
32 | // function : Font_FTFont |
33 | // purpose : |
34 | // ======================================================================= |
35 | Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib) |
151da08b |
36 | : myFTLib (theFTLib), |
37 | myFTFace (NULL), |
912761ea |
38 | myActiveFTFace(NULL), |
39 | myFontAspect (Font_FontAspect_Regular), |
151da08b |
40 | myWidthScaling(1.0), |
41 | myLoadFlags (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL), |
912761ea |
42 | myUChar (0U), |
43 | myToUseUnicodeSubsetFallback (Font_FontMgr::ToUseUnicodeSubsetFallback()) |
a174a3c5 |
44 | { |
45 | if (myFTLib.IsNull()) |
46 | { |
47 | myFTLib = new Font_FTLibrary(); |
48 | } |
49 | } |
50 | |
51 | // ======================================================================= |
52 | // function : Font_FTFont |
53 | // purpose : |
54 | // ======================================================================= |
55 | Font_FTFont::~Font_FTFont() |
56 | { |
57 | Release(); |
58 | } |
59 | |
60 | // ======================================================================= |
f9801cf9 |
61 | // function : Release |
a174a3c5 |
62 | // purpose : |
63 | // ======================================================================= |
64 | void Font_FTFont::Release() |
65 | { |
66 | myGlyphImg.Clear(); |
67 | myFontPath.Clear(); |
68 | myUChar = 0; |
69 | if (myFTFace != NULL) |
70 | { |
71 | FT_Done_Face (myFTFace); |
72 | myFTFace = NULL; |
73 | } |
912761ea |
74 | myActiveFTFace = NULL; |
1bbd7c79 |
75 | myBuffer.Nullify(); |
a174a3c5 |
76 | } |
77 | |
78 | // ======================================================================= |
b514beda |
79 | // function : Init |
a174a3c5 |
80 | // purpose : |
81 | // ======================================================================= |
1bbd7c79 |
82 | bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData, |
83 | const TCollection_AsciiString& theFileName, |
84 | const Font_FTFontParams& theParams) |
a174a3c5 |
85 | { |
86 | Release(); |
1bbd7c79 |
87 | myBuffer = theData; |
88 | myFontPath = theFileName; |
89 | myFontParams = theParams; |
a174a3c5 |
90 | if (!myFTLib->IsValid()) |
91 | { |
1bbd7c79 |
92 | Message::DefaultMessenger()->Send ("FreeType library is unavailable", Message_Trace); |
a174a3c5 |
93 | Release(); |
94 | return false; |
95 | } |
96 | |
1bbd7c79 |
97 | if (!theData.IsNull()) |
a174a3c5 |
98 | { |
1bbd7c79 |
99 | if (FT_New_Memory_Face (myFTLib->Instance(), theData->Data(), (FT_Long )theData->Size(), 0, &myFTFace) != 0) |
100 | { |
101 | Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from memory", Message_Trace); |
102 | Release(); |
103 | return false; |
104 | } |
a174a3c5 |
105 | } |
1bbd7c79 |
106 | else |
a174a3c5 |
107 | { |
1bbd7c79 |
108 | if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), 0, &myFTFace) != 0) |
109 | { |
110 | //Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from file", Message_Trace); |
111 | Release(); |
112 | return false; |
113 | } |
114 | } |
115 | |
116 | if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0) |
117 | { |
118 | Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap", Message_Trace); |
a174a3c5 |
119 | Release(); |
120 | return false; |
121 | } |
1bbd7c79 |
122 | else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0) |
a174a3c5 |
123 | { |
1bbd7c79 |
124 | Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size", Message_Trace); |
a174a3c5 |
125 | Release(); |
126 | return false; |
127 | } |
1bbd7c79 |
128 | |
129 | if (theParams.ToSynthesizeItalic) |
130 | { |
131 | const double THE_SHEAR_ANGLE = 10.0 * M_PI / 180.0; |
132 | |
133 | FT_Matrix aMat; |
134 | aMat.xx = FT_Fixed (Cos (-THE_SHEAR_ANGLE) * (1 << 16)); |
135 | aMat.xy = 0; |
136 | aMat.yx = 0; |
137 | aMat.yy = aMat.xx; |
138 | |
139 | FT_Fixed aFactor = FT_Fixed (Tan (THE_SHEAR_ANGLE) * (1 << 16)); |
140 | aMat.xy += FT_MulFix (aFactor, aMat.xx); |
141 | |
142 | FT_Set_Transform (myFTFace, &aMat, 0); |
143 | } |
912761ea |
144 | myActiveFTFace = myFTFace; |
a174a3c5 |
145 | return true; |
146 | } |
147 | |
b514beda |
148 | // ======================================================================= |
1bbd7c79 |
149 | // function : FindAndCreate |
b514beda |
150 | // purpose : |
151 | // ======================================================================= |
1bbd7c79 |
152 | Handle(Font_FTFont) Font_FTFont::FindAndCreate (const TCollection_AsciiString& theFontName, |
153 | const Font_FontAspect theFontAspect, |
154 | const Font_FTFontParams& theParams, |
155 | const Font_StrictLevel theStrictLevel) |
b514beda |
156 | { |
157 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
5b377041 |
158 | Font_FontAspect aFontAspect = theFontAspect; |
1bbd7c79 |
159 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theStrictLevel, aFontAspect)) |
e4f0cc46 |
160 | { |
1bbd7c79 |
161 | Font_FTFontParams aParams = theParams; |
162 | if (aRequestedFont->IsSingleStrokeFont()) |
163 | { |
164 | aParams.IsSingleStrokeFont = true; |
165 | } |
166 | |
167 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic); |
168 | Handle(Font_FTFont) aFont = new Font_FTFont(); |
169 | if (aFont->Init (aPath, aParams)) |
170 | { |
912761ea |
171 | aFont->myFontAspect = aFontAspect; |
1bbd7c79 |
172 | return aFont; |
173 | } |
e4f0cc46 |
174 | } |
1bbd7c79 |
175 | return Handle(Font_FTFont)(); |
176 | } |
177 | |
178 | // ======================================================================= |
179 | // function : FindAndInit |
180 | // purpose : |
181 | // ======================================================================= |
182 | bool Font_FTFont::FindAndInit (const TCollection_AsciiString& theFontName, |
183 | Font_FontAspect theFontAspect, |
184 | const Font_FTFontParams& theParams, |
185 | Font_StrictLevel theStrictLevel) |
186 | { |
187 | Font_FTFontParams aParams = theParams; |
912761ea |
188 | myFontAspect = theFontAspect; |
1bbd7c79 |
189 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
912761ea |
190 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, myFontAspect)) |
1bbd7c79 |
191 | { |
192 | if (aRequestedFont->IsSingleStrokeFont()) |
193 | { |
194 | aParams.IsSingleStrokeFont = true; |
195 | } |
196 | |
912761ea |
197 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic); |
1bbd7c79 |
198 | return Init (aPath, aParams); |
199 | } |
200 | Release(); |
e4f0cc46 |
201 | return false; |
b514beda |
202 | } |
203 | |
912761ea |
204 | // ======================================================================= |
205 | // function : findAndInitFallback |
206 | // purpose : |
207 | // ======================================================================= |
208 | bool Font_FTFont::findAndInitFallback (Font_UnicodeSubset theSubset) |
209 | { |
210 | if (!myFallbackFaces[theSubset].IsNull()) |
211 | { |
212 | return myFallbackFaces[theSubset]->IsValid(); |
213 | } |
214 | |
215 | myFallbackFaces[theSubset] = new Font_FTFont (myFTLib); |
216 | myFallbackFaces[theSubset]->myToUseUnicodeSubsetFallback = false; // no recursion |
217 | |
218 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
219 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFallbackFont (theSubset, myFontAspect)) |
220 | { |
221 | Font_FTFontParams aParams = myFontParams; |
222 | aParams.IsSingleStrokeFont = aRequestedFont->IsSingleStrokeFont(); |
223 | |
224 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic); |
225 | if (myFallbackFaces[theSubset]->Init (aPath, aParams)) |
226 | { |
227 | Message::DefaultMessenger()->Send (TCollection_AsciiString ("Font_FTFont, using fallback font '") + aRequestedFont->FontName() + "'" |
228 | + " for symbols unsupported by '" + myFTFace->family_name + "'", Message_Trace); |
229 | } |
230 | } |
231 | return myFallbackFaces[theSubset]->IsValid(); |
232 | } |
233 | |
234 | // ======================================================================= |
235 | // function : HasSymbol |
236 | // purpose : |
237 | // ======================================================================= |
238 | bool Font_FTFont::HasSymbol (Standard_Utf32Char theUChar) const |
239 | { |
240 | return FT_Get_Char_Index (myFTFace, theUChar) != 0; |
241 | } |
242 | |
a174a3c5 |
243 | // ======================================================================= |
244 | // function : loadGlyph |
245 | // purpose : |
246 | // ======================================================================= |
247 | bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar) |
248 | { |
249 | if (myUChar == theUChar) |
250 | { |
82be4141 |
251 | return myUChar != 0; |
a174a3c5 |
252 | } |
253 | |
254 | myGlyphImg.Clear(); |
255 | myUChar = 0; |
912761ea |
256 | myActiveFTFace = myFTFace; |
257 | if (theUChar == 0) |
258 | { |
259 | return false; |
260 | } |
261 | |
262 | if (myToUseUnicodeSubsetFallback |
263 | && !HasSymbol (theUChar)) |
264 | { |
265 | // try using fallback |
266 | const Font_UnicodeSubset aSubset = CharSubset (theUChar); |
267 | if (findAndInitFallback (aSubset) |
268 | && myFallbackFaces[aSubset]->HasSymbol (theUChar)) |
269 | { |
270 | myActiveFTFace = myFallbackFaces[aSubset]->myFTFace; |
271 | } |
272 | } |
273 | |
274 | if (FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags)) != 0 |
275 | || myActiveFTFace->glyph == NULL) |
a174a3c5 |
276 | { |
277 | return false; |
278 | } |
279 | |
280 | myUChar = theUChar; |
281 | return true; |
282 | } |
283 | |
284 | // ======================================================================= |
285 | // function : RenderGlyph |
286 | // purpose : |
287 | // ======================================================================= |
288 | bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar) |
289 | { |
290 | myGlyphImg.Clear(); |
291 | myUChar = 0; |
912761ea |
292 | myActiveFTFace = myFTFace; |
293 | |
294 | if (theUChar != 0 |
295 | && myToUseUnicodeSubsetFallback |
296 | && !HasSymbol (theUChar)) |
297 | { |
298 | // try using fallback |
299 | const Font_UnicodeSubset aSubset = CharSubset (theUChar); |
300 | if (findAndInitFallback (aSubset) |
301 | && myFallbackFaces[aSubset]->HasSymbol (theUChar)) |
302 | { |
303 | myActiveFTFace = myFallbackFaces[aSubset]->myFTFace; |
304 | } |
305 | } |
306 | |
a174a3c5 |
307 | if (theUChar == 0 |
912761ea |
308 | || FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0 |
309 | || myActiveFTFace->glyph == NULL |
310 | || myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP) |
a174a3c5 |
311 | { |
312 | return false; |
313 | } |
314 | |
912761ea |
315 | FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap; |
316 | if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0) |
a174a3c5 |
317 | { |
318 | return false; |
319 | } |
912761ea |
320 | |
321 | if (aBitmap.pixel_mode == FT_PIXEL_MODE_GRAY) |
322 | { |
323 | if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer, |
324 | aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch))) |
325 | { |
326 | return false; |
327 | } |
328 | myGlyphImg.SetTopDown (aBitmap.pitch > 0); |
329 | } |
330 | else if (aBitmap.pixel_mode == FT_PIXEL_MODE_MONO) |
331 | { |
332 | if (!myGlyphImg.InitTrash (Image_Format_Gray, aBitmap.width, aBitmap.rows)) |
333 | { |
334 | return false; |
335 | } |
336 | |
337 | myGlyphImg.SetTopDown (aBitmap.pitch > 0); |
338 | const int aNumOfBytesInRow = aBitmap.width / 8 + (aBitmap.width % 8 ? 1 : 0); |
339 | for (int aRow = 0; aRow < (int )aBitmap.rows; ++aRow) |
340 | { |
341 | for (int aCol = 0; aCol < (int )aBitmap.width; ++aCol) |
342 | { |
343 | const int aBitOn = aBitmap.buffer[aNumOfBytesInRow * aRow + aCol / 8] & (0x80 >> (aCol % 8)); |
344 | *myGlyphImg.ChangeRawValue (aRow, aCol) = aBitOn ? 255 : 0; |
345 | } |
346 | } |
347 | } |
348 | else |
a174a3c5 |
349 | { |
350 | return false; |
351 | } |
912761ea |
352 | |
a174a3c5 |
353 | myUChar = theUChar; |
354 | return true; |
355 | } |
356 | |
357 | // ======================================================================= |
358 | // function : GlyphMaxSizeX |
359 | // purpose : |
360 | // ======================================================================= |
912761ea |
361 | unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const |
a174a3c5 |
362 | { |
912761ea |
363 | if (!theToIncludeFallback) |
364 | { |
365 | float aWidth = (FT_IS_SCALABLE(myFTFace) != 0) |
366 | ? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM)) |
367 | : fromFTPoints<float> (myFTFace->size->metrics.max_advance); |
368 | return (unsigned int)(aWidth + 0.5f); |
369 | } |
370 | |
371 | unsigned int aWidth = GlyphMaxSizeX (false); |
372 | if (theToIncludeFallback) |
373 | { |
374 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
375 | { |
376 | if (!myFallbackFaces[aFontIter].IsNull() |
377 | && myFallbackFaces[aFontIter]->IsValid()) |
378 | { |
379 | aWidth = std::max (aWidth, myFallbackFaces[aFontIter]->GlyphMaxSizeX (false)); |
380 | } |
381 | } |
382 | } |
383 | return aWidth; |
a174a3c5 |
384 | } |
385 | |
386 | // ======================================================================= |
387 | // function : GlyphMaxSizeY |
388 | // purpose : |
389 | // ======================================================================= |
912761ea |
390 | unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const |
a174a3c5 |
391 | { |
912761ea |
392 | if (!theToIncludeFallback) |
393 | { |
394 | float aHeight = (FT_IS_SCALABLE(myFTFace) != 0) |
395 | ? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)) |
396 | : fromFTPoints<float> (myFTFace->size->metrics.height); |
397 | return (unsigned int)(aHeight + 0.5f); |
398 | } |
399 | |
400 | unsigned int aHeight = GlyphMaxSizeY (false); |
401 | if (theToIncludeFallback) |
402 | { |
403 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
404 | { |
405 | if (!myFallbackFaces[aFontIter].IsNull() |
406 | && myFallbackFaces[aFontIter]->IsValid()) |
407 | { |
408 | aHeight = std::max (aHeight, myFallbackFaces[aFontIter]->GlyphMaxSizeY (false)); |
409 | } |
410 | } |
411 | } |
412 | return aHeight; |
a174a3c5 |
413 | } |
414 | |
f9801cf9 |
415 | // ======================================================================= |
416 | // function : Ascender |
417 | // purpose : |
418 | // ======================================================================= |
419 | float Font_FTFont::Ascender() const |
420 | { |
421 | return float(myFTFace->ascender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
422 | } |
423 | |
424 | // ======================================================================= |
425 | // function : Descender |
426 | // purpose : |
427 | // ======================================================================= |
428 | float Font_FTFont::Descender() const |
429 | { |
430 | return float(myFTFace->descender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
431 | } |
432 | |
433 | // ======================================================================= |
434 | // function : LineSpacing |
435 | // purpose : |
436 | // ======================================================================= |
437 | float Font_FTFont::LineSpacing() const |
438 | { |
439 | return float(myFTFace->height) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
440 | } |
441 | |
a174a3c5 |
442 | // ======================================================================= |
443 | // function : AdvanceX |
444 | // purpose : |
445 | // ======================================================================= |
82be4141 |
446 | float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar, |
447 | Standard_Utf32Char theUCharNext) |
a174a3c5 |
448 | { |
449 | loadGlyph (theUChar); |
450 | return AdvanceX (theUCharNext); |
451 | } |
452 | |
453 | // ======================================================================= |
454 | // function : AdvanceY |
455 | // purpose : |
456 | // ======================================================================= |
82be4141 |
457 | float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar, |
458 | Standard_Utf32Char theUCharNext) |
a174a3c5 |
459 | { |
460 | loadGlyph (theUChar); |
461 | return AdvanceY (theUCharNext); |
462 | } |
463 | |
912761ea |
464 | // ======================================================================= |
465 | // function : getKerning |
466 | // purpose : |
467 | // ======================================================================= |
82be4141 |
468 | bool Font_FTFont::getKerning (FT_Vector& theKern, |
469 | Standard_Utf32Char theUCharCurr, |
470 | Standard_Utf32Char theUCharNext) const |
471 | { |
472 | theKern.x = 0; |
473 | theKern.y = 0; |
912761ea |
474 | if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0) |
82be4141 |
475 | { |
912761ea |
476 | const FT_UInt aCharCurr = FT_Get_Char_Index (myActiveFTFace, theUCharCurr); |
477 | const FT_UInt aCharNext = FT_Get_Char_Index (myActiveFTFace, theUCharNext); |
82be4141 |
478 | if (aCharCurr == 0 || aCharNext == 0 |
912761ea |
479 | || FT_Get_Kerning (myActiveFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0) |
82be4141 |
480 | { |
481 | theKern.x = 0; |
482 | theKern.y = 0; |
483 | return false; |
484 | } |
485 | return true; |
486 | } |
487 | return false; |
488 | } |
489 | |
a174a3c5 |
490 | // ======================================================================= |
491 | // function : AdvanceX |
492 | // purpose : |
493 | // ======================================================================= |
82be4141 |
494 | float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const |
a174a3c5 |
495 | { |
496 | if (myUChar == 0) |
497 | { |
498 | return 0.0f; |
499 | } |
500 | |
82be4141 |
501 | FT_Vector aKern; |
502 | getKerning (aKern, myUChar, theUCharNext); |
912761ea |
503 | return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x); |
a174a3c5 |
504 | } |
505 | |
506 | // ======================================================================= |
507 | // function : AdvanceY |
508 | // purpose : |
509 | // ======================================================================= |
82be4141 |
510 | float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const |
a174a3c5 |
511 | { |
512 | if (myUChar == 0) |
513 | { |
514 | return 0.0f; |
515 | } |
516 | |
82be4141 |
517 | FT_Vector aKern; |
518 | getKerning (aKern, myUChar, theUCharNext); |
912761ea |
519 | return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y); |
f9801cf9 |
520 | } |
521 | |
522 | // ======================================================================= |
523 | // function : GlyphsNumber |
524 | // purpose : |
525 | // ======================================================================= |
912761ea |
526 | Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const |
f9801cf9 |
527 | { |
912761ea |
528 | Standard_Integer aNbGlyphs = myFTFace->num_glyphs; |
529 | if (theToIncludeFallback) |
530 | { |
531 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
532 | { |
533 | if (!myFallbackFaces[aFontIter].IsNull() |
534 | && myFallbackFaces[aFontIter]->IsValid()) |
535 | { |
536 | aNbGlyphs += myFallbackFaces[aFontIter]->GlyphsNumber (false); |
537 | } |
538 | } |
539 | } |
540 | return aNbGlyphs; |
f9801cf9 |
541 | } |
542 | |
543 | // ======================================================================= |
912761ea |
544 | // function : GlyphRect |
f9801cf9 |
545 | // purpose : |
546 | // ======================================================================= |
547 | void Font_FTFont::GlyphRect (Font_Rect& theRect) const |
548 | { |
912761ea |
549 | const FT_Bitmap& aBitmap = myActiveFTFace->glyph->bitmap; |
550 | theRect.Left = float(myActiveFTFace->glyph->bitmap_left); |
551 | theRect.Top = float(myActiveFTFace->glyph->bitmap_top); |
552 | theRect.Right = float(myActiveFTFace->glyph->bitmap_left + (int )aBitmap.width); |
553 | theRect.Bottom = float(myActiveFTFace->glyph->bitmap_top - (int )aBitmap.rows); |
a174a3c5 |
554 | } |
317d68c9 |
555 | |
556 | // ======================================================================= |
557 | // function : BoundingBox |
558 | // purpose : |
559 | // ======================================================================= |
d2eddacc |
560 | Font_Rect Font_FTFont::BoundingBox (const NCollection_String& theString, |
561 | const Graphic3d_HorizontalTextAlignment theAlignX, |
562 | const Graphic3d_VerticalTextAlignment theAlignY) |
317d68c9 |
563 | { |
564 | Font_TextFormatter aFormatter; |
565 | aFormatter.SetupAlignment (theAlignX, theAlignY); |
566 | aFormatter.Reset(); |
567 | |
568 | aFormatter.Append (theString, *this); |
569 | aFormatter.Format(); |
570 | |
d2eddacc |
571 | Font_Rect aBndBox; |
317d68c9 |
572 | aFormatter.BndBox (aBndBox); |
317d68c9 |
573 | return aBndBox; |
574 | } |