185 lines
6.6 KiB
C++
185 lines
6.6 KiB
C++
// 批次 2V0-g: the 40250 font path (CGraphicText → CGraphicFontTexture → CGraphicDib) over the GDI
|
|
// emulation in platform/Win32Gdi.cpp, and the code-page conversions CGraphicTextInstance runs text through.
|
|
//
|
|
// Needs a system Tahoma (macOS ships /System/Library/Fonts/Supplemental/Tahoma.ttf); exit 77 (ctest
|
|
// SKIP) without one, unless MT_ASSETS_STRICT=1.
|
|
#include "EterLib/StdAfx.h"
|
|
#include "EterLib/GrpText.h"
|
|
#include "EterLib/GrpTextInstance.h"
|
|
#include "EterLib/Util.h"
|
|
#include "EterLib/ResourceManager.h"
|
|
#include "../../src/platform/EterLib/UIRenderCommands.h"
|
|
#include "../../src/platform/UserInterface/UserInterface.h"
|
|
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
|
|
#include <unistd.h>
|
|
|
|
static int g_failures = 0;
|
|
#define CHECK(cond) \
|
|
do { \
|
|
if (!(cond)) { \
|
|
std::fprintf(stderr, "%s:%d: CHECK(%s)\n", __FILE__, __LINE__, #cond); \
|
|
++g_failures; \
|
|
} \
|
|
} while (0)
|
|
|
|
static void code_pages()
|
|
{
|
|
// CP949 "굴림" (B1BC B8B2) → U+AD74 U+B9BC, and back.
|
|
const char gulim[] = "\xb1\xbc\xb8\xb2";
|
|
WCHAR wide[8] = {};
|
|
CHECK(MultiByteToWideChar(949, 0, gulim, -1, nullptr, 0) == 3);
|
|
CHECK(MultiByteToWideChar(949, 0, gulim, -1, wide, 8) == 3);
|
|
CHECK(wide[0] == 0xAD74 && wide[1] == 0xB9BC && wide[2] == 0);
|
|
char narrow[8] = {};
|
|
CHECK(WideCharToMultiByte(949, 0, wide, -1, narrow, sizeof(narrow), nullptr, nullptr) == 5);
|
|
CHECK(std::string(narrow) == gulim);
|
|
|
|
// UTF-8 and the Windows size rules: a too-small buffer answers 0.
|
|
CHECK(MultiByteToWideChar(CP_UTF8, 0, "\xea\xb5\xb4", 3, wide, 8) == 1 && wide[0] == 0xAD74);
|
|
CHECK(MultiByteToWideChar(CP_UTF8, 0, "abc", 3, wide, 2) == 0);
|
|
// CP1252 0x80 is the euro sign.
|
|
CHECK(MultiByteToWideChar(1252, 0, "\x80", 1, wide, 8) == 1 && wide[0] == 0x20AC);
|
|
|
|
// 40250 Util.cpp face table.
|
|
CHECK(SetDefaultCodePage(949) && std::string(GetDefaultFontFace()) == "GulimChe");
|
|
CHECK(GetCharsetFromCodePage(949) == HANGUL_CHARSET);
|
|
CHECK(SetDefaultCodePage(1252) && std::string(GetDefaultFontFace()) == "Arial");
|
|
CHECK(GetDefaultCodePage() == 1252);
|
|
}
|
|
|
|
static int glyph_quads(float* min_x, float* max_x)
|
|
{
|
|
int count = 0;
|
|
*min_x = 1e9f;
|
|
*max_x = -1e9f;
|
|
for (const auto& command : UIRenderCommands())
|
|
{
|
|
if (command.kind != UIRenderCommand::Image || command.text.rfind("mem:", 0) != 0)
|
|
continue;
|
|
++count;
|
|
for (float x : command.qx)
|
|
{
|
|
*min_x = std::fmin(*min_x, x);
|
|
*max_x = std::fmax(*max_x, x);
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
const char* strict = std::getenv("MT_ASSETS_STRICT");
|
|
const bool is_strict = strict && std::string(strict) == "1";
|
|
|
|
PackSingletons();
|
|
CResourceManager resource_manager; // CResource::Release queues the resource here
|
|
code_pages();
|
|
|
|
if (access("/System/Library/Fonts/Supplemental/Tahoma.ttf", 0) != 0)
|
|
{
|
|
std::fprintf(stderr, "port_text_test: no system Tahoma\n");
|
|
return g_failures ? 1 : (is_strict ? 1 : 77);
|
|
}
|
|
|
|
// Not in any pack: CResource::Load falls through to OnLoad(0, NULL), as for every 40250 .fnt.
|
|
CGraphicText* text = new CGraphicText("Tahoma:12.fnt");
|
|
text->AddReference();
|
|
text->Load();
|
|
CHECK(!text->IsEmpty());
|
|
|
|
CGraphicTextInstance instance;
|
|
instance.SetTextPointer(text);
|
|
instance.SetValue("Hello");
|
|
instance.Update();
|
|
int width = 0, height = 0;
|
|
instance.GetTextSize(&width, &height);
|
|
// GDI lays a 12-pixel LOGFONT cell out as Tahoma's win ascent + descent at 10 ppem: 12 rows.
|
|
CHECK(height == 12);
|
|
CHECK(width > 20 && width < 40);
|
|
CHECK(instance.PixelPositionToCharacterPosition(0) == 0);
|
|
CHECK(instance.PixelPositionToCharacterPosition(width - 1) == 4);
|
|
CHECK(instance.PixelPositionToCharacterPosition(width + 5) == -1);
|
|
|
|
UIRenderSetSize(800, 600);
|
|
UIRenderBeginFrame();
|
|
instance.SetPosition(100.0f, 50.0f);
|
|
instance.Render();
|
|
float left = 0, right = 0;
|
|
CHECK(glyph_quads(&left, &right) == 5);
|
|
CHECK(std::fabs(left - 100.0f) <= 1.5f);
|
|
|
|
// Centred: the text straddles the position.
|
|
instance.SetHorizonalAlign(CGraphicTextInstance::HORIZONTAL_ALIGN_CENTER);
|
|
instance.Update();
|
|
UIRenderBeginFrame();
|
|
instance.Render();
|
|
CHECK(glyph_quads(&left, &right) == 5);
|
|
CHECK(left < 100.0f && right > 100.0f && std::fabs((left + right) * 0.5f - 100.0f) <= 2.0f);
|
|
|
|
// The glyph page has ink.
|
|
bool inked = false;
|
|
for (const auto& command : UIRenderCommands())
|
|
{
|
|
UIMemoryTexture page;
|
|
if (command.text.rfind("mem:", 0) == 0 && UIRenderMemoryTexture(command.text, &page))
|
|
for (std::uint32_t argb : page.argb)
|
|
inked |= (argb >> 24) != 0;
|
|
}
|
|
CHECK(inked);
|
|
|
|
// PORT: changing monitors must rebuild glyph rasters, not text layout. Existing
|
|
// CGraphicTextInstance objects retain pointers into the character-info map.
|
|
auto* font = text->GetFontTexturePointer();
|
|
auto* glyph = font->GetCharacterInfomation(1252, L'H');
|
|
const auto original_glyph = *glyph;
|
|
int page_width = 0, page_height = 0;
|
|
for (const auto& command : UIRenderCommands()) {
|
|
UIMemoryTexture page;
|
|
if (UIRenderMemoryTexture(command.text, &page)) {
|
|
page_width = page.width; page_height = page.height; break;
|
|
}
|
|
}
|
|
CHECK(page_width > 0);
|
|
for (int scale : {2, 3, 1, 2}) {
|
|
UISetFontOversample(scale);
|
|
CHECK(UIFontOversample() == scale);
|
|
CHECK(font->GetCharacterInfomation(1252, L'H') == glyph);
|
|
CHECK(glyph->width == original_glyph.width && glyph->height == original_glyph.height &&
|
|
glyph->advance == original_glyph.advance);
|
|
UIRenderBeginFrame();
|
|
instance.Render(); // use the already cached glyph pointers
|
|
CHECK(glyph_quads(&left, &right) == 5);
|
|
int new_width = 0, new_height = 0;
|
|
instance.GetTextSize(&new_width, &new_height);
|
|
CHECK(new_width == width && new_height == height);
|
|
bool sized = false, fine_coverage = false;
|
|
for (const auto& command : UIRenderCommands()) {
|
|
UIMemoryTexture page;
|
|
if (!UIRenderMemoryTexture(command.text, &page)) continue;
|
|
sized |= page.width == page_width * scale && page.height == page_height * scale;
|
|
for (auto argb : page.argb) {
|
|
const auto alpha = argb >> 24;
|
|
fine_coverage |= alpha > 0 && alpha < 255 && alpha % 17 != 0;
|
|
}
|
|
}
|
|
CHECK(sized);
|
|
if (scale > 1) CHECK(fine_coverage); // 8-bit alpha, not the old 4-bit quantisation
|
|
}
|
|
|
|
instance.Destroy();
|
|
text->Release();
|
|
|
|
if (g_failures)
|
|
{
|
|
std::fprintf(stderr, "%d check(s) failed\n", g_failures);
|
|
return 1;
|
|
}
|
|
std::printf("port_text_test: ok\n");
|
|
return 0;
|
|
}
|