14 #ifdef MYGUI_USE_FREETYPE
17 # include FT_TRUETYPE_TABLES_H
19 # include FT_WINFONTS_H
36 # ifndef MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
37 # define MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX 1
40 #endif // MYGUI_USE_FREETYPE
45 #ifndef MYGUI_USE_FREETYPE
57 MYGUI_LOG(Error,
"ResourceTrueTypeFont: TrueType font '" <<
getResourceName() <<
"' disabled. Define MYGUI_USE_FREETYE if you need TrueType fonts.");
77 return std::vector<std::pair<Char, Char> >();
133 #else // MYGUI_USE_FREETYPE
138 void setMax(T& _var,
const T& _newValue)
140 if (_var < _newValue)
144 std::pair<const Char, const uint8> charMaskData[] =
152 const std::map<const Char, const uint8> charMask(charMaskData, charMaskData +
sizeof charMaskData /
sizeof(*charMaskData));
154 const uint8 charMaskBlack = (
const uint8)
'\x00';
155 const uint8 charMaskWhite = (
const uint8)
'\xFF';
157 template<
bool LAMode>
164 static size_t getNumBytes();
173 struct PixelBase<false>
175 static size_t getNumBytes()
188 *_dest++ = _luminance;
189 *_dest++ = _luminance;
190 *_dest++ = _luminance;
196 struct PixelBase<true>
198 static size_t getNumBytes()
211 *_dest++ = _luminance;
216 template<
bool LAMode,
bool FromSource = false,
bool Antialias = false>
217 struct Pixel : PixelBase<LAMode>
227 template<
bool LAMode,
bool Antialias>
228 struct Pixel<LAMode, false, Antialias> : PixelBase<LAMode>
233 PixelBase<LAMode>::set(_dest, _luminance, _alpha);
237 template<
bool LAMode>
238 struct Pixel<LAMode, true, false> : PixelBase<LAMode>
243 PixelBase<LAMode>::set(_dest, _luminance, *_source++);
247 template<
bool LAMode>
248 struct Pixel<LAMode, true, true> : PixelBase<LAMode>
253 PixelBase<LAMode>::set(_dest, *_source, *_source);
260 const int ResourceTrueTypeFont::mDefaultGlyphSpacing = 1;
261 const float ResourceTrueTypeFont::mDefaultTabWidth = 8.0f;
262 const float ResourceTrueTypeFont::mSelectedWidth = 1.0f;
263 const float ResourceTrueTypeFont::mCursorWidth = 2.0f;
268 mHinting(HintingUseNative),
274 mSubstituteCodePoint(static_cast<
Char>(FontCodeType::
NotDefined)),
283 if (mTexture !=
nullptr)
294 xml::ElementEnumerator node = _node->getElementEnumerator();
297 if (node->getName() ==
"Property")
299 const std::string& key = node->findAttribute(
"key");
300 const std::string& value = node->findAttribute(
"value");
303 else if (key ==
"Size")
305 else if (key ==
"Resolution")
307 else if (key ==
"Antialias")
309 else if (key ==
"TabWidth")
311 else if (key ==
"OffsetHeight")
313 else if (key ==
"SubstituteCode")
315 else if (key ==
"Distance")
317 else if (key ==
"Hinting")
319 else if (key ==
"SpaceWidth")
322 MYGUI_LOG(Warning, _node->findAttribute(
"type") <<
": Property '" << key <<
"' in font '" << _node->findAttribute(
"name") <<
"' is deprecated; remove it to use automatic calculation.");
324 else if (key ==
"CursorWidth")
326 MYGUI_LOG(Warning, _node->findAttribute(
"type") <<
": Property '" << key <<
"' in font '" << _node->findAttribute(
"name") <<
"' is deprecated; value ignored.");
329 else if (node->getName() ==
"Codes")
332 xml::ElementEnumerator range = node->getElementEnumerator();
333 while (range.next(
"Code"))
335 std::string range_value;
336 if (range->findAttribute(
"range", range_value))
338 std::vector<std::string> parse_range =
utility::split(range_value);
339 if (!parse_range.empty())
350 if (mCharMap.empty())
354 range = node->getElementEnumerator();
355 while (range.next(
"Code"))
357 std::string range_value;
358 if (range->findAttribute(
"hide", range_value))
360 std::vector<std::string> parse_range =
utility::split(range_value);
361 if (!parse_range.empty())
377 CharMap::const_iterator charIter = mCharMap.find(_id);
379 if (charIter != mCharMap.end())
381 GlyphMap::iterator glyphIter = mGlyphMap.find(charIter->second);
383 if (glyphIter != mGlyphMap.end())
384 return &glyphIter->second;
387 return mSubstituteGlyphInfo;
397 return mDefaultHeight;
402 std::vector<std::pair<Char, Char> > result;
404 if (!mCharMap.empty())
406 CharMap::const_iterator iter = mCharMap.begin(), endIter = mCharMap.end();
409 Char rangeBegin = iter->first, rangeEnd = rangeBegin;
412 for (++iter; iter != endIter; ++iter)
414 if (iter->first == rangeEnd + 1)
422 result.push_back(std::make_pair(rangeBegin, rangeEnd));
425 rangeBegin = rangeEnd = iter->first;
430 result.push_back(std::make_pair(rangeBegin, rangeEnd));
438 return mSubstituteCodePoint;
441 void ResourceTrueTypeFont::addCodePoint(
Char _codePoint)
443 mCharMap.insert(CharMap::value_type(_codePoint, 0));
446 void ResourceTrueTypeFont::removeCodePoint(
Char _codePoint)
448 mCharMap.erase(_codePoint);
453 CharMap::iterator positionHint = mCharMap.lower_bound(_first);
455 if (positionHint != mCharMap.begin())
458 for (
Char i = _first; i <= _second; ++i)
459 positionHint = mCharMap.insert(positionHint, CharMap::value_type(i, 0));
464 mCharMap.erase(mCharMap.lower_bound(_first), mCharMap.upper_bound(_second));
467 void ResourceTrueTypeFont::clearCodePoints()
474 if (mGlyphSpacing == -1)
475 mGlyphSpacing = mDefaultGlyphSpacing;
483 int init = (laMode ? 2 : 0) | (mAntialias ? 1 : 0);
488 ResourceTrueTypeFont::initialiseFreeType<false, false>();
491 ResourceTrueTypeFont::initialiseFreeType<false, true>();
494 ResourceTrueTypeFont::initialiseFreeType<true, false>();
497 ResourceTrueTypeFont::initialiseFreeType<true, true>();
502 template<
bool LAMode,
bool Antialias>
503 void ResourceTrueTypeFont::initialiseFreeType()
509 FT_Library ftLibrary;
511 if (FT_Init_FreeType(&ftLibrary) != 0)
512 MYGUI_EXCEPT(
"ResourceTrueTypeFont: Could not init the FreeType library!");
514 uint8* fontBuffer =
nullptr;
516 FT_Face ftFace = loadFace(ftLibrary, fontBuffer);
518 if (ftFace ==
nullptr)
532 int fontAscent = ftFace->size->metrics.ascender >> 6;
533 int fontDescent = -ftFace->size->metrics.descender >> 6;
535 TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table(ftFace, ft_sfnt_os2);
539 setMax(fontAscent, os2->usWinAscent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
540 setMax(fontDescent, os2->usWinDescent * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
542 setMax(fontAscent, os2->sTypoAscender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
543 setMax(fontDescent, -os2->sTypoDescender * ftFace->size->metrics.y_ppem / ftFace->units_per_EM);
550 mDefaultHeight = fontAscent + fontDescent;
553 FT_Int32 ftLoadFlags;
557 case HintingForceAuto:
558 ftLoadFlags = FT_LOAD_FORCE_AUTOHINT;
560 case HintingDisableAuto:
561 ftLoadFlags = FT_LOAD_NO_AUTOHINT;
563 case HintingDisableAll:
566 ftLoadFlags = FT_LOAD_NO_HINTING | FT_LOAD_RENDER;
570 ftLoadFlags = FT_LOAD_DEFAULT;
578 GlyphHeightMap glyphHeightMap;
586 for (CharMap::iterator iter = mCharMap.begin(); iter != mCharMap.end(); )
588 const Char& codePoint = iter->first;
589 FT_UInt glyphIndex = FT_Get_Char_Index(ftFace, codePoint);
591 texWidth += createFaceGlyph(glyphIndex, codePoint, fontAscent, ftFace, ftLoadFlags, glyphHeightMap);
595 if (iter->second != 0)
598 mCharMap.erase(iter++);
601 #if MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
603 bool isBytecodeAvailable = (ftFace->face_flags & FT_FACE_FLAG_HINTER) != 0;
604 bool isBytecodeUsedByLoadFlags = (ftLoadFlags & (FT_LOAD_FORCE_AUTOHINT | FT_LOAD_NO_HINTING)) == 0;
606 if (isBytecodeAvailable && isBytecodeUsedByLoadFlags)
608 for (GlyphMap::iterator iter = mGlyphMap.begin(); iter != mGlyphMap.end(); ++iter)
610 if (FT_Load_Glyph(ftFace, iter->first, ftLoadFlags) == 0)
612 GlyphInfo& info = iter->second;
613 GlyphInfo newInfo = createFaceGlyphInfo(0, fontAscent, ftFace->glyph);
615 if (info.width != newInfo.width)
617 texWidth += (int)ceil(newInfo.width) - (int)ceil(info.width);
618 info.width = newInfo.width;
621 if (info.height != newInfo.height)
623 GlyphHeightMap::mapped_type oldHeightMap = glyphHeightMap[(FT_Pos)info.height];
624 GlyphHeightMap::mapped_type::iterator heightMapItem = oldHeightMap.find(iter->first);
625 glyphHeightMap[(FT_Pos)newInfo.height].insert(*heightMapItem);
626 oldHeightMap.erase(heightMapItem);
627 info.height = newInfo.height;
630 if (info.advance != newInfo.advance)
631 info.advance = newInfo.advance;
633 if (info.bearingX != newInfo.bearingX)
634 info.bearingX = newInfo.bearingX;
636 if (info.bearingY != newInfo.bearingY)
637 info.bearingY = newInfo.bearingY;
641 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot load glyph " << iter->first <<
" for character " << iter->second.codePoint <<
" in font '" <<
getResourceName() <<
"'.");
646 #endif // MYGUI_USE_FREETYPE_BYTECODE_BUG_FIX
654 if (mSpaceWidth != 0.0f)
656 texWidth += (int)ceil(mSpaceWidth) - (int)ceil(spaceGlyphInfo->width);
657 spaceGlyphInfo->width = mSpaceWidth;
658 spaceGlyphInfo->advance = mSpaceWidth;
662 if (mTabWidth == 0.0f)
663 mTabWidth = mDefaultTabWidth * spaceGlyphInfo->advance;
669 FT_UInt nextGlyphIndex = (FT_UInt)ftFace->num_glyphs;
671 float height = (
float)mDefaultHeight;
673 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(
FontCodeType::Tab), 0.0f, 0.0f, mTabWidth, 0.0f, 0.0f), glyphHeightMap);
674 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(
FontCodeType::Selected), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
675 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(
FontCodeType::SelectedBack), mSelectedWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
676 texWidth += createGlyph(nextGlyphIndex++, GlyphInfo(static_cast<Char>(
FontCodeType::Cursor), mCursorWidth, height, 0.0f, 0.0f, 0.0f), glyphHeightMap);
686 texWidth += createFaceGlyph(0, static_cast<Char>(
FontCodeType::NotDefined), fontAscent, ftFace, ftLoadFlags, glyphHeightMap);
689 mSubstituteGlyphInfo = &mGlyphMap.find(mCharMap.find(mSubstituteCodePoint)->second)->second;
693 double averageGlyphHeight = 0.0;
695 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
696 averageGlyphHeight += j->first * j->second.size();
698 averageGlyphHeight /= mGlyphMap.size();
711 while (texWidth > texHeight)
724 if (texHeight > texWidth * 2)
727 int texX = 0, texY = 0;
729 for (GlyphHeightMap::const_iterator j = glyphHeightMap.begin(); j != glyphHeightMap.end(); ++j)
731 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
733 GlyphInfo& info = *i->second;
735 int glyphWidth = (int)ceil(info.width);
736 int glyphHeight = (int)ceil(info.height);
738 autoWrapGlyphPos(glyphWidth, texWidth, glyphHeight, texX, texY);
741 texX += mGlyphSpacing + glyphWidth;
747 while (texHeight > texWidth * 2);
759 if (texBuffer !=
nullptr)
762 for (
uint8* dest = texBuffer, * endDest = dest + texWidth * texHeight * Pixel<LAMode>::getNumBytes(); dest != endDest; )
763 Pixel<LAMode, false, false>::set(dest, charMaskWhite, charMaskBlack);
765 renderGlyphs<LAMode, Antialias>(glyphHeightMap, ftLibrary, ftFace, ftLoadFlags, texBuffer, texWidth, texHeight);
769 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using texture size " << texWidth <<
" x " << texHeight <<
".");
770 MYGUI_LOG(Info,
"ResourceTrueTypeFont: Font '" <<
getResourceName() <<
"' using real height " << mDefaultHeight <<
" pixels.");
774 MYGUI_LOG(Error,
"ResourceTrueTypeFont: Error locking texture; pointer is nullptr.");
777 FT_Done_Face(ftFace);
778 FT_Done_FreeType(ftLibrary);
780 delete [] fontBuffer;
783 FT_Face ResourceTrueTypeFont::loadFace(
const FT_Library& _ftLibrary,
uint8*& _fontBuffer)
785 FT_Face result =
nullptr;
790 if (datastream ==
nullptr)
793 size_t fontBufferSize = datastream->
size();
794 _fontBuffer =
new uint8[fontBufferSize];
795 datastream->read(_fontBuffer, fontBufferSize);
798 datastream =
nullptr;
801 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, -1, &result) != 0)
804 FT_Long numFaces = result->num_faces;
805 FT_Long faceIndex = 0;
808 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
811 if (result->face_flags & FT_FACE_FLAG_SCALABLE)
815 FT_F26Dot6 ftSize = (FT_F26Dot6)(mSize * (1 << 6));
817 if (FT_Set_Char_Size(result, ftSize, 0, mResolution, mResolution) != 0)
821 if (mCharMap.empty())
827 FT_WinFNT_HeaderRec fnt;
831 std::map<float, FT_Long> faceSizes;
835 if (FT_Get_WinFNT_Header(result, &fnt) != 0)
838 faceSizes.insert(std::make_pair((
float)fnt.nominal_point_size * fnt.vertical_resolution / mResolution, faceIndex));
840 FT_Done_Face(result);
842 if (++faceIndex < numFaces)
843 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
846 while (faceIndex < numFaces);
848 std::map<float, FT_Long>::const_iterator iter = faceSizes.lower_bound(mSize);
850 faceIndex = (iter != faceSizes.end()) ? iter->second : faceSizes.rbegin()->second;
852 if (FT_New_Memory_Face(_ftLibrary, _fontBuffer, (FT_Long)fontBufferSize, faceIndex, &result) != 0)
857 if (FT_Select_Size(result, 0) != 0)
862 if (mCharMap.empty())
869 if (fnt.charset == FT_WinFNT_ID_CP1252)
881 if (fnt.charset == FT_WinFNT_ID_CP1252)
891 void ResourceTrueTypeFont::autoWrapGlyphPos(
int _glyphWidth,
int _texWidth,
int _lineHeight,
int& _texX,
int& _texY)
893 if (_glyphWidth > 0 && _texX + mGlyphSpacing + _glyphWidth > _texWidth)
896 _texY += mGlyphSpacing + _lineHeight;
900 GlyphInfo ResourceTrueTypeFont::createFaceGlyphInfo(
Char _codePoint,
int _fontAscent, FT_GlyphSlot _glyph)
902 float bearingX = _glyph->metrics.horiBearingX / 64.0f;
910 std::max((
float)_glyph->bitmap.width, _glyph->metrics.width / 64.0f),
911 std::max((
float)_glyph->bitmap.rows, _glyph->metrics.height / 64.0f),
912 (_glyph->advance.x / 64.0f) - bearingX,
914 floor(_fontAscent - (_glyph->metrics.horiBearingY / 64.0f) - mOffsetHeight));
917 int ResourceTrueTypeFont::createGlyph(FT_UInt _glyphIndex,
const GlyphInfo& _glyphInfo, GlyphHeightMap& _glyphHeightMap)
919 int width = (int)ceil(_glyphInfo.width);
920 int height = (int)ceil(_glyphInfo.height);
922 mCharMap[_glyphInfo.codePoint] = _glyphIndex;
923 GlyphInfo& info = mGlyphMap.insert(GlyphMap::value_type(_glyphIndex, _glyphInfo)).first->second;
924 _glyphHeightMap[(FT_Pos)height].insert(std::make_pair(_glyphIndex, &info));
926 return (width > 0) ? mGlyphSpacing + width : 0;
929 int ResourceTrueTypeFont::createFaceGlyph(FT_UInt _glyphIndex,
Char _codePoint,
int _fontAscent,
const FT_Face& _ftFace, FT_Int32 _ftLoadFlags, GlyphHeightMap& _glyphHeightMap)
931 if (mGlyphMap.find(_glyphIndex) == mGlyphMap.end())
933 if (FT_Load_Glyph(_ftFace, _glyphIndex, _ftLoadFlags) == 0)
934 return createGlyph(_glyphIndex, createFaceGlyphInfo(_codePoint, _fontAscent, _ftFace->glyph), _glyphHeightMap);
936 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot load glyph " << _glyphIndex <<
" for character " << _codePoint <<
" in font '" <<
getResourceName() <<
"'.");
940 mCharMap[_codePoint] = _glyphIndex;
946 template<
bool LAMode,
bool Antialias>
947 void ResourceTrueTypeFont::renderGlyphs(
const GlyphHeightMap& _glyphHeightMap,
const FT_Library& _ftLibrary,
const FT_Face& _ftFace, FT_Int32 _ftLoadFlags,
uint8* _texBuffer,
int _texWidth,
int _texHeight)
950 FT_Bitmap_New(&ftBitmap);
952 int texX = 0, texY = 0;
954 for (GlyphHeightMap::const_iterator j = _glyphHeightMap.begin(); j != _glyphHeightMap.end(); ++j)
956 for (GlyphHeightMap::mapped_type::const_iterator i = j->second.begin(); i != j->second.end(); ++i)
958 GlyphInfo& info = *i->second;
960 switch (info.codePoint)
965 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
970 glyphInfo->width = 0.0f;
971 glyphInfo->uvRect.right = glyphInfo->uvRect.left;
977 renderGlyph<LAMode, false, false>(info, charMaskWhite, charMaskBlack, charMask.find(info.codePoint)->second, j->first, _texBuffer, _texWidth, _texHeight, texX, texY);
981 if (FT_Load_Glyph(_ftFace, i->first, _ftLoadFlags | FT_LOAD_RENDER) == 0)
983 if (_ftFace->glyph->bitmap.buffer !=
nullptr)
985 uint8* glyphBuffer =
nullptr;
987 switch (_ftFace->glyph->bitmap.pixel_mode)
989 case FT_PIXEL_MODE_GRAY:
990 glyphBuffer = _ftFace->glyph->bitmap.buffer;
993 case FT_PIXEL_MODE_MONO:
995 if (FT_Bitmap_Convert(_ftLibrary, &_ftFace->glyph->bitmap, &ftBitmap, 1) == 0)
998 for (
uint8* p = ftBitmap.buffer, * endP = p + ftBitmap.width * ftBitmap.rows; p != endP; ++p)
1001 glyphBuffer = ftBitmap.buffer;
1006 if (glyphBuffer !=
nullptr)
1007 renderGlyph<LAMode, true, Antialias>(info, charMaskWhite, charMaskWhite, charMaskWhite, j->first, _texBuffer, _texWidth, _texHeight, texX, texY, glyphBuffer);
1012 MYGUI_LOG(Warning,
"ResourceTrueTypeFont: Cannot render glyph " << i->first <<
" for character " << info.codePoint <<
" in font '" <<
getResourceName() <<
"'.");
1019 FT_Bitmap_Done(_ftLibrary, &ftBitmap);
1022 template<
bool LAMode,
bool UseBuffer,
bool Antialias>
1023 void ResourceTrueTypeFont::renderGlyph(GlyphInfo& _info,
uint8 _luminance0,
uint8 _luminance1,
uint8 _alpha,
int _lineHeight,
uint8* _texBuffer,
int _texWidth,
int _texHeight,
int& _texX,
int& _texY,
uint8* _glyphBuffer)
1025 int width = (int)ceil(_info.width);
1026 int height = (int)ceil(_info.height);
1028 autoWrapGlyphPos(width, _texWidth, _lineHeight, _texX, _texY);
1030 uint8* dest = _texBuffer + (_texY * _texWidth + _texX) * Pixel<LAMode>::getNumBytes();
1033 ptrdiff_t destNextRow = (_texWidth - width) * Pixel<LAMode>::getNumBytes();
1035 for (
int j = height; j > 0; --j)
1038 for (i = width; i > 1; i -= 2)
1040 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
1041 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance1, _alpha, _glyphBuffer);
1045 Pixel<LAMode, UseBuffer, Antialias>::set(dest, _luminance0, _alpha, _glyphBuffer);
1047 dest += destNextRow;
1051 _info.uvRect.left = (float)_texX / _texWidth;
1052 _info.uvRect.top = (float)_texY / _texHeight;
1053 _info.uvRect.right = (float)(_texX + _info.width) / _texWidth;
1054 _info.uvRect.bottom = (float)(_texY + _info.height) / _texHeight;
1057 _texX += mGlyphSpacing + width;
1072 mResolution = _value;
1077 if (_value ==
"use_native")
1078 mHinting = HintingUseNative;
1079 else if (_value ==
"force_auto")
1080 mHinting = HintingForceAuto;
1081 else if (_value ==
"disable_auto")
1082 mHinting = HintingDisableAuto;
1083 else if (_value ==
"disable_all")
1084 mHinting = HintingDisableAll;
1086 mHinting = HintingUseNative;
1091 mAntialias = _value;
1101 mOffsetHeight = _value;
1106 mSubstituteCodePoint = _value;
1111 mGlyphSpacing = _value;
1114 #endif // MYGUI_USE_FREETYPE