1 // Created on: 2013-01-28
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Font_FTFont.hxx>
18 #include <Font_FTLibrary.hxx>
19 #include <Font_FontMgr.hxx>
20 #include <Font_TextFormatter.hxx>
21 #include <Message.hxx>
22 #include <Message_Messenger.hxx>
27 #include FT_FREETYPE_H
29 IMPLEMENT_STANDARD_RTTIEXT(Font_FTFont,Standard_Transient)
31 // =======================================================================
32 // function : Font_FTFont
34 // =======================================================================
35 Font_FTFont::Font_FTFont (const Handle(Font_FTLibrary)& theFTLib)
39 myFontAspect (Font_FontAspect_Regular),
41 myLoadFlags (FT_LOAD_NO_HINTING | FT_LOAD_TARGET_NORMAL),
43 myToUseUnicodeSubsetFallback (Font_FontMgr::ToUseUnicodeSubsetFallback())
47 myFTLib = new Font_FTLibrary();
51 // =======================================================================
52 // function : Font_FTFont
54 // =======================================================================
55 Font_FTFont::~Font_FTFont()
60 // =======================================================================
63 // =======================================================================
64 void Font_FTFont::Release()
71 FT_Done_Face (myFTFace);
74 myActiveFTFace = NULL;
78 // =======================================================================
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)
89 myFontPath = theFileName;
90 myFontParams = theParams;
91 if (!myFTLib->IsValid())
93 Message::SendTrace ("FreeType library is unavailable");
98 if (!theData.IsNull())
100 if (FT_New_Memory_Face (myFTLib->Instance(), theData->Data(), (FT_Long )theData->Size(), (FT_Long )theFaceId, &myFTFace) != 0)
102 Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from memory");
109 if (FT_New_Face (myFTLib->Instance(), myFontPath.ToCString(), (FT_Long )theFaceId, &myFTFace) != 0)
111 //Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' failed to load from file");
117 if (FT_Select_Charmap (myFTFace, ft_encoding_unicode) != 0)
119 Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap");
123 else if (FT_Set_Char_Size (myFTFace, 0L, toFTPoints (theParams.PointSize), theParams.Resolution, theParams.Resolution) != 0)
125 Message::SendTrace (TCollection_AsciiString("Font '") + myFontPath + "' doesn't contains Unicode charmap of requested size");
130 if (theParams.ToSynthesizeItalic)
132 const double THE_SHEAR_ANGLE = 10.0 * M_PI / 180.0;
135 aMat.xx = FT_Fixed (Cos (-THE_SHEAR_ANGLE) * (1 << 16));
140 FT_Fixed aFactor = FT_Fixed (Tan (THE_SHEAR_ANGLE) * (1 << 16));
141 aMat.xy += FT_MulFix (aFactor, aMat.xx);
143 FT_Set_Transform (myFTFace, &aMat, 0);
145 myActiveFTFace = myFTFace;
149 // =======================================================================
150 // function : FindAndCreate
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)
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))
163 if (aRequestedFont->IsSingleStrokeFont())
165 aParams.IsSingleStrokeFont = true;
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))
173 aFont->myFontAspect = aFontAspect;
177 else if (theStrictLevel == Font_StrictLevel_Any)
179 switch (theFontAspect)
181 case Font_FontAspect_UNDEFINED:
182 case Font_FontAspect_Regular:
183 case Font_FontAspect_Bold:
184 aFontAspect = Font_FontAspect_Regular;
186 case Font_FontAspect_Italic:
187 case Font_FontAspect_BoldItalic:
188 aFontAspect = Font_FontAspect_Italic;
189 aParams.ToSynthesizeItalic = true;
192 Handle(Font_FTFont) aFont = new Font_FTFont();
193 if (aFont->Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0))
195 aFont->myFontAspect = aFontAspect;
199 return Handle(Font_FTFont)();
202 // =======================================================================
203 // function : FindAndInit
205 // =======================================================================
206 bool Font_FTFont::FindAndInit (const TCollection_AsciiString& theFontName,
207 Font_FontAspect theFontAspect,
208 const Font_FTFontParams& theParams,
209 Font_StrictLevel theStrictLevel)
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))
216 if (aRequestedFont->IsSingleStrokeFont())
218 aParams.IsSingleStrokeFont = true;
221 Standard_Integer aFaceId = 0;
222 const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId);
223 return Init (aPath, aParams, aFaceId);
225 else if (theStrictLevel == Font_StrictLevel_Any)
227 if (theFontAspect == Font_FontAspect_Italic
228 || theFontAspect == Font_FontAspect_BoldItalic)
230 aParams.ToSynthesizeItalic = true;
232 return Init (Font_FontMgr::EmbedFallbackFont(), "Embed Fallback Font", aParams, 0);
238 // =======================================================================
239 // function : findAndInitFallback
241 // =======================================================================
242 bool Font_FTFont::findAndInitFallback (Font_UnicodeSubset theSubset)
244 if (!myFallbackFaces[theSubset].IsNull())
246 return myFallbackFaces[theSubset]->IsValid();
249 myFallbackFaces[theSubset] = new Font_FTFont (myFTLib);
250 myFallbackFaces[theSubset]->myToUseUnicodeSubsetFallback = false; // no recursion
252 Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
253 if (Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFallbackFont (theSubset, myFontAspect))
255 Font_FTFontParams aParams = myFontParams;
256 aParams.IsSingleStrokeFont = aRequestedFont->IsSingleStrokeFont();
258 Standard_Integer aFaceId = 0;
259 const TCollection_AsciiString& aPath = aRequestedFont->FontPathAny (myFontAspect, aParams.ToSynthesizeItalic, aFaceId);
260 if (myFallbackFaces[theSubset]->Init (aPath, aParams, aFaceId))
262 Message::SendTrace (TCollection_AsciiString ("Font_FTFont, using fallback font '") + aRequestedFont->FontName() + "'"
263 + " for symbols unsupported by '" + myFTFace->family_name + "'");
266 return myFallbackFaces[theSubset]->IsValid();
269 // =======================================================================
270 // function : HasSymbol
272 // =======================================================================
273 bool Font_FTFont::HasSymbol (Standard_Utf32Char theUChar) const
275 return FT_Get_Char_Index (myFTFace, theUChar) != 0;
278 // =======================================================================
279 // function : loadGlyph
281 // =======================================================================
282 bool Font_FTFont::loadGlyph (const Standard_Utf32Char theUChar)
284 if (myUChar == theUChar)
291 myActiveFTFace = myFTFace;
297 if (myToUseUnicodeSubsetFallback
298 && !HasSymbol (theUChar))
300 // try using fallback
301 const Font_UnicodeSubset aSubset = CharSubset (theUChar);
302 if (findAndInitFallback (aSubset)
303 && myFallbackFaces[aSubset]->HasSymbol (theUChar))
305 myActiveFTFace = myFallbackFaces[aSubset]->myFTFace;
309 if (FT_Load_Char (myActiveFTFace, theUChar, FT_Int32(myLoadFlags)) != 0
310 || myActiveFTFace->glyph == NULL)
319 // =======================================================================
320 // function : RenderGlyph
322 // =======================================================================
323 bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar)
327 myActiveFTFace = myFTFace;
330 && myToUseUnicodeSubsetFallback
331 && !HasSymbol (theUChar))
333 // try using fallback
334 const Font_UnicodeSubset aSubset = CharSubset (theUChar);
335 if (findAndInitFallback (aSubset)
336 && myFallbackFaces[aSubset]->HasSymbol (theUChar))
338 myActiveFTFace = myFallbackFaces[aSubset]->myFTFace;
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)
350 FT_Bitmap aBitmap = myActiveFTFace->glyph->bitmap;
351 if (aBitmap.buffer == NULL || aBitmap.width == 0 || aBitmap.rows == 0)
356 if (aBitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
358 if (!myGlyphImg.InitWrapper (Image_Format_Alpha, aBitmap.buffer,
359 aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch)))
363 myGlyphImg.SetTopDown (aBitmap.pitch > 0);
365 else if (aBitmap.pixel_mode == FT_PIXEL_MODE_MONO)
367 if (!myGlyphImg.InitTrash (Image_Format_Gray, aBitmap.width, aBitmap.rows))
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)
376 for (int aCol = 0; aCol < (int )aBitmap.width; ++aCol)
378 const int aBitOn = aBitmap.buffer[aNumOfBytesInRow * aRow + aCol / 8] & (0x80 >> (aCol % 8));
379 *myGlyphImg.ChangeRawValue (aRow, aCol) = aBitOn ? 255 : 0;
392 // =======================================================================
393 // function : GlyphMaxSizeX
395 // =======================================================================
396 unsigned int Font_FTFont::GlyphMaxSizeX (bool theToIncludeFallback) const
398 if (!theToIncludeFallback)
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);
406 unsigned int aWidth = GlyphMaxSizeX (false);
407 if (theToIncludeFallback)
409 for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
411 if (!myFallbackFaces[aFontIter].IsNull()
412 && myFallbackFaces[aFontIter]->IsValid())
414 aWidth = std::max (aWidth, myFallbackFaces[aFontIter]->GlyphMaxSizeX (false));
421 // =======================================================================
422 // function : GlyphMaxSizeY
424 // =======================================================================
425 unsigned int Font_FTFont::GlyphMaxSizeY (bool theToIncludeFallback) const
427 if (!theToIncludeFallback)
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);
435 unsigned int aHeight = GlyphMaxSizeY (false);
436 if (theToIncludeFallback)
438 for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
440 if (!myFallbackFaces[aFontIter].IsNull()
441 && myFallbackFaces[aFontIter]->IsValid())
443 aHeight = std::max (aHeight, myFallbackFaces[aFontIter]->GlyphMaxSizeY (false));
450 // =======================================================================
451 // function : Ascender
453 // =======================================================================
454 float Font_FTFont::Ascender() const
456 return float(myFTFace->ascender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
459 // =======================================================================
460 // function : Descender
462 // =======================================================================
463 float Font_FTFont::Descender() const
465 return float(myFTFace->descender) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
468 // =======================================================================
469 // function : LineSpacing
471 // =======================================================================
472 float Font_FTFont::LineSpacing() const
474 return float(myFTFace->height) * (float(myFTFace->size->metrics.y_ppem) / float(myFTFace->units_per_EM));
477 // =======================================================================
478 // function : AdvanceX
480 // =======================================================================
481 float Font_FTFont::AdvanceX (Standard_Utf32Char theUChar,
482 Standard_Utf32Char theUCharNext)
484 loadGlyph (theUChar);
485 return AdvanceX (theUCharNext);
488 // =======================================================================
489 // function : AdvanceY
491 // =======================================================================
492 float Font_FTFont::AdvanceY (Standard_Utf32Char theUChar,
493 Standard_Utf32Char theUCharNext)
495 loadGlyph (theUChar);
496 return AdvanceY (theUCharNext);
499 // =======================================================================
500 // function : getKerning
502 // =======================================================================
503 bool Font_FTFont::getKerning (FT_Vector& theKern,
504 Standard_Utf32Char theUCharCurr,
505 Standard_Utf32Char theUCharNext) const
509 if (theUCharNext != 0 && FT_HAS_KERNING(myActiveFTFace) != 0)
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)
525 // =======================================================================
526 // function : AdvanceX
528 // =======================================================================
529 float Font_FTFont::AdvanceX (Standard_Utf32Char theUCharNext) const
537 getKerning (aKern, myUChar, theUCharNext);
538 return myWidthScaling * fromFTPoints<float> (myActiveFTFace->glyph->advance.x + aKern.x);
541 // =======================================================================
542 // function : AdvanceY
544 // =======================================================================
545 float Font_FTFont::AdvanceY (Standard_Utf32Char theUCharNext) const
553 getKerning (aKern, myUChar, theUCharNext);
554 return fromFTPoints<float> (myActiveFTFace->glyph->advance.y + aKern.y);
557 // =======================================================================
558 // function : GlyphsNumber
560 // =======================================================================
561 Standard_Integer Font_FTFont::GlyphsNumber (bool theToIncludeFallback) const
563 Standard_Integer aNbGlyphs = myFTFace->num_glyphs;
564 if (theToIncludeFallback)
566 for (Standard_Integer aFontIter = 0; aFontIter < Font_UnicodeSubset_NB; ++aFontIter)
568 if (!myFallbackFaces[aFontIter].IsNull()
569 && myFallbackFaces[aFontIter]->IsValid())
571 aNbGlyphs += myFallbackFaces[aFontIter]->GlyphsNumber (false);
578 // =======================================================================
579 // function : GlyphRect
581 // =======================================================================
582 void Font_FTFont::GlyphRect (Font_Rect& theRect) const
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);
591 // =======================================================================
592 // function : BoundingBox
594 // =======================================================================
595 Font_Rect Font_FTFont::BoundingBox (const NCollection_String& theString,
596 const Graphic3d_HorizontalTextAlignment theAlignX,
597 const Graphic3d_VerticalTextAlignment theAlignY)
599 Font_TextFormatter aFormatter;
600 aFormatter.SetupAlignment (theAlignX, theAlignY);
603 aFormatter.Append (theString, *this);
607 aFormatter.BndBox (aBndBox);
611 // =======================================================================
612 // function : renderGlyphOutline
614 // =======================================================================
615 const FT_Outline* Font_FTFont::renderGlyphOutline (const Standard_Utf32Char theChar)
617 if (!loadGlyph (theChar)
618 || myActiveFTFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
622 return &myActiveFTFace->glyph->outline;