Replace all core::unicode::ustring with std::u32string (#13775)

This commit is contained in:
Caleb Butler 2023-10-02 07:43:38 -04:00 committed by GitHub
parent 56965bc814
commit 3a4bf14c20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 59 deletions

@ -2,6 +2,7 @@
CGUITTFont FreeType class for Irrlicht CGUITTFont FreeType class for Irrlicht
Copyright (c) 2009-2010 John Norman Copyright (c) 2009-2010 John Norman
Copyright (c) 2016 Nathanaëlle Courant Copyright (c) 2016 Nathanaëlle Courant
Copyright (c) 2023 Caleb Butler
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -31,6 +32,8 @@
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream> #include <iostream>
#include <codecvt>
#include <locale>
#include "CGUITTFont.h" #include "CGUITTFont.h"
namespace irr namespace irr
@ -313,7 +316,7 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
// Log. // Log.
if (logger) if (logger)
logger->log(L"CGUITTFont", core::stringw(core::stringw(L"Creating new font: ") + core::ustring(filename).toWCHAR_s() + L" " + core::stringc(size) + L"pt " + (antialias ? L"+antialias " : L"-antialias ") + (transparency ? L"+transparency" : L"-transparency")).c_str(), irr::ELL_INFORMATION); logger->log(L"CGUITTFont", core::stringw(core::stringw(L"Creating new font: ") + core::stringw(filename) + L" " + core::stringc(size) + L"pt " + (antialias ? L"+antialias " : L"-antialias ") + (transparency ? L"+transparency" : L"-transparency")).c_str(), irr::ELL_INFORMATION);
// Grab the face. // Grab the face.
SGUITTFace* face = 0; SGUITTFace* face = 0;
@ -354,8 +357,7 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
} }
else else
{ {
core::ustring converter(filename); if (FT_New_Face(c_library, reinterpret_cast<const char*>(filename.c_str()), 0, &face->face))
if (FT_New_Face(c_library, reinterpret_cast<const char*>(converter.toUTF8_s().c_str()), 0, &face->face))
{ {
if (logger) logger->log(L"CGUITTFont", L"FT_New_Face failed.", irr::ELL_INFORMATION); if (logger) logger->log(L"CGUITTFont", L"FT_New_Face failed.", irr::ELL_INFORMATION);
@ -398,7 +400,7 @@ bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antia
// Cache the first 127 ascii characters. // Cache the first 127 ascii characters.
u32 old_size = batch_load_size; u32 old_size = batch_load_size;
batch_load_size = 127; batch_load_size = 127;
getGlyphIndexByChar((uchar32_t)0); getGlyphIndexByChar((char32_t)0);
batch_load_size = old_size; batch_load_size = old_size;
return true; return true;
@ -578,28 +580,28 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
} }
// Convert to a unicode string. // Convert to a unicode string.
core::ustring utext = text.getString(); std::u32string utext = convertWCharToU32String(text.c_str());
// Set up our render map. // Set up our render map.
std::map<u32, CGUITTGlyphPage*> Render_Map; std::map<u32, CGUITTGlyphPage*> Render_Map;
// Start parsing characters. // Start parsing characters.
u32 n; u32 n;
uchar32_t previousChar = 0; char32_t previousChar = 0;
core::ustring::const_iterator iter(utext); std::u32string::const_iterator iter = utext.begin();
while (!iter.atEnd()) while (iter != utext.end())
{ {
uchar32_t currentChar = *iter; char32_t currentChar = *iter;
n = getGlyphIndexByChar(currentChar); n = getGlyphIndexByChar(currentChar);
bool visible = (Invisible.findFirst(currentChar) == -1); bool visible = (Invisible.find_first_of(currentChar) == std::u32string::npos);
bool lineBreak=false; bool lineBreak=false;
if (currentChar == L'\r') // Mac or Windows breaks if (currentChar == L'\r') // Mac or Windows breaks
{ {
lineBreak = true; lineBreak = true;
if (*(iter + 1) == (uchar32_t)'\n') // Windows line breaks. if (*(iter + 1) == (char32_t)'\n') // Windows line breaks.
currentChar = *(++iter); currentChar = *(++iter);
} }
else if (currentChar == (uchar32_t)'\n') // Unix breaks else if (currentChar == (char32_t)'\n') // Unix breaks
{ {
lineBreak = true; lineBreak = true;
} }
@ -632,8 +634,9 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
CGUITTGlyphPage* const page = Glyph_Pages[glyph.glyph_page]; CGUITTGlyphPage* const page = Glyph_Pages[glyph.glyph_page];
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy)); page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
page->render_source_rects.push_back(glyph.source_rect); page->render_source_rects.push_back(glyph.source_rect);
if (iter.getPos() < colors.size()) const size_t iterPos = iter - utext.begin();
page->render_colors.push_back(colors[iter.getPos()]); if (iterPos < colors.size())
page->render_colors.push_back(colors[iterPos]);
else else
page->render_colors.push_back(video::SColor(255,255,255,255)); page->render_colors.push_back(video::SColor(255,255,255,255));
Render_Map[glyph.glyph_page] = page; Render_Map[glyph.glyph_page] = page;
@ -653,7 +656,7 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
offset.X += fallback->getKerningWidth(l1, &l2); offset.X += fallback->getKerningWidth(l1, &l2);
offset.Y += fallback->getKerningHeight(); offset.Y += fallback->getKerningHeight();
u32 current_color = iter.getPos(); const u32 current_color = iter - utext.begin();
fallback->draw(core::stringw(l1), fallback->draw(core::stringw(l1),
core::rect<s32>({offset.X-1, offset.Y-1}, position.LowerRightCorner), // ??? core::rect<s32>({offset.X-1, offset.Y-1}, position.LowerRightCorner), // ???
current_color < colors.size() ? colors[current_color] : video::SColor(255, 255, 255, 255), current_color < colors.size() ? colors[current_color] : video::SColor(255, 255, 255, 255),
@ -718,10 +721,10 @@ core::dimension2d<u32> CGUITTFont::getCharDimension(const wchar_t ch) const
core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const core::dimension2d<u32> CGUITTFont::getDimension(const wchar_t* text) const
{ {
return getDimension(core::ustring(text)); return getDimension(convertWCharToU32String(text));
} }
core::dimension2d<u32> CGUITTFont::getDimension(const core::ustring& text) const core::dimension2d<u32> CGUITTFont::getDimension(const std::u32string& text) const
{ {
// Get the maximum font height. Unfortunately, we have to do this hack as // Get the maximum font height. Unfortunately, we have to do this hack as
// Irrlicht will draw things wrong. In FreeType, the font size is the // Irrlicht will draw things wrong. In FreeType, the font size is the
@ -730,19 +733,19 @@ core::dimension2d<u32> CGUITTFont::getDimension(const core::ustring& text) const
// Irrlicht does not understand this concept when drawing fonts. Also, I // Irrlicht does not understand this concept when drawing fonts. Also, I
// add +1 to give it a 1 pixel blank border. This makes things like // add +1 to give it a 1 pixel blank border. This makes things like
// tooltips look nicer. // tooltips look nicer.
s32 test1 = getHeightFromCharacter((uchar32_t)'g') + 1; s32 test1 = getHeightFromCharacter((char32_t)'g') + 1;
s32 test2 = getHeightFromCharacter((uchar32_t)'j') + 1; s32 test2 = getHeightFromCharacter((char32_t)'j') + 1;
s32 test3 = getHeightFromCharacter((uchar32_t)'_') + 1; s32 test3 = getHeightFromCharacter((char32_t)'_') + 1;
s32 max_font_height = core::max_(test1, core::max_(test2, test3)); s32 max_font_height = core::max_(test1, core::max_(test2, test3));
core::dimension2d<u32> text_dimension(0, max_font_height); core::dimension2d<u32> text_dimension(0, max_font_height);
core::dimension2d<u32> line(0, max_font_height); core::dimension2d<u32> line(0, max_font_height);
uchar32_t previousChar = 0; char32_t previousChar = 0;
core::ustring::const_iterator iter = text.begin(); std::u32string::const_iterator iter = text.begin();
for (; !iter.atEnd(); ++iter) for (; iter != text.end(); ++iter)
{ {
uchar32_t p = *iter; char32_t p = *iter;
bool lineBreak = false; bool lineBreak = false;
if (p == '\r') // Mac or Windows line breaks. if (p == '\r') // Mac or Windows line breaks.
{ {
@ -784,10 +787,10 @@ core::dimension2d<u32> CGUITTFont::getDimension(const core::ustring& text) const
inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const inline u32 CGUITTFont::getWidthFromCharacter(wchar_t c) const
{ {
return getWidthFromCharacter((uchar32_t)c); return getWidthFromCharacter((char32_t)c);
} }
inline u32 CGUITTFont::getWidthFromCharacter(uchar32_t c) const inline u32 CGUITTFont::getWidthFromCharacter(char32_t c) const
{ {
// Set the size of the face. // Set the size of the face.
// This is because we cache faces and the face may have been set to a different size. // This is because we cache faces and the face may have been set to a different size.
@ -812,10 +815,10 @@ inline u32 CGUITTFont::getWidthFromCharacter(uchar32_t c) const
inline u32 CGUITTFont::getHeightFromCharacter(wchar_t c) const inline u32 CGUITTFont::getHeightFromCharacter(wchar_t c) const
{ {
return getHeightFromCharacter((uchar32_t)c); return getHeightFromCharacter((char32_t)c);
} }
inline u32 CGUITTFont::getHeightFromCharacter(uchar32_t c) const inline u32 CGUITTFont::getHeightFromCharacter(char32_t c) const
{ {
// Set the size of the face. // Set the size of the face.
// This is because we cache faces and the face may have been set to a different size. // This is because we cache faces and the face may have been set to a different size.
@ -841,10 +844,10 @@ inline u32 CGUITTFont::getHeightFromCharacter(uchar32_t c) const
u32 CGUITTFont::getGlyphIndexByChar(wchar_t c) const u32 CGUITTFont::getGlyphIndexByChar(wchar_t c) const
{ {
return getGlyphIndexByChar((uchar32_t)c); return getGlyphIndexByChar((char32_t)c);
} }
u32 CGUITTFont::getGlyphIndexByChar(uchar32_t c) const u32 CGUITTFont::getGlyphIndexByChar(char32_t c) const
{ {
// Get the glyph. // Get the glyph.
u32 glyph = FT_Get_Char_Index(tt_face, c); u32 glyph = FT_Get_Char_Index(tt_face, c);
@ -888,20 +891,20 @@ u32 CGUITTFont::getGlyphIndexByChar(uchar32_t c) const
s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
{ {
return getCharacterFromPos(core::ustring(text), pixel_x); return getCharacterFromPos(convertWCharToU32String(text), pixel_x);
} }
s32 CGUITTFont::getCharacterFromPos(const core::ustring& text, s32 pixel_x) const s32 CGUITTFont::getCharacterFromPos(const std::u32string& text, s32 pixel_x) const
{ {
s32 x = 0; s32 x = 0;
//s32 idx = 0; //s32 idx = 0;
u32 character = 0; u32 character = 0;
uchar32_t previousChar = 0; char32_t previousChar = 0;
core::ustring::const_iterator iter = text.begin(); std::u32string::const_iterator iter = text.begin();
while (!iter.atEnd()) while (iter != text.end())
{ {
uchar32_t c = *iter; char32_t c = *iter;
x += getWidthFromCharacter(c); x += getWidthFromCharacter(c);
// Kerning. // Kerning.
@ -936,10 +939,10 @@ s32 CGUITTFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previo
if (thisLetter == 0 || previousLetter == 0) if (thisLetter == 0 || previousLetter == 0)
return 0; return 0;
return getKerningWidth((uchar32_t)*thisLetter, (uchar32_t)*previousLetter); return getKerningWidth((char32_t)*thisLetter, (char32_t)*previousLetter);
} }
s32 CGUITTFont::getKerningWidth(const uchar32_t thisLetter, const uchar32_t previousLetter) const s32 CGUITTFont::getKerningWidth(const char32_t thisLetter, const char32_t previousLetter) const
{ {
// Return only the kerning width. // Return only the kerning width.
return getKerning(thisLetter, previousLetter).X; return getKerning(thisLetter, previousLetter).X;
@ -953,10 +956,10 @@ s32 CGUITTFont::getKerningHeight() const
core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const core::vector2di CGUITTFont::getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const
{ {
return getKerning((uchar32_t)thisLetter, (uchar32_t)previousLetter); return getKerning((char32_t)thisLetter, (char32_t)previousLetter);
} }
core::vector2di CGUITTFont::getKerning(const uchar32_t thisLetter, const uchar32_t previousLetter) const core::vector2di CGUITTFont::getKerning(const char32_t thisLetter, const char32_t previousLetter) const
{ {
if (tt_face == 0 || thisLetter == 0 || previousLetter == 0) if (tt_face == 0 || thisLetter == 0 || previousLetter == 0)
return core::vector2di(); return core::vector2di();
@ -1006,20 +1009,18 @@ core::vector2di CGUITTFont::getKerning(const uchar32_t thisLetter, const uchar32
void CGUITTFont::setInvisibleCharacters(const wchar_t *s) void CGUITTFont::setInvisibleCharacters(const wchar_t *s)
{ {
core::ustring us(s); Invisible = convertWCharToU32String(s);
Invisible = us;
} }
void CGUITTFont::setInvisibleCharacters(const core::ustring& s) video::IImage* CGUITTFont::createTextureFromChar(const char32_t& ch)
{ {
Invisible = s; // This character allows us to print something to the screen for unknown, unrecognizable, or
} // unrepresentable characters. See Unicode spec.
const char32_t UTF_REPLACEMENT_CHARACTER = 0xFFFD;
video::IImage* CGUITTFont::createTextureFromChar(const uchar32_t& ch)
{
u32 n = getGlyphIndexByChar(ch); u32 n = getGlyphIndexByChar(ch);
if (n == 0) if (n == 0)
n = getGlyphIndexByChar((uchar32_t) core::unicode::UTF_REPLACEMENT_CHARACTER); n = getGlyphIndexByChar(UTF_REPLACEMENT_CHARACTER);
const SGUITTGlyph& glyph = Glyphs[n-1]; const SGUITTGlyph& glyph = Glyphs[n-1];
CGUITTGlyphPage* page = Glyph_Pages[glyph.glyph_page]; CGUITTGlyphPage* page = Glyph_Pages[glyph.glyph_page];
@ -1246,5 +1247,27 @@ core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text
return container; return container;
} }
std::u32string CGUITTFont::convertWCharToU32String(const wchar_t* const charArray) const
{
static_assert(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4, "unexpected wchar size");
if (sizeof(wchar_t) == 4) // Systems where wchar_t is UTF-32
return std::u32string(reinterpret_cast<const char32_t*>(charArray));
// Systems where wchar_t is UTF-16:
// First, convert to UTF-8
std::u16string utf16String(reinterpret_cast<const char16_t*>(charArray));
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter1;
std::string utf8String = converter1.to_bytes(utf16String);
// Next, convert to UTF-32
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter2;
return converter2.from_bytes(utf8String);
// This is inefficient, but importantly it is _correct_, rather than a hand-rolled UTF-16 to
// UTF-32 converter which may or may not be correct.
}
} // end namespace gui } // end namespace gui
} // end namespace irr } // end namespace irr

@ -2,6 +2,7 @@
CGUITTFont FreeType class for Irrlicht CGUITTFont FreeType class for Irrlicht
Copyright (c) 2009-2010 John Norman Copyright (c) 2009-2010 John Norman
Copyright (c) 2016 Nathanaëlle Courant Copyright (c) 2016 Nathanaëlle Courant
Copyright (c) 2023 Caleb Butler
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any warranty. In no event will the authors be held liable for any
@ -35,7 +36,6 @@
#include <ft2build.h> #include <ft2build.h>
#include <vector> #include <vector>
#include <map> #include <map>
#include <irrUString.h>
#include "util/enriched_string.h" #include "util/enriched_string.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"
#include FT_FREETYPE_H #include FT_FREETYPE_H
@ -289,11 +289,9 @@ namespace gui
//! Returns the dimension of a text string. //! Returns the dimension of a text string.
virtual core::dimension2d<u32> getDimension(const wchar_t* text) const; virtual core::dimension2d<u32> getDimension(const wchar_t* text) const;
virtual core::dimension2d<u32> getDimension(const core::ustring& text) const;
//! Calculates the index of the character in the text which is on a specific position. //! Calculates the index of the character in the text which is on a specific position.
virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const; virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const;
virtual s32 getCharacterFromPos(const core::ustring& text, s32 pixel_x) const;
//! Sets global kerning width for the font. //! Sets global kerning width for the font.
virtual void setKerningWidth(s32 kerning); virtual void setKerningWidth(s32 kerning);
@ -303,14 +301,13 @@ namespace gui
//! Gets kerning values (distance between letters) for the font. If no parameters are provided, //! Gets kerning values (distance between letters) for the font. If no parameters are provided,
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const; virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const;
virtual s32 getKerningWidth(const uchar32_t thisLetter=0, const uchar32_t previousLetter=0) const; virtual s32 getKerningWidth(const char32_t thisLetter=0, const char32_t previousLetter=0) const;
//! Returns the distance between letters //! Returns the distance between letters
virtual s32 getKerningHeight() const; virtual s32 getKerningHeight() const;
//! Define which characters should not be drawn by the font. //! Define which characters should not be drawn by the font.
virtual void setInvisibleCharacters(const wchar_t *s); virtual void setInvisibleCharacters(const wchar_t *s);
virtual void setInvisibleCharacters(const core::ustring& s);
//! Get the last glyph page if there's still available slots. //! Get the last glyph page if there's still available slots.
//! If not, it will return zero. //! If not, it will return zero.
@ -330,7 +327,7 @@ namespace gui
//! Create corresponding character's software image copy from the font, //! Create corresponding character's software image copy from the font,
//! so you can use this data just like any ordinary video::IImage. //! so you can use this data just like any ordinary video::IImage.
//! \param ch The character you need //! \param ch The character you need
virtual video::IImage* createTextureFromChar(const uchar32_t& ch); virtual video::IImage* createTextureFromChar(const char32_t& ch);
//! This function is for debugging mostly. If the page doesn't exist it returns zero. //! This function is for debugging mostly. If the page doesn't exist it returns zero.
//! \param page_index Simply return the texture handle of a given page index. //! \param page_index Simply return the texture handle of a given page index.
@ -360,6 +357,14 @@ namespace gui
static scene::IMesh* shared_plane_ptr_; static scene::IMesh* shared_plane_ptr_;
static scene::SMesh shared_plane_; static scene::SMesh shared_plane_;
// Helper functions for the same-named public member functions above
// (Since std::u32string is nicer to work with than wchar_t *)
core::dimension2d<u32> getDimension(const std::u32string& text) const;
s32 getCharacterFromPos(const std::u32string& text, s32 pixel_x) const;
// Helper function for the above helper functions :P
std::u32string convertWCharToU32String(const wchar_t* const) const;
CGUITTFont(IGUIEnvironment *env); CGUITTFont(IGUIEnvironment *env);
bool load(const io::path& filename, const u32 size, const bool antialias, const bool transparency); bool load(const io::path& filename, const u32 size, const bool antialias, const bool transparency);
void reset_images(); void reset_images();
@ -374,13 +379,13 @@ namespace gui
else load_flags |= FT_LOAD_TARGET_NORMAL; else load_flags |= FT_LOAD_TARGET_NORMAL;
} }
u32 getWidthFromCharacter(wchar_t c) const; u32 getWidthFromCharacter(wchar_t c) const;
u32 getWidthFromCharacter(uchar32_t c) const; u32 getWidthFromCharacter(char32_t c) const;
u32 getHeightFromCharacter(wchar_t c) const; u32 getHeightFromCharacter(wchar_t c) const;
u32 getHeightFromCharacter(uchar32_t c) const; u32 getHeightFromCharacter(char32_t c) const;
u32 getGlyphIndexByChar(wchar_t c) const; u32 getGlyphIndexByChar(wchar_t c) const;
u32 getGlyphIndexByChar(uchar32_t c) const; u32 getGlyphIndexByChar(char32_t c) const;
core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const; core::vector2di getKerning(const wchar_t thisLetter, const wchar_t previousLetter) const;
core::vector2di getKerning(const uchar32_t thisLetter, const uchar32_t previousLetter) const; core::vector2di getKerning(const char32_t thisLetter, const char32_t previousLetter) const;
core::dimension2d<u32> getDimensionUntilEndOfLine(const wchar_t* p) const; core::dimension2d<u32> getDimensionUntilEndOfLine(const wchar_t* p) const;
void createSharedPlane(); void createSharedPlane();
@ -398,7 +403,7 @@ namespace gui
s32 GlobalKerningWidth; s32 GlobalKerningWidth;
s32 GlobalKerningHeight; s32 GlobalKerningHeight;
core::ustring Invisible; std::u32string Invisible;
u32 shadow_offset; u32 shadow_offset;
u32 shadow_alpha; u32 shadow_alpha;