703d3175a2e9d78bac7453a937035ef1032907e9
[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                         const Standard_Integer theFaceId)
86 {
87   Release();
88   myBuffer = theData;
89   myFontPath = theFileName;
90   myFontParams = theParams;
91   if (!myFTLib->IsValid())
92   {
93     Message::DefaultMessenger()->Send ("FreeType library is unavailable", Message_Trace);
94     Release();
95     return false;
96   }
97
98   if (!theData.IsNull())
99   {
100     if (FT_New_Memory_Face (myFTLib->Instance(), theData->Data(), (FT_Long )theData->Size(), (FT_Long )theFaceId, &myFTFace) != 0)
101     {
102       Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from memory", Message_Trace);
103       Release();
104       return false;
105     }
106   }
107   else
108   {
109     if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), (FT_Long )theFaceId, &myFTFace) != 0)
110     {
111       //Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from file", Message_Trace);
112       Release();
113       return false;
114     }
115   }
116
117   if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0)
118   {
119     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap", Message_Trace);
120     Release();
121     return false;
122   }
123   else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0)
124   {
125     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size", Message_Trace);
126     Release();
127     return false;
128   }
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   }
145   myActiveFTFace = myFTFace;
146   return true;
147 }
148
149 // =======================================================================
150 // function : FindAndCreate
151 // purpose  :
152 // =======================================================================
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)
157 {
158   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
159   Font_FontAspect aFontAspect = theFontAspect;
160   Font_FTFontParams aParams = theParams;
161   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theStrictLevel, aFontAspect))
162   {
163     if (aRequestedFont->IsSingleStrokeFont())
164     {
165       aParams.IsSingleStrokeFont = true;
166     }
167
168     Standard_Integer aFaceId = 0;
169     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic, aFaceId);
170     Handle(Font_FTFont) aFont = new Font_FTFont();
171     if (aFont->Init (aPath, aParams, aFaceId))
172     {
173       aFont->myFontAspect = aFontAspect;
174       return aFont;
175     }
176   }
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     }
192     Handle(Font_FTFont) aFont = new Font_FTFont();
193     if (aFont->Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0))
194     {
195       aFont->myFontAspect = aFontAspect;
196       return aFont;
197     }
198   }
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;
212   myFontAspect = theFontAspect;
213   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
214   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, myFontAspect))
215   {
216     if (aRequestedFont->IsSingleStrokeFont())
217     {
218       aParams.IsSingleStrokeFont = true;
219     }
220
221     Standard_Integer aFaceId = 0;
222     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId);
223     return Init (aPath, aParams, aFaceId);
224   }
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     }
232     return Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0);
233   }
234   Release();
235   return false;
236 }
237
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
258     Standard_Integer aFaceId = 0;
259     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId);
260     if (myFallbackFaces[theSubset]->Init (aPath, aParams, aFaceId))
261     {
262       Message::DefaultMessenger()->Send (TCollection_AsciiString ("Font_FTFont, using fallback font '") + aRequestedFont->FontName() + "'"
263                                       + " for symbols unsupported by '" + myFTFace->family_name + "'", Message_Trace);
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
278 // =======================================================================
279 // function : loadGlyph
280 // purpose  :
281 // =======================================================================
282 bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
283 {
284   if (myUChar == theUChar)
285   {
286     return myUChar != 0;
287   }
288
289   myGlyphImg.Clear();
290   myUChar = 0;
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)
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;
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
342   if (theUChar == 0
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)
346   {
347     return false;
348   }
349
350   FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap;
351   if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
352   {
353     return false;
354   }
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
384   {
385     return false;
386   }
387
388   myUChar = theUChar;
389   return true;
390 }
391
392 // =======================================================================
393 // function : GlyphMaxSizeX
394 // purpose  :
395 // =======================================================================
396 unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const
397 {
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;
419 }
420
421 // =======================================================================
422 // function : GlyphMaxSizeY
423 // purpose  :
424 // =======================================================================
425 unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const
426 {
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;
448 }
449
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
477 // =======================================================================
478 // function : AdvanceX
479 // purpose  :
480 // =======================================================================
481 float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar,
482                              Standard_Utf32Char theUCharNext)
483 {
484   loadGlyph (theUChar);
485   return AdvanceX (theUCharNext);
486 }
487
488 // =======================================================================
489 // function : AdvanceY
490 // purpose  :
491 // =======================================================================
492 float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
493                              Standard_Utf32Char theUCharNext)
494 {
495   loadGlyph (theUChar);
496   return AdvanceY (theUCharNext);
497 }
498
499 // =======================================================================
500 // function : getKerning
501 // purpose  :
502 // =======================================================================
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;
509   if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0)
510   {
511     const FT_UInt aCharCurr = FT_Get_Char_Index (myActiveFTFace, theUCharCurr);
512     const FT_UInt aCharNext = FT_Get_Char_Index (myActiveFTFace, theUCharNext);
513     if (aCharCurr == 0 || aCharNext == 0
514      || FT_Get_Kerning (myActiveFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
515     {
516       theKern.x = 0;
517       theKern.y = 0;
518       return false;
519     }
520     return true;
521   }
522   return false;
523 }
524
525 // =======================================================================
526 // function : AdvanceX
527 // purpose  :
528 // =======================================================================
529 float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
530 {
531   if (myUChar == 0)
532   {
533     return 0.0f;
534   }
535
536   FT_Vector aKern;
537   getKerning (aKern, myUChar, theUCharNext);
538   return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x);
539 }
540
541 // =======================================================================
542 // function : AdvanceY
543 // purpose  :
544 // =======================================================================
545 float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
546 {
547   if (myUChar == 0)
548   {
549     return 0.0f;
550   }
551
552   FT_Vector aKern;
553   getKerning (aKern, myUChar, theUCharNext);
554   return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y);
555 }
556
557 // =======================================================================
558 // function : GlyphsNumber
559 // purpose  :
560 // =======================================================================
561 Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const
562 {
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;
576 }
577
578 // =======================================================================
579 // function : GlyphRect
580 // purpose  :
581 // =======================================================================
582 void Font_FTFont::GlyphRect (Font_Rect& theRect) const
583 {
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);
589 }
590
591 // =======================================================================
592 // function : BoundingBox
593 // purpose  :
594 // =======================================================================
595 Font_Rect Font_FTFont::BoundingBox (const NCollection_String&               theString,
596                                     const Graphic3d_HorizontalTextAlignment theAlignX,
597                                     const Graphic3d_VerticalTextAlignment   theAlignY)
598 {
599   Font_TextFormatter aFormatter;
600   aFormatter.SetupAlignment (theAlignX, theAlignY);
601   aFormatter.Reset();
602
603   aFormatter.Append (theString, *this);
604   aFormatter.Format();
605
606   Font_Rect aBndBox;
607   aFormatter.BndBox (aBndBox);
608   return aBndBox;
609 }