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