blob: 26b4f74c5e1e446657b7cba5ad32b7ba833b7e8a [file] [log] [blame]
// { dg-do compile }
// { dg-require-effective-target c++17 }
// { dg-options "-O2 -Wall" }
#include <stdint.h>
#include <optional>
#include <string_view>
using utf8 = char;
enum
{
FONT_SIZE_TINY = 2,
FONT_SIZE_SMALL = 0,
FONT_SIZE_MEDIUM = 1,
FONT_SIZE_COUNT = 3
};
constexpr const uint16_t FONT_SPRITE_GLYPH_COUNT = 224;
enum class FontSpriteBase : int16_t
{
MEDIUM_EXTRA_DARK = -2,
MEDIUM_DARK = -1,
TINY = FONT_SIZE_TINY * FONT_SPRITE_GLYPH_COUNT,
SMALL = FONT_SIZE_SMALL * FONT_SPRITE_GLYPH_COUNT,
MEDIUM = FONT_SIZE_MEDIUM * FONT_SPRITE_GLYPH_COUNT,
};
struct TTFSurface;
class CodepointView
{
private:
std::string_view _str;
public:
class iterator
{
private:
std::string_view _str;
size_t _index;
public:
iterator(std::string_view str, size_t index)
: _str(str)
, _index(index)
{
}
bool operator==(const iterator& rhs) const
{
return _index == rhs._index;
}
bool operator!=(const iterator& rhs) const
{
return _index != rhs._index;
}
char32_t operator*() const
{
return GetNextCodepoint(&_str[_index], nullptr);
}
iterator& operator++()
{
return *this;
}
iterator operator++(int)
{
auto result = *this;
if (_index < _str.size())
{
const utf8* nextch;
GetNextCodepoint(&_str[_index], &nextch);
_index = nextch - _str.data();
}
return result;
}
size_t GetIndex() const
{
return _index;
}
static char32_t GetNextCodepoint(const char* ch, const char** next);
};
CodepointView(std::string_view str)
: _str(str)
{
}
iterator begin() const
{
return iterator(_str, 0);
}
iterator end() const
{
return iterator(_str, _str.size());
}
};
struct InternalTTFFont;
using TTF_Font = InternalTTFFont;
struct TTFFontDescriptor
{
const utf8* filename;
const utf8* font_name;
int32_t ptSize;
int32_t offset_x;
int32_t offset_y;
int32_t line_height;
int32_t hinting_threshold;
TTF_Font* font;
};
using codepoint_t = uint32_t;
#define abstract = 0
struct ITTF
{
virtual ~ITTF() = default;
virtual TTFFontDescriptor* ttf_get_font_from_sprite_base(FontSpriteBase spriteBase) abstract;
virtual TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, std::string_view text) abstract;
};
namespace OpenRCT2 {
struct IContext
{
virtual ~IContext() = default;
virtual ITTF* GetTTF() abstract;
};
}
static void ttf_draw_string_raw_ttf(OpenRCT2::IContext* context, std::string_view text)
{
TTFFontDescriptor* fontDesc = context->GetTTF()->ttf_get_font_from_sprite_base(FontSpriteBase::MEDIUM_EXTRA_DARK);
if (fontDesc->font == nullptr)
{
return;
}
TTFSurface* surface = context->GetTTF()->ttf_surface_cache_get_or_add(fontDesc->font, text);
if (surface == nullptr)
return;
}
namespace UnicodeChar
{
// Punctuation
constexpr char32_t leftguillemet = 0xAB;
constexpr char32_t rightguillemet = 0xBB;
constexpr char32_t german_quote_open = 0x201E;
constexpr char32_t quote_open = 0x201C;
constexpr char32_t quote_close = 0x201D;
// Dingbats
constexpr char32_t up = 0x25B2;
constexpr char32_t small_up = 0x25B4;
constexpr char32_t right = 0x25B6;
constexpr char32_t down = 0x25BC;
constexpr char32_t small_down = 0x25BE;
constexpr char32_t left = 0x25C0;
constexpr char32_t tick = 0x2713;
constexpr char32_t plus = 0x2795;
constexpr char32_t minus = 0x2796;
// Emoji
constexpr char32_t cross = 0x274C;
constexpr char32_t variation_selector = 0xFE0F;
constexpr char32_t eye = 0x1F441;
constexpr char32_t road = 0x1F6E3;
constexpr char32_t railway = 0x1F6E4;
}; // namespace UnicodeChar
static bool ShouldUseSpriteForCodepoint(char32_t codepoint)
{
switch (codepoint)
{
case UnicodeChar::up:
case UnicodeChar::down:
case UnicodeChar::leftguillemet:
case UnicodeChar::tick:
case UnicodeChar::cross:
case UnicodeChar::right:
case UnicodeChar::rightguillemet:
case UnicodeChar::small_up:
case UnicodeChar::small_down:
case UnicodeChar::left:
case UnicodeChar::quote_open:
case UnicodeChar::quote_close:
case UnicodeChar::german_quote_open:
case UnicodeChar::plus:
case UnicodeChar::minus:
case UnicodeChar::variation_selector:
case UnicodeChar::eye:
case UnicodeChar::road:
case UnicodeChar::railway:
return true;
default:
return false;
}
}
void ttf_process_string_literal(OpenRCT2::IContext* context, std::string_view text)
{
CodepointView codepoints(text);
std::optional<size_t> ttfRunIndex;
for (auto it = codepoints.begin(); it != codepoints.end(); it++)
{
auto codepoint = *it;
if (ShouldUseSpriteForCodepoint(codepoint))
{
if (ttfRunIndex.has_value())
{
// Draw the TTF run
auto len = it.GetIndex() - ttfRunIndex.value(); // { dg-bogus "may be used uninitialized" }
ttf_draw_string_raw_ttf(context, text.substr(ttfRunIndex.value(), len));
ttfRunIndex = std::nullopt;
}
// Draw the sprite font glyph
}
else
{
if (!ttfRunIndex.has_value())
{
ttfRunIndex = it.GetIndex();
}
}
}
}