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, |
9a90a452 |
84 | const Font_FTFontParams& theParams, |
85 | const Standard_Integer theFaceId) |
a174a3c5 |
86 | { |
87 | Release(); |
1bbd7c79 |
88 | myBuffer = theData; |
89 | myFontPath = theFileName; |
90 | myFontParams = theParams; |
a174a3c5 |
91 | if (!myFTLib->IsValid()) |
92 | { |
a87b1b37 |
93 | Message::SendTrace ("FreeType library is unavailable"); |
a174a3c5 |
94 | Release(); |
95 | return false; |
96 | } |
97 | |
1bbd7c79 |
98 | if (!theData.IsNull()) |
a174a3c5 |
99 | { |
9a90a452 |
100 | if (FT_New_Memory_Face (myFTLib->Instance(), theData->Data(), (FT_Long )theData->Size(), (FT_Long )theFaceId, &myFTFace) != 0) |
1bbd7c79 |
101 | { |
a87b1b37 |
102 | Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from memory"); |
1bbd7c79 |
103 | Release(); |
104 | return false; |
105 | } |
a174a3c5 |
106 | } |
1bbd7c79 |
107 | else |
a174a3c5 |
108 | { |
9a90a452 |
109 | if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), (FT_Long )theFaceId, &myFTFace) != 0) |
1bbd7c79 |
110 | { |
a87b1b37 |
111 | //Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from file"); |
1bbd7c79 |
112 | Release(); |
113 | return false; |
114 | } |
115 | } |
116 | |
117 | if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0) |
118 | { |
a87b1b37 |
119 | Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap"); |
a174a3c5 |
120 | Release(); |
121 | return false; |
122 | } |
1bbd7c79 |
123 | else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0) |
a174a3c5 |
124 | { |
a87b1b37 |
125 | Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size"); |
a174a3c5 |
126 | Release(); |
127 | return false; |
128 | } |
1bbd7c79 |
129 | |
130 | if (theParams.ToSynthesizeItalic) |
131 | { |
132 | const double THE_SHEAR_ANGLE = 10.0 * M_PI / 180.0; |
133 | |
134 | FT_Matrix aMat; |
135 | aMat.xx = FT_Fixed (Cos (-THE_SHEAR_ANGLE) * (1 << 16)); |
136 | aMat.xy = 0; |
137 | aMat.yx = 0; |
138 | aMat.yy = aMat.xx; |
139 | |
140 | FT_Fixed aFactor = FT_Fixed (Tan (THE_SHEAR_ANGLE) * (1 << 16)); |
141 | aMat.xy += FT_MulFix (aFactor, aMat.xx); |
142 | |
143 | FT_Set_Transform (myFTFace, &aMat, 0); |
144 | } |
912761ea |
145 | myActiveFTFace = myFTFace; |
a174a3c5 |
146 | return true; |
147 | } |
148 | |
b514beda |
149 | // ======================================================================= |
1bbd7c79 |
150 | // function : FindAndCreate |
b514beda |
151 | // purpose : |
152 | // ======================================================================= |
1bbd7c79 |
153 | Handle(Font_FTFont) Font_FTFont::FindAndCreate (const TCollection_AsciiString& theFontName, |
154 | const Font_FontAspect theFontAspect, |
155 | const Font_FTFontParams& theParams, |
156 | const Font_StrictLevel theStrictLevel) |
b514beda |
157 | { |
158 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
5b377041 |
159 | Font_FontAspect aFontAspect = theFontAspect; |
36e28f96 |
160 | Font_FTFontParams aParams = theParams; |
1bbd7c79 |
161 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theStrictLevel, aFontAspect)) |
e4f0cc46 |
162 | { |
1bbd7c79 |
163 | if (aRequestedFont->IsSingleStrokeFont()) |
164 | { |
165 | aParams.IsSingleStrokeFont = true; |
166 | } |
167 | |
9a90a452 |
168 | Standard_Integer aFaceId = 0; |
169 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic, aFaceId); |
1bbd7c79 |
170 | Handle(Font_FTFont) aFont = new Font_FTFont(); |
9a90a452 |
171 | if (aFont->Init (aPath, aParams, aFaceId)) |
1bbd7c79 |
172 | { |
912761ea |
173 | aFont->myFontAspect = aFontAspect; |
1bbd7c79 |
174 | return aFont; |
175 | } |
e4f0cc46 |
176 | } |
36e28f96 |
177 | else if (theStrictLevel == Font_StrictLevel_Any) |
178 | { |
179 | switch (theFontAspect) |
180 | { |
181 | case Font_FontAspect_UNDEFINED: |
182 | case Font_FontAspect_Regular: |
183 | case Font_FontAspect_Bold: |
184 | aFontAspect = Font_FontAspect_Regular; |
185 | break; |
186 | case Font_FontAspect_Italic: |
187 | case Font_FontAspect_BoldItalic: |
188 | aFontAspect = Font_FontAspect_Italic; |
189 | aParams.ToSynthesizeItalic = true; |
190 | break; |
191 | } |
36e28f96 |
192 | Handle(Font_FTFont) aFont = new Font_FTFont(); |
21095f2d |
193 | if (aFont->Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0)) |
36e28f96 |
194 | { |
195 | aFont->myFontAspect = aFontAspect; |
196 | return aFont; |
197 | } |
198 | } |
1bbd7c79 |
199 | return Handle(Font_FTFont)(); |
200 | } |
201 | |
202 | // ======================================================================= |
203 | // function : FindAndInit |
204 | // purpose : |
205 | // ======================================================================= |
206 | bool Font_FTFont::FindAndInit (const TCollection_AsciiString& theFontName, |
207 | Font_FontAspect theFontAspect, |
208 | const Font_FTFontParams& theParams, |
209 | Font_StrictLevel theStrictLevel) |
210 | { |
211 | Font_FTFontParams aParams = theParams; |
912761ea |
212 | myFontAspect = theFontAspect; |
1bbd7c79 |
213 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
912761ea |
214 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, myFontAspect)) |
1bbd7c79 |
215 | { |
216 | if (aRequestedFont->IsSingleStrokeFont()) |
217 | { |
218 | aParams.IsSingleStrokeFont = true; |
219 | } |
220 | |
9a90a452 |
221 | Standard_Integer aFaceId = 0; |
222 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId); |
223 | return Init (aPath, aParams, aFaceId); |
1bbd7c79 |
224 | } |
36e28f96 |
225 | else if (theStrictLevel == Font_StrictLevel_Any) |
226 | { |
227 | if (theFontAspect == Font_FontAspect_Italic |
228 | || theFontAspect == Font_FontAspect_BoldItalic) |
229 | { |
230 | aParams.ToSynthesizeItalic = true; |
231 | } |
21095f2d |
232 | return Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0); |
36e28f96 |
233 | } |
1bbd7c79 |
234 | Release(); |
e4f0cc46 |
235 | return false; |
b514beda |
236 | } |
237 | |
912761ea |
238 | // ======================================================================= |
239 | // function : findAndInitFallback |
240 | // purpose : |
241 | // ======================================================================= |
242 | bool Font_FTFont::findAndInitFallback (Font_UnicodeSubset theSubset) |
243 | { |
244 | if (!myFallbackFaces[theSubset].IsNull()) |
245 | { |
246 | return myFallbackFaces[theSubset]->IsValid(); |
247 | } |
248 | |
249 | myFallbackFaces[theSubset] = new Font_FTFont (myFTLib); |
250 | myFallbackFaces[theSubset]->myToUseUnicodeSubsetFallback = false; // no recursion |
251 | |
252 | Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance(); |
253 | if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFallbackFont (theSubset, myFontAspect)) |
254 | { |
255 | Font_FTFontParams aParams = myFontParams; |
256 | aParams.IsSingleStrokeFont = aRequestedFont->IsSingleStrokeFont(); |
257 | |
9a90a452 |
258 | Standard_Integer aFaceId = 0; |
259 | const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId); |
260 | if (myFallbackFaces[theSubset]->Init (aPath, aParams, aFaceId)) |
912761ea |
261 | { |
a87b1b37 |
262 | Message::SendTrace (TCollection_AsciiString ("Font_FTFont, using fallback font '") + aRequestedFont->FontName() + "'" |
263 | + " for symbols unsupported by '" + myFTFace->family_name + "'"); |
912761ea |
264 | } |
265 | } |
266 | return myFallbackFaces[theSubset]->IsValid(); |
267 | } |
268 | |
269 | // ======================================================================= |
270 | // function : HasSymbol |
271 | // purpose : |
272 | // ======================================================================= |
273 | bool Font_FTFont::HasSymbol (Standard_Utf32Char theUChar) const |
274 | { |
275 | return FT_Get_Char_Index (myFTFace, theUChar) != 0; |
276 | } |
277 | |
a174a3c5 |
278 | // ======================================================================= |
279 | // function : loadGlyph |
280 | // purpose : |
281 | // ======================================================================= |
282 | bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar) |
283 | { |
284 | if (myUChar == theUChar) |
285 | { |
82be4141 |
286 | return myUChar != 0; |
a174a3c5 |
287 | } |
288 | |
289 | myGlyphImg.Clear(); |
290 | myUChar = 0; |
912761ea |
291 | myActiveFTFace = myFTFace; |
292 | if (theUChar == 0) |
293 | { |
294 | return false; |
295 | } |
296 | |
297 | if (myToUseUnicodeSubsetFallback |
298 | && !HasSymbol (theUChar)) |
299 | { |
300 | // try using fallback |
301 | const Font_UnicodeSubset aSubset = CharSubset (theUChar); |
302 | if (findAndInitFallback (aSubset) |
303 | && myFallbackFaces[aSubset]->HasSymbol (theUChar)) |
304 | { |
305 | myActiveFTFace = myFallbackFaces[aSubset]->myFTFace; |
306 | } |
307 | } |
308 | |
309 | if (FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags)) != 0 |
310 | || myActiveFTFace->glyph == NULL) |
a174a3c5 |
311 | { |
312 | return false; |
313 | } |
314 | |
315 | myUChar = theUChar; |
316 | return true; |
317 | } |
318 | |
319 | // ======================================================================= |
320 | // function : RenderGlyph |
321 | // purpose : |
322 | // ======================================================================= |
323 | bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar) |
324 | { |
325 | myGlyphImg.Clear(); |
326 | myUChar = 0; |
912761ea |
327 | myActiveFTFace = myFTFace; |
328 | |
329 | if (theUChar != 0 |
330 | && myToUseUnicodeSubsetFallback |
331 | && !HasSymbol (theUChar)) |
332 | { |
333 | // try using fallback |
334 | const Font_UnicodeSubset aSubset = CharSubset (theUChar); |
335 | if (findAndInitFallback (aSubset) |
336 | && myFallbackFaces[aSubset]->HasSymbol (theUChar)) |
337 | { |
338 | myActiveFTFace = myFallbackFaces[aSubset]->myFTFace; |
339 | } |
340 | } |
341 | |
a174a3c5 |
342 | if (theUChar == 0 |
912761ea |
343 | || FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0 |
344 | || myActiveFTFace->glyph == NULL |
345 | || myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP) |
a174a3c5 |
346 | { |
347 | return false; |
348 | } |
349 | |
912761ea |
350 | FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap; |
351 | if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0) |
a174a3c5 |
352 | { |
353 | return false; |
354 | } |
912761ea |
355 | |
356 | if (aBitmap.pixel_mode == FT_PIXEL_MODE_GRAY) |
357 | { |
358 | if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer, |
359 | aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch))) |
360 | { |
361 | return false; |
362 | } |
363 | myGlyphImg.SetTopDown (aBitmap.pitch > 0); |
364 | } |
365 | else if (aBitmap.pixel_mode == FT_PIXEL_MODE_MONO) |
366 | { |
367 | if (!myGlyphImg.InitTrash (Image_Format_Gray, aBitmap.width, aBitmap.rows)) |
368 | { |
369 | return false; |
370 | } |
371 | |
372 | myGlyphImg.SetTopDown (aBitmap.pitch > 0); |
373 | const int aNumOfBytesInRow = aBitmap.width / 8 + (aBitmap.width % 8 ? 1 : 0); |
374 | for (int aRow = 0; aRow < (int )aBitmap.rows; ++aRow) |
375 | { |
376 | for (int aCol = 0; aCol < (int )aBitmap.width; ++aCol) |
377 | { |
378 | const int aBitOn = aBitmap.buffer[aNumOfBytesInRow * aRow + aCol / 8] & (0x80 >> (aCol % 8)); |
379 | *myGlyphImg.ChangeRawValue (aRow, aCol) = aBitOn ? 255 : 0; |
380 | } |
381 | } |
382 | } |
383 | else |
a174a3c5 |
384 | { |
385 | return false; |
386 | } |
912761ea |
387 | |
a174a3c5 |
388 | myUChar = theUChar; |
389 | return true; |
390 | } |
391 | |
392 | // ======================================================================= |
393 | // function : GlyphMaxSizeX |
394 | // purpose : |
395 | // ======================================================================= |
912761ea |
396 | unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const |
a174a3c5 |
397 | { |
912761ea |
398 | if (!theToIncludeFallback) |
399 | { |
400 | float aWidth = (FT_IS_SCALABLE(myFTFace) != 0) |
401 | ? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM)) |
402 | : fromFTPoints<float> (myFTFace->size->metrics.max_advance); |
403 | return (unsigned int)(aWidth + 0.5f); |
404 | } |
405 | |
406 | unsigned int aWidth = GlyphMaxSizeX (false); |
407 | if (theToIncludeFallback) |
408 | { |
409 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
410 | { |
411 | if (!myFallbackFaces[aFontIter].IsNull() |
412 | && myFallbackFaces[aFontIter]->IsValid()) |
413 | { |
414 | aWidth = std::max (aWidth, myFallbackFaces[aFontIter]->GlyphMaxSizeX (false)); |
415 | } |
416 | } |
417 | } |
418 | return aWidth; |
a174a3c5 |
419 | } |
420 | |
421 | // ======================================================================= |
422 | // function : GlyphMaxSizeY |
423 | // purpose : |
424 | // ======================================================================= |
912761ea |
425 | unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const |
a174a3c5 |
426 | { |
912761ea |
427 | if (!theToIncludeFallback) |
428 | { |
429 | float aHeight = (FT_IS_SCALABLE(myFTFace) != 0) |
430 | ? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)) |
431 | : fromFTPoints<float> (myFTFace->size->metrics.height); |
432 | return (unsigned int)(aHeight + 0.5f); |
433 | } |
434 | |
435 | unsigned int aHeight = GlyphMaxSizeY (false); |
436 | if (theToIncludeFallback) |
437 | { |
438 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
439 | { |
440 | if (!myFallbackFaces[aFontIter].IsNull() |
441 | && myFallbackFaces[aFontIter]->IsValid()) |
442 | { |
443 | aHeight = std::max (aHeight, myFallbackFaces[aFontIter]->GlyphMaxSizeY (false)); |
444 | } |
445 | } |
446 | } |
447 | return aHeight; |
a174a3c5 |
448 | } |
449 | |
f9801cf9 |
450 | // ======================================================================= |
451 | // function : Ascender |
452 | // purpose : |
453 | // ======================================================================= |
454 | float Font_FTFont::Ascender() const |
455 | { |
456 | return float(myFTFace->ascender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
457 | } |
458 | |
459 | // ======================================================================= |
460 | // function : Descender |
461 | // purpose : |
462 | // ======================================================================= |
463 | float Font_FTFont::Descender() const |
464 | { |
465 | return float(myFTFace->descender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
466 | } |
467 | |
468 | // ======================================================================= |
469 | // function : LineSpacing |
470 | // purpose : |
471 | // ======================================================================= |
472 | float Font_FTFont::LineSpacing() const |
473 | { |
474 | return float(myFTFace->height) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM)); |
475 | } |
476 | |
a174a3c5 |
477 | // ======================================================================= |
478 | // function : AdvanceX |
479 | // purpose : |
480 | // ======================================================================= |
82be4141 |
481 | float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar, |
482 | Standard_Utf32Char theUCharNext) |
a174a3c5 |
483 | { |
484 | loadGlyph (theUChar); |
485 | return AdvanceX (theUCharNext); |
486 | } |
487 | |
488 | // ======================================================================= |
489 | // function : AdvanceY |
490 | // purpose : |
491 | // ======================================================================= |
82be4141 |
492 | float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar, |
493 | Standard_Utf32Char theUCharNext) |
a174a3c5 |
494 | { |
495 | loadGlyph (theUChar); |
496 | return AdvanceY (theUCharNext); |
497 | } |
498 | |
912761ea |
499 | // ======================================================================= |
500 | // function : getKerning |
501 | // purpose : |
502 | // ======================================================================= |
82be4141 |
503 | bool Font_FTFont::getKerning (FT_Vector& theKern, |
504 | Standard_Utf32Char theUCharCurr, |
505 | Standard_Utf32Char theUCharNext) const |
506 | { |
507 | theKern.x = 0; |
508 | theKern.y = 0; |
912761ea |
509 | if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0) |
82be4141 |
510 | { |
912761ea |
511 | const FT_UInt aCharCurr = FT_Get_Char_Index (myActiveFTFace, theUCharCurr); |
512 | const FT_UInt aCharNext = FT_Get_Char_Index (myActiveFTFace, theUCharNext); |
82be4141 |
513 | if (aCharCurr == 0 || aCharNext == 0 |
912761ea |
514 | || FT_Get_Kerning (myActiveFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0) |
82be4141 |
515 | { |
516 | theKern.x = 0; |
517 | theKern.y = 0; |
518 | return false; |
519 | } |
520 | return true; |
521 | } |
522 | return false; |
523 | } |
524 | |
a174a3c5 |
525 | // ======================================================================= |
526 | // function : AdvanceX |
527 | // purpose : |
528 | // ======================================================================= |
82be4141 |
529 | float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const |
a174a3c5 |
530 | { |
531 | if (myUChar == 0) |
532 | { |
533 | return 0.0f; |
534 | } |
535 | |
82be4141 |
536 | FT_Vector aKern; |
537 | getKerning (aKern, myUChar, theUCharNext); |
912761ea |
538 | return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x); |
a174a3c5 |
539 | } |
540 | |
541 | // ======================================================================= |
542 | // function : AdvanceY |
543 | // purpose : |
544 | // ======================================================================= |
82be4141 |
545 | float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const |
a174a3c5 |
546 | { |
547 | if (myUChar == 0) |
548 | { |
549 | return 0.0f; |
550 | } |
551 | |
82be4141 |
552 | FT_Vector aKern; |
553 | getKerning (aKern, myUChar, theUCharNext); |
912761ea |
554 | return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y); |
f9801cf9 |
555 | } |
556 | |
557 | // ======================================================================= |
558 | // function : GlyphsNumber |
559 | // purpose : |
560 | // ======================================================================= |
912761ea |
561 | Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const |
f9801cf9 |
562 | { |
912761ea |
563 | Standard_Integer aNbGlyphs = myFTFace->num_glyphs; |
564 | if (theToIncludeFallback) |
565 | { |
566 | for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter) |
567 | { |
568 | if (!myFallbackFaces[aFontIter].IsNull() |
569 | && myFallbackFaces[aFontIter]->IsValid()) |
570 | { |
571 | aNbGlyphs += myFallbackFaces[aFontIter]->GlyphsNumber (false); |
572 | } |
573 | } |
574 | } |
575 | return aNbGlyphs; |
f9801cf9 |
576 | } |
577 | |
578 | // ======================================================================= |
912761ea |
579 | // function : GlyphRect |
f9801cf9 |
580 | // purpose : |
581 | // ======================================================================= |
582 | void Font_FTFont::GlyphRect (Font_Rect& theRect) const |
583 | { |
912761ea |
584 | const FT_Bitmap& aBitmap = myActiveFTFace->glyph->bitmap; |
585 | theRect.Left = float(myActiveFTFace->glyph->bitmap_left); |
586 | theRect.Top = float(myActiveFTFace->glyph->bitmap_top); |
587 | theRect.Right = float(myActiveFTFace->glyph->bitmap_left + (int )aBitmap.width); |
588 | theRect.Bottom = float(myActiveFTFace->glyph->bitmap_top - (int )aBitmap.rows); |
a174a3c5 |
589 | } |
317d68c9 |
590 | |
591 | // ======================================================================= |
592 | // function : BoundingBox |
593 | // purpose : |
594 | // ======================================================================= |
d2eddacc |
595 | Font_Rect Font_FTFont::BoundingBox (const NCollection_String& theString, |
596 | const Graphic3d_HorizontalTextAlignment theAlignX, |
597 | const Graphic3d_VerticalTextAlignment theAlignY) |
317d68c9 |
598 | { |
599 | Font_TextFormatter aFormatter; |
600 | aFormatter.SetupAlignment (theAlignX, theAlignY); |
601 | aFormatter.Reset(); |
602 | |
603 | aFormatter.Append (theString, *this); |
604 | aFormatter.Format(); |
605 | |
d2eddacc |
606 | Font_Rect aBndBox; |
317d68c9 |
607 | aFormatter.BndBox (aBndBox); |
317d68c9 |
608 | return aBndBox; |
609 | } |
ac5b3cbc |
610 | |
611 | // ======================================================================= |
612 | // function : renderGlyphOutline |
613 | // purpose : |
614 | // ======================================================================= |
615 | const FT_Outline* Font_FTFont::renderGlyphOutline (const Standard_Utf32Char theChar) |
616 | { |
617 | if (!loadGlyph (theChar) |
618 | || myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE) |
619 | { |
620 | return 0; |
621 | } |
622 | return &myActiveFTFace->glyph->outline; |
623 | } |