2fa393cc6deb2e981d79ecb5c6b63fb76a05d708
[occt.git] / src / Font / Font_FTFont.cxx
1 // Created on: 2013-01-28
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Font_FTFont.hxx>
17
18 #include <Font_FTLibrary.hxx>
19 #include <Font_FontMgr.hxx>
20 #include <Font_TextFormatter.hxx>
21 #include <Message.hxx>
22 #include <Message_Messenger.hxx>
23
24 #include <algorithm>
25
26 #include <ft2build.h>
27 #include FT_FREETYPE_H
28
29 IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
30
31 // =======================================================================
32 // function : Font_FTFont
33 // purpose  :
34 // =======================================================================
35 Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
36 : myFTLib       (theFTLib),
37   myFTFace      (NULL),
38   myActiveFTFace(NULL),
39   myFontAspect  (Font_FontAspect_Regular),
40   myWidthScaling(1.0),
41   myLoadFlags   (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
42   myUChar       (0U),
43   myToUseUnicodeSubsetFallback (Font_FontMgr::ToUseUnicodeSubsetFallback())
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 // =======================================================================
61 // function : Release
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   }
74   myActiveFTFace = NULL;
75   myBuffer.Nullify();
76 }
77
78 // =======================================================================
79 // function : Init
80 // purpose  :
81 // =======================================================================
82 bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
83                         const TCollection_AsciiString& theFileName,
84                         const Font_FTFontParams& theParams)
85 {
86   Release();
87   myBuffer = theData;
88   myFontPath = theFileName;
89   myFontParams = theParams;
90   if (!myFTLib->IsValid())
91   {
92     Message::DefaultMessenger()->Send ("FreeType library is unavailable", Message_Trace);
93     Release();
94     return false;
95   }
96
97   if (!theData.IsNull())
98   {
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     }
105   }
106   else
107   {
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);
119     Release();
120     return false;
121   }
122   else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0)
123   {
124     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size", Message_Trace);
125     Release();
126     return false;
127   }
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   }
144   myActiveFTFace = myFTFace;
145   return true;
146 }
147
148 // =======================================================================
149 // function : FindAndCreate
150 // purpose  :
151 // =======================================================================
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)
156 {
157   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
158   Font_FontAspect aFontAspect = theFontAspect;
159   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theStrictLevel, aFontAspect))
160   {
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     {
171       aFont->myFontAspect = aFontAspect;
172       return aFont;
173     }
174   }
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;
188   myFontAspect = theFontAspect;
189   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
190   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, myFontAspect))
191   {
192     if (aRequestedFont->IsSingleStrokeFont())
193     {
194       aParams.IsSingleStrokeFont = true;
195     }
196
197     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic);
198     return Init (aPath, aParams);
199   }
200   Release();
201   return false;
202 }
203
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
243 // =======================================================================
244 // function : loadGlyph
245 // purpose  :
246 // =======================================================================
247 bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
248 {
249   if (myUChar == theUChar)
250   {
251     return myUChar != 0;
252   }
253
254   myGlyphImg.Clear();
255   myUChar = 0;
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)
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;
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
307   if (theUChar == 0
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)
311   {
312     return false;
313   }
314
315   FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap;
316   if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
317   {
318     return false;
319   }
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
349   {
350     return false;
351   }
352
353   myUChar = theUChar;
354   return true;
355 }
356
357 // =======================================================================
358 // function : GlyphMaxSizeX
359 // purpose  :
360 // =======================================================================
361 unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const
362 {
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;
384 }
385
386 // =======================================================================
387 // function : GlyphMaxSizeY
388 // purpose  :
389 // =======================================================================
390 unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const
391 {
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;
413 }
414
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
442 // =======================================================================
443 // function : AdvanceX
444 // purpose  :
445 // =======================================================================
446 float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar,
447                              Standard_Utf32Char theUCharNext)
448 {
449   loadGlyph (theUChar);
450   return AdvanceX (theUCharNext);
451 }
452
453 // =======================================================================
454 // function : AdvanceY
455 // purpose  :
456 // =======================================================================
457 float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
458                              Standard_Utf32Char theUCharNext)
459 {
460   loadGlyph (theUChar);
461   return AdvanceY (theUCharNext);
462 }
463
464 // =======================================================================
465 // function : getKerning
466 // purpose  :
467 // =======================================================================
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;
474   if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0)
475   {
476     const FT_UInt aCharCurr = FT_Get_Char_Index (myActiveFTFace, theUCharCurr);
477     const FT_UInt aCharNext = FT_Get_Char_Index (myActiveFTFace, theUCharNext);
478     if (aCharCurr == 0 || aCharNext == 0
479      || FT_Get_Kerning (myActiveFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
480     {
481       theKern.x = 0;
482       theKern.y = 0;
483       return false;
484     }
485     return true;
486   }
487   return false;
488 }
489
490 // =======================================================================
491 // function : AdvanceX
492 // purpose  :
493 // =======================================================================
494 float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
495 {
496   if (myUChar == 0)
497   {
498     return 0.0f;
499   }
500
501   FT_Vector aKern;
502   getKerning (aKern, myUChar, theUCharNext);
503   return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x);
504 }
505
506 // =======================================================================
507 // function : AdvanceY
508 // purpose  :
509 // =======================================================================
510 float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
511 {
512   if (myUChar == 0)
513   {
514     return 0.0f;
515   }
516
517   FT_Vector aKern;
518   getKerning (aKern, myUChar, theUCharNext);
519   return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y);
520 }
521
522 // =======================================================================
523 // function : GlyphsNumber
524 // purpose  :
525 // =======================================================================
526 Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const
527 {
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;
541 }
542
543 // =======================================================================
544 // function : GlyphRect
545 // purpose  :
546 // =======================================================================
547 void Font_FTFont::GlyphRect (Font_Rect& theRect) const
548 {
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);
554 }
555
556 // =======================================================================
557 // function : BoundingBox
558 // purpose  :
559 // =======================================================================
560 Font_Rect Font_FTFont::BoundingBox (const NCollection_String&               theString,
561                                     const Graphic3d_HorizontalTextAlignment theAlignX,
562                                     const Graphic3d_VerticalTextAlignment   theAlignY)
563 {
564   Font_TextFormatter aFormatter;
565   aFormatter.SetupAlignment (theAlignX, theAlignY);
566   aFormatter.Reset();
567
568   aFormatter.Append (theString, *this);
569   aFormatter.Format();
570
571   Font_Rect aBndBox;
572   aFormatter.BndBox (aBndBox);
573   return aBndBox;
574 }