0030679: Attached model hangs most of OCCT common functionality
[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 <ft2build.h>
25 #include FT_FREETYPE_H
26
27 IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
28
29 // =======================================================================
30 // function : Font_FTFont
31 // purpose  :
32 // =======================================================================
33 Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
34 : myFTLib       (theFTLib),
35   myFTFace      (NULL),
36   myWidthScaling(1.0),
37   myLoadFlags   (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
38   myUChar       (0U)
39 {
40   if (myFTLib.IsNull())
41   {
42     myFTLib = new Font_FTLibrary();
43   }
44 }
45
46 // =======================================================================
47 // function : Font_FTFont
48 // purpose  :
49 // =======================================================================
50 Font_FTFont::~Font_FTFont()
51 {
52   Release();
53 }
54
55 // =======================================================================
56 // function : Release
57 // purpose  :
58 // =======================================================================
59 void Font_FTFont::Release()
60 {
61   myGlyphImg.Clear();
62   myFontPath.Clear();
63   myUChar = 0;
64   if (myFTFace != NULL)
65   {
66     FT_Done_Face (myFTFace);
67     myFTFace = NULL;
68   }
69   myBuffer.Nullify();
70 }
71
72 // =======================================================================
73 // function : Init
74 // purpose  :
75 // =======================================================================
76 bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
77                         const TCollection_AsciiString& theFileName,
78                         const Font_FTFontParams& theParams)
79 {
80   Release();
81   myBuffer = theData;
82   myFontPath = theFileName;
83   myFontParams = theParams;
84   if (!myFTLib->IsValid())
85   {
86     Message::DefaultMessenger()->Send ("FreeType library is unavailable", Message_Trace);
87     Release();
88     return false;
89   }
90
91   if (!theData.IsNull())
92   {
93     if (FT_New_Memory_Face (myFTLib->Instance(), theData->Data(), (FT_Long )theData->Size(), 0, &myFTFace) != 0)
94     {
95       Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from memory", Message_Trace);
96       Release();
97       return false;
98     }
99   }
100   else
101   {
102     if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), 0, &myFTFace) != 0)
103     {
104       //Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from file", Message_Trace);
105       Release();
106       return false;
107     }
108   }
109
110   if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0)
111   {
112     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap", Message_Trace);
113     Release();
114     return false;
115   }
116   else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0)
117   {
118     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size", Message_Trace);
119     Release();
120     return false;
121   }
122
123   if (theParams.ToSynthesizeItalic)
124   {
125     const double THE_SHEAR_ANGLE = 10.0 * M_PI / 180.0;
126
127     FT_Matrix aMat;
128     aMat.xx = FT_Fixed (Cos (-THE_SHEAR_ANGLE) * (1 << 16));
129     aMat.xy = 0;
130     aMat.yx = 0;
131     aMat.yy = aMat.xx;
132
133     FT_Fixed aFactor = FT_Fixed (Tan (THE_SHEAR_ANGLE) * (1 << 16));
134     aMat.xy += FT_MulFix (aFactor, aMat.xx);
135
136     FT_Set_Transform (myFTFace, &aMat, 0);
137   }
138   return true;
139 }
140
141 // =======================================================================
142 // function : FindAndCreate
143 // purpose  :
144 // =======================================================================
145 Handle(Font_FTFont) Font_FTFont::FindAndCreate (const TCollection_AsciiString& theFontName,
146                                                 const Font_FontAspect     theFontAspect,
147                                                 const Font_FTFontParams&  theParams,
148                                                 const Font_StrictLevel    theStrictLevel)
149 {
150   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
151   Font_FontAspect aFontAspect = theFontAspect;
152   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theStrictLevel, aFontAspect))
153   {
154     Font_FTFontParams aParams = theParams;
155     if (aRequestedFont->IsSingleStrokeFont())
156     {
157       aParams.IsSingleStrokeFont = true;
158     }
159
160     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic);
161     Handle(Font_FTFont) aFont = new Font_FTFont();
162     if (aFont->Init (aPath, aParams))
163     {
164       return aFont;
165     }
166   }
167   return Handle(Font_FTFont)();
168 }
169
170 // =======================================================================
171 // function : FindAndInit
172 // purpose  :
173 // =======================================================================
174 bool Font_FTFont::FindAndInit (const TCollection_AsciiString& theFontName,
175                                Font_FontAspect theFontAspect,
176                                const Font_FTFontParams& theParams,
177                                Font_StrictLevel theStrictLevel)
178 {
179   Font_FTFontParams aParams = theParams;
180   Font_FontAspect aFontAspect = theFontAspect;
181   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
182   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName.ToCString(), theStrictLevel, aFontAspect))
183   {
184     if (aRequestedFont->IsSingleStrokeFont())
185     {
186       aParams.IsSingleStrokeFont = true;
187     }
188
189     const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (aFontAspect, aParams.ToSynthesizeItalic);
190     return Init (aPath, aParams);
191   }
192   Release();
193   return false;
194 }
195
196 // =======================================================================
197 // function : loadGlyph
198 // purpose  :
199 // =======================================================================
200 bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
201 {
202   if (myUChar == theUChar)
203   {
204     return myUChar != 0;
205   }
206
207   myGlyphImg.Clear();
208   myUChar = 0;
209   if (theUChar == 0
210    || FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags)) != 0
211    || myFTFace->glyph == NULL)
212   {
213     return false;
214   }
215
216   myUChar = theUChar;
217   return true;
218 }
219
220 // =======================================================================
221 // function : RenderGlyph
222 // purpose  :
223 // =======================================================================
224 bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar)
225 {
226   myGlyphImg.Clear();
227   myUChar = 0;
228   if (theUChar == 0
229    || FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0
230    || myFTFace->glyph == NULL
231    || myFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
232   {
233     return false;
234   }
235
236   FT_Bitmap aBitmap = myFTFace->glyph->bitmap;
237   if (aBitmap.pixel_mode != FT_PIXEL_MODE_GRAY
238    || aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
239   {
240     return false;
241   }
242   if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer,
243                                aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch)))
244   {
245     return false;
246   }
247   myGlyphImg.SetTopDown (aBitmap.pitch > 0);
248   myUChar = theUChar;
249   return true;
250 }
251
252 // =======================================================================
253 // function : GlyphMaxSizeX
254 // purpose  :
255 // =======================================================================
256 unsigned int Font_FTFont::GlyphMaxSizeX() const
257 {
258   float aWidth = (FT_IS_SCALABLE(myFTFace) != 0)
259                ? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM))
260                : fromFTPoints<float> (myFTFace->size->metrics.max_advance);
261   return (unsigned int)(aWidth + 0.5f);
262 }
263
264 // =======================================================================
265 // function : GlyphMaxSizeY
266 // purpose  :
267 // =======================================================================
268 unsigned int Font_FTFont::GlyphMaxSizeY() const
269 {
270   float aHeight = (FT_IS_SCALABLE(myFTFace) != 0)
271                 ? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM))
272                 : fromFTPoints<float> (myFTFace->size->metrics.height);
273   return (unsigned int)(aHeight + 0.5f);
274 }
275
276 // =======================================================================
277 // function : Ascender
278 // purpose  :
279 // =======================================================================
280 float Font_FTFont::Ascender() const
281 {
282   return float(myFTFace->ascender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
283 }
284
285 // =======================================================================
286 // function : Descender
287 // purpose  :
288 // =======================================================================
289 float Font_FTFont::Descender() const
290 {
291   return float(myFTFace->descender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
292 }
293
294 // =======================================================================
295 // function : LineSpacing
296 // purpose  :
297 // =======================================================================
298 float Font_FTFont::LineSpacing() const
299 {
300   return float(myFTFace->height) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
301 }
302
303 // =======================================================================
304 // function : AdvanceX
305 // purpose  :
306 // =======================================================================
307 float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar,
308                              Standard_Utf32Char theUCharNext)
309 {
310   loadGlyph (theUChar);
311   return AdvanceX (theUCharNext);
312 }
313
314 // =======================================================================
315 // function : AdvanceY
316 // purpose  :
317 // =======================================================================
318 float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
319                              Standard_Utf32Char theUCharNext)
320 {
321   loadGlyph (theUChar);
322   return AdvanceY (theUCharNext);
323 }
324
325 bool Font_FTFont::getKerning (FT_Vector& theKern,
326                               Standard_Utf32Char theUCharCurr,
327                               Standard_Utf32Char theUCharNext) const
328 {
329   theKern.x = 0;
330   theKern.y = 0;
331   if (theUCharNext != 0 && FT_HAS_KERNING(myFTFace) != 0)
332   {
333     const FT_UInt aCharCurr = FT_Get_Char_Index (myFTFace, theUCharCurr);
334     const FT_UInt aCharNext = FT_Get_Char_Index (myFTFace, theUCharNext);
335     if (aCharCurr == 0 || aCharNext == 0
336      || FT_Get_Kerning (myFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
337     {
338       theKern.x = 0;
339       theKern.y = 0;
340       return false;
341     }
342     return true;
343   }
344   return false;
345 }
346
347 // =======================================================================
348 // function : AdvanceX
349 // purpose  :
350 // =======================================================================
351 float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
352 {
353   if (myUChar == 0)
354   {
355     return 0.0f;
356   }
357
358   FT_Vector aKern;
359   getKerning (aKern, myUChar, theUCharNext);
360   return myWidthScaling * fromFTPoints<float> (myFTFace->glyph->advance.x + aKern.x);
361 }
362
363 // =======================================================================
364 // function : AdvanceY
365 // purpose  :
366 // =======================================================================
367 float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
368 {
369   if (myUChar == 0)
370   {
371     return 0.0f;
372   }
373
374   FT_Vector aKern;
375   getKerning (aKern, myUChar, theUCharNext);
376   return fromFTPoints<float> (myFTFace->glyph->advance.y + aKern.y);
377 }
378
379 // =======================================================================
380 // function : GlyphsNumber
381 // purpose  :
382 // =======================================================================
383 Standard_Integer Font_FTFont::GlyphsNumber() const
384 {
385   return myFTFace->num_glyphs;
386 }
387
388 // =======================================================================
389 // function : theRect
390 // purpose  :
391 // =======================================================================
392 void Font_FTFont::GlyphRect (Font_Rect& theRect) const
393 {
394   const FT_Bitmap& aBitmap = myFTFace->glyph->bitmap;
395   theRect.Left   = float(myFTFace->glyph->bitmap_left);
396   theRect.Top    = float(myFTFace->glyph->bitmap_top);
397   theRect.Right  = float(myFTFace->glyph->bitmap_left + (int )aBitmap.width);
398   theRect.Bottom = float(myFTFace->glyph->bitmap_top  - (int )aBitmap.rows);
399 }
400
401 // =======================================================================
402 // function : BoundingBox
403 // purpose  :
404 // =======================================================================
405 Font_Rect Font_FTFont::BoundingBox (const NCollection_String&               theString,
406                                     const Graphic3d_HorizontalTextAlignment theAlignX,
407                                     const Graphic3d_VerticalTextAlignment   theAlignY)
408 {
409   Font_TextFormatter aFormatter;
410   aFormatter.SetupAlignment (theAlignX, theAlignY);
411   aFormatter.Reset();
412
413   aFormatter.Append (theString, *this);
414   aFormatter.Format();
415
416   Font_Rect aBndBox;
417   aFormatter.BndBox (aBndBox);
418   return aBndBox;
419 }