87ab2b7189c330530f282858701c3a6118745009
[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
22 #include <ft2build.h>
23 #include FT_FREETYPE_H
24
25 IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
26
27 // =======================================================================
28 // function : Font_FTFont
29 // purpose  :
30 // =======================================================================
31 Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
32 : myFTLib       (theFTLib),
33   myFTFace      (NULL),
34   myPointSize   (0U),
35   myWidthScaling(1.0),
36   myLoadFlags   (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
37   myIsSingleLine(false),
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 }
70
71 // =======================================================================
72 // function : Init
73 // purpose  :
74 // =======================================================================
75 bool Font_FTFont::Init (const NCollection_String& theFontPath,
76                         const unsigned int        thePointSize,
77                         const unsigned int        theResolution)
78 {
79   Release();
80   myFontPath  = theFontPath;
81   myPointSize = thePointSize;
82   if (!myFTLib->IsValid())
83   {
84     //std::cerr << "FreeType library is unavailable!\n";
85     Release();
86     return false;
87   }
88
89   if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), 0, &myFTFace) != 0)
90   {
91     //std::cerr << "Font '" << myFontPath << "' fail to load!\n";
92     Release();
93     return false;
94   }
95   else if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0)
96   {
97     //std::cerr << "Font '" << myFontPath << "' doesn't contains Unicode charmap!\n";
98     Release();
99     return false;
100   }
101   else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (thePointSize), theResolution, theResolution) != 0)
102   {
103     //std::cerr << "Font '" << myFontPath << "' doesn't contains Unicode charmap!\n";
104     Release();
105     return false;
106   }
107   return true;
108 }
109
110 // =======================================================================
111 // function : Init
112 // purpose  :
113 // =======================================================================
114 bool Font_FTFont::Init (const NCollection_String& theFontName,
115                         const Font_FontAspect     theFontAspect,
116                         const unsigned int        thePointSize,
117                         const unsigned int        theResolution)
118 {
119   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
120   const TCollection_AsciiString aFontName (theFontName.ToCString());
121   Font_FontAspect aFontAspect = theFontAspect;
122   if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, aFontAspect))
123   {
124     myIsSingleLine = aRequestedFont->IsSingleStrokeFont();
125     return Font_FTFont::Init (aRequestedFont->FontPathAny (aFontAspect).ToCString(), thePointSize, theResolution);
126   }
127   return false;
128 }
129
130 // =======================================================================
131 // function : loadGlyph
132 // purpose  :
133 // =======================================================================
134 bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
135 {
136   if (myUChar == theUChar)
137   {
138     return myUChar != 0;
139   }
140
141   myGlyphImg.Clear();
142   myUChar = 0;
143   if (theUChar == 0
144    || FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags)) != 0
145    || myFTFace->glyph == NULL)
146   {
147     return false;
148   }
149
150   myUChar = theUChar;
151   return true;
152 }
153
154 // =======================================================================
155 // function : RenderGlyph
156 // purpose  :
157 // =======================================================================
158 bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar)
159 {
160   myGlyphImg.Clear();
161   myUChar = 0;
162   if (theUChar == 0
163    || FT_Load_Char (myFTFace, theUChar, FT_Int32(myLoadFlags | FT_LOAD_RENDER)) != 0
164    || myFTFace->glyph == NULL
165    || myFTFace->glyph->format != FT_GLYPH_FORMAT_BITMAP)
166   {
167     return false;
168   }
169
170   FT_Bitmap aBitmap = myFTFace->glyph->bitmap;
171   if (aBitmap.pixel_mode != FT_PIXEL_MODE_GRAY
172    || aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
173   {
174     return false;
175   }
176   if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer,
177                                aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch)))
178   {
179     return false;
180   }
181   myGlyphImg.SetTopDown (aBitmap.pitch > 0);
182   myUChar = theUChar;
183   return true;
184 }
185
186 // =======================================================================
187 // function : GlyphMaxSizeX
188 // purpose  :
189 // =======================================================================
190 unsigned int Font_FTFont::GlyphMaxSizeX() const
191 {
192   float aWidth = (FT_IS_SCALABLE(myFTFace) != 0)
193                ? float(myFTFace->bbox.xMax - myFTFace->bbox.xMin) * (float(myFTFace->size->metrics.x_ppem) / float(myFTFace->units_per_EM))
194                : fromFTPoints<float> (myFTFace->size->metrics.max_advance);
195   return (unsigned int)(aWidth + 0.5f);
196 }
197
198 // =======================================================================
199 // function : GlyphMaxSizeY
200 // purpose  :
201 // =======================================================================
202 unsigned int Font_FTFont::GlyphMaxSizeY() const
203 {
204   float aHeight = (FT_IS_SCALABLE(myFTFace) != 0)
205                 ? float(myFTFace->bbox.yMax - myFTFace->bbox.yMin) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM))
206                 : fromFTPoints<float> (myFTFace->size->metrics.height);
207   return (unsigned int)(aHeight + 0.5f);
208 }
209
210 // =======================================================================
211 // function : Ascender
212 // purpose  :
213 // =======================================================================
214 float Font_FTFont::Ascender() const
215 {
216   return float(myFTFace->ascender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
217 }
218
219 // =======================================================================
220 // function : Descender
221 // purpose  :
222 // =======================================================================
223 float Font_FTFont::Descender() const
224 {
225   return float(myFTFace->descender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
226 }
227
228 // =======================================================================
229 // function : LineSpacing
230 // purpose  :
231 // =======================================================================
232 float Font_FTFont::LineSpacing() const
233 {
234   return float(myFTFace->height) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
235 }
236
237 // =======================================================================
238 // function : AdvanceX
239 // purpose  :
240 // =======================================================================
241 float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar,
242                              Standard_Utf32Char theUCharNext)
243 {
244   loadGlyph (theUChar);
245   return AdvanceX (theUCharNext);
246 }
247
248 // =======================================================================
249 // function : AdvanceY
250 // purpose  :
251 // =======================================================================
252 float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
253                              Standard_Utf32Char theUCharNext)
254 {
255   loadGlyph (theUChar);
256   return AdvanceY (theUCharNext);
257 }
258
259 bool Font_FTFont::getKerning (FT_Vector& theKern,
260                               Standard_Utf32Char theUCharCurr,
261                               Standard_Utf32Char theUCharNext) const
262 {
263   theKern.x = 0;
264   theKern.y = 0;
265   if (theUCharNext != 0 && FT_HAS_KERNING(myFTFace) != 0)
266   {
267     const FT_UInt aCharCurr = FT_Get_Char_Index (myFTFace, theUCharCurr);
268     const FT_UInt aCharNext = FT_Get_Char_Index (myFTFace, theUCharNext);
269     if (aCharCurr == 0 || aCharNext == 0
270      || FT_Get_Kerning (myFTFace, aCharCurr, aCharNext, FT_KERNING_UNFITTED, &theKern) != 0)
271     {
272       theKern.x = 0;
273       theKern.y = 0;
274       return false;
275     }
276     return true;
277   }
278   return false;
279 }
280
281 // =======================================================================
282 // function : AdvanceX
283 // purpose  :
284 // =======================================================================
285 float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
286 {
287   if (myUChar == 0)
288   {
289     return 0.0f;
290   }
291
292   FT_Vector aKern;
293   getKerning (aKern, myUChar, theUCharNext);
294   return myWidthScaling * fromFTPoints<float> (myFTFace->glyph->advance.x + aKern.x);
295 }
296
297 // =======================================================================
298 // function : AdvanceY
299 // purpose  :
300 // =======================================================================
301 float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
302 {
303   if (myUChar == 0)
304   {
305     return 0.0f;
306   }
307
308   FT_Vector aKern;
309   getKerning (aKern, myUChar, theUCharNext);
310   return fromFTPoints<float> (myFTFace->glyph->advance.y + aKern.y);
311 }
312
313 // =======================================================================
314 // function : GlyphsNumber
315 // purpose  :
316 // =======================================================================
317 Standard_Integer Font_FTFont::GlyphsNumber() const
318 {
319   return myFTFace->num_glyphs;
320 }
321
322 // =======================================================================
323 // function : theRect
324 // purpose  :
325 // =======================================================================
326 void Font_FTFont::GlyphRect (Font_Rect& theRect) const
327 {
328   const FT_Bitmap& aBitmap = myFTFace->glyph->bitmap;
329   theRect.Left   = float(myFTFace->glyph->bitmap_left);
330   theRect.Top    = float(myFTFace->glyph->bitmap_top);
331   theRect.Right  = float(myFTFace->glyph->bitmap_left + (int )aBitmap.width);
332   theRect.Bottom = float(myFTFace->glyph->bitmap_top  - (int )aBitmap.rows);
333 }
334
335 // =======================================================================
336 // function : BoundingBox
337 // purpose  :
338 // =======================================================================
339 Font_Rect Font_FTFont::BoundingBox (const NCollection_String&               theString,
340                                     const Graphic3d_HorizontalTextAlignment theAlignX,
341                                     const Graphic3d_VerticalTextAlignment   theAlignY)
342 {
343   Font_TextFormatter aFormatter;
344   aFormatter.SetupAlignment (theAlignX, theAlignY);
345   aFormatter.Reset();
346
347   aFormatter.Append (theString, *this);
348   aFormatter.Format();
349
350   Font_Rect aBndBox;
351   aFormatter.BndBox (aBndBox);
352   return aBndBox;
353 }