mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-03 03:31:04 +03:00
Optimize native system font resolution. Fix duplicate macOS menu shortcuts and suppress popup hint.
Avoid enumerating every installed font during SystemFontResolver warmup. Use native platform matching for generic families and lazily resolve fallback fonts when a missing glyph is encountered. Cache generic and codepoint fallback results, preserve collection face indices, and validate native matches with FreeType. Improve CoreText, DirectWrite, and Fontconfig matching while retaining full enumeration for font-listing APIs. Add a Fontconfig override for testing the backend on macOS and extend resolver coverage for lazy matching, CJK fallback, and enumeration. Make pixel-exact subpixel rendering tests disable HiDPI so their framebuffer dimensions remain deterministic on Retina displays. Avoid executing native menu key equivalents twice when SDL also forwards the same key-down event through eepp's keybinding dispatcher. Preserve native menu item activation for mouse clicks. Hide the "Hold Shift to keep menu open" hint while the native macOS menu bar is enabled.
This commit is contained in:
@@ -110,11 +110,11 @@ class EE_API SystemFontResolver {
|
|||||||
|
|
||||||
FontDesc getFallbackForCodepoint( Uint32 codepoint, FontWeight weight, bool italic );
|
FontDesc getFallbackForCodepoint( Uint32 codepoint, FontWeight weight, bool italic );
|
||||||
|
|
||||||
/** Populate and cache the system font database without copying the resulting font list.
|
/** Pre-resolve the native fonts needed by normal rendering. Full system-font enumeration
|
||||||
* Safe to call from a worker thread after enabling the resolver. */
|
* remains lazy until enumerate() or enumerateFamily() is called. */
|
||||||
void warmUp() const;
|
void warmUp() const;
|
||||||
|
|
||||||
bool fontContainsCodepoint( const std::string& path, Uint32 codepoint );
|
bool fontContainsCodepoint( const std::string& path, Uint32 codepoint, Uint32 faceIndex = 0 );
|
||||||
|
|
||||||
void invalidateCache();
|
void invalidateCache();
|
||||||
|
|
||||||
@@ -122,6 +122,10 @@ class EE_API SystemFontResolver {
|
|||||||
|
|
||||||
bool isLoading() const { return mFontListLoading; }
|
bool isLoading() const { return mFontListLoading; }
|
||||||
|
|
||||||
|
bool isFontListPopulated() const {
|
||||||
|
return mFontListPopulated.load( std::memory_order_acquire );
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<FontDesc> enumerate();
|
std::vector<FontDesc> enumerate();
|
||||||
|
|
||||||
std::vector<FontDesc> enumerateFamily( const std::string& family );
|
std::vector<FontDesc> enumerateFamily( const std::string& family );
|
||||||
@@ -148,6 +152,12 @@ class EE_API SystemFontResolver {
|
|||||||
|
|
||||||
void populateGenericFallbacks() const;
|
void populateGenericFallbacks() const;
|
||||||
|
|
||||||
|
FontDesc matchFont( const FontQuery& query ) const;
|
||||||
|
|
||||||
|
FontDesc matchGenericFont( GenericFamily generic, FontWeight weight, bool italic ) const;
|
||||||
|
|
||||||
|
FontDesc resolveGenericCached( GenericFamily generic, FontWeight weight, bool italic ) const;
|
||||||
|
|
||||||
FontDesc matchFallbackForCodepoint( Uint32 codepoint, FontWeight weight, bool italic ) const;
|
FontDesc matchFallbackForCodepoint( Uint32 codepoint, FontWeight weight, bool italic ) const;
|
||||||
|
|
||||||
static int scoreMatch( const FontQuery& query, const FontDesc& candidate );
|
static int scoreMatch( const FontQuery& query, const FontDesc& candidate );
|
||||||
@@ -164,7 +174,7 @@ class EE_API SystemFontResolver {
|
|||||||
|
|
||||||
mutable UnorderedMap<Uint32, FontDesc> mGenericCache;
|
mutable UnorderedMap<Uint32, FontDesc> mGenericCache;
|
||||||
|
|
||||||
mutable UnorderedMap<Uint32, std::string> mCodepointFallbackCache;
|
mutable UnorderedMap<Uint32, FontDesc> mCodepointFallbackCache;
|
||||||
|
|
||||||
struct GenericEntry {
|
struct GenericEntry {
|
||||||
GenericFamily generic;
|
GenericFamily generic;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -495,6 +495,13 @@ struct NativeMenuSource {
|
|||||||
|
|
||||||
- (void)menuItemActivated:(NSMenuItem*)sender {
|
- (void)menuItemActivated:(NSMenuItem*)sender {
|
||||||
eeASSERT( [NSThread isMainThread] );
|
eeASSERT( [NSThread isMainThread] );
|
||||||
|
// Shortcut text on UIMenuItem is presentation-only; applications register the actual shortcut
|
||||||
|
// with their KeyBindings target. AppKit also invokes this action for native key equivalents,
|
||||||
|
// while SDL still forwards the same key-down event to eepp. Let the normal keybinding dispatch
|
||||||
|
// own keyboard activation so commands are not executed twice, while preserving menu clicks.
|
||||||
|
NSEvent* event = [NSApp currentEvent];
|
||||||
|
if ( nil != event && event.type == NSEventTypeKeyDown )
|
||||||
|
return;
|
||||||
auto found = _itemMap.find( sender );
|
auto found = _itemMap.find( sender );
|
||||||
if ( found != _itemMap.end() && nullptr != found->second )
|
if ( found != _itemMap.end() && nullptr != found->second )
|
||||||
found->second->activate();
|
found->second->activate();
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ UTEST( FontRendering, glyphAdvanceDoesNotCreateTexturePages ) {
|
|||||||
UTEST( FontRendering, subpixelCoverageCompositesPerChannel ) {
|
UTEST( FontRendering, subpixelCoverageCompositesPerChannel ) {
|
||||||
UIApplication app(
|
UIApplication app(
|
||||||
WindowSettings( 360, 220, "eepp - Subpixel Text Test", WindowStyle::Default,
|
WindowSettings( 360, 220, "eepp - Subpixel Text Test", WindowStyle::Default,
|
||||||
WindowBackend::Default, 32 ),
|
WindowBackend::Default, 32, std::string(), 1, EE_SCREEN_KEYBOARD_ENABLED,
|
||||||
|
true ),
|
||||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||||
ResourceScope& scope = *app.getUI()->getResourceScope();
|
ResourceScope& scope = *app.getUI()->getResourceScope();
|
||||||
FontTrueTypePtr font = FontTrueType::New( "SubpixelText-Regular", scope );
|
FontTrueTypePtr font = FontTrueType::New( "SubpixelText-Regular", scope );
|
||||||
@@ -228,7 +229,8 @@ UTEST( FontRendering, subpixelCoverageAllRenderers ) {
|
|||||||
UTEST( FontRendering, scaledSubpixelGlyphAtlas ) {
|
UTEST( FontRendering, scaledSubpixelGlyphAtlas ) {
|
||||||
UIApplication app(
|
UIApplication app(
|
||||||
WindowSettings( 256, 64, "eepp - Scaled Subpixel Glyph Atlas", VisualTestWindowStyle,
|
WindowSettings( 256, 64, "eepp - Scaled Subpixel Glyph Atlas", VisualTestWindowStyle,
|
||||||
WindowBackend::Default, 32 ),
|
WindowBackend::Default, 32, std::string(), 1, EE_SCREEN_KEYBOARD_ENABLED,
|
||||||
|
true ),
|
||||||
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) );
|
||||||
ResourceScope& scope = *app.getUI()->getResourceScope();
|
ResourceScope& scope = *app.getUI()->getResourceScope();
|
||||||
FontTrueTypePtr font = FontTrueType::New( "ScaledSubpixelNonicons", scope );
|
FontTrueTypePtr font = FontTrueType::New( "ScaledSubpixelNonicons", scope );
|
||||||
|
|||||||
@@ -70,9 +70,13 @@ UTEST( SystemFontResolver, workerWarmUp ) {
|
|||||||
warmUpThread.wait();
|
warmUpThread.wait();
|
||||||
|
|
||||||
EXPECT_FALSE( resolver->isLoading() );
|
EXPECT_FALSE( resolver->isLoading() );
|
||||||
#if EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_BSD || \
|
#if EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
|
||||||
EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
|
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_LINUX || \
|
||||||
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_HAIKU
|
EE_PLATFORM == EE_PLATFORM_BSD || EE_PLATFORM == EE_PLATFORM_HAIKU
|
||||||
|
EXPECT_FALSE( resolver->isFontListPopulated() );
|
||||||
|
EXPECT_FALSE( resolver->resolveGeneric( GenericFamily::SansSerif, FontWeight::Normal, false )
|
||||||
|
.path.empty() );
|
||||||
|
#elif EE_PLATFORM == EE_PLATFORM_ANDROID
|
||||||
EXPECT_FALSE( resolver->enumerate().empty() );
|
EXPECT_FALSE( resolver->enumerate().empty() );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -80,6 +84,40 @@ UTEST( SystemFontResolver, workerWarmUp ) {
|
|||||||
SystemFontResolver::destroySingleton();
|
SystemFontResolver::destroySingleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if EE_PLATFORM == EE_PLATFORM_WIN || EE_PLATFORM == EE_PLATFORM_MACOS || \
|
||||||
|
EE_PLATFORM == EE_PLATFORM_IOS || EE_PLATFORM == EE_PLATFORM_LINUX || \
|
||||||
|
EE_PLATFORM == EE_PLATFORM_BSD || EE_PLATFORM == EE_PLATFORM_HAIKU
|
||||||
|
UTEST( SystemFontResolver, nativeRenderingDoesNotEnumerate ) {
|
||||||
|
SystemFontResolver::setEnabled( true );
|
||||||
|
auto* resolver = SystemFontResolver::instance();
|
||||||
|
resolver->invalidateCache();
|
||||||
|
|
||||||
|
resolver->warmUp();
|
||||||
|
EXPECT_FALSE( resolver->isFontListPopulated() );
|
||||||
|
|
||||||
|
FontDesc sans = resolver->resolveGeneric( GenericFamily::SansSerif, FontWeight::Normal, false );
|
||||||
|
EXPECT_FALSE( sans.path.empty() );
|
||||||
|
FontQuery query;
|
||||||
|
query.family = sans.family;
|
||||||
|
EXPECT_FALSE( resolver->resolve( query ).path.empty() );
|
||||||
|
EXPECT_FALSE( resolver->resolveGeneric( GenericFamily::Monospace, FontWeight::Normal, false )
|
||||||
|
.path.empty() );
|
||||||
|
#if EE_PLATFORM == EE_PLATFORM_MACOS || EE_PLATFORM == EE_PLATFORM_IOS
|
||||||
|
EXPECT_FALSE(
|
||||||
|
resolver->getFallbackForCodepoint( 0x65E5, FontWeight::Normal, false ).path.empty() );
|
||||||
|
#else
|
||||||
|
resolver->getFallbackForCodepoint( 0x65E5, FontWeight::Normal, false );
|
||||||
|
#endif
|
||||||
|
EXPECT_FALSE( resolver->isFontListPopulated() );
|
||||||
|
|
||||||
|
EXPECT_FALSE( resolver->enumerate().empty() );
|
||||||
|
EXPECT_TRUE( resolver->isFontListPopulated() );
|
||||||
|
|
||||||
|
SystemFontResolver::setEnabled( false );
|
||||||
|
SystemFontResolver::destroySingleton();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
UTEST( SystemFontResolver, fallbackWaitsForConcurrentWarmUp ) {
|
UTEST( SystemFontResolver, fallbackWaitsForConcurrentWarmUp ) {
|
||||||
SystemFontResolver::setEnabled( true );
|
SystemFontResolver::setEnabled( true );
|
||||||
auto* resolver = SystemFontResolver::instance();
|
auto* resolver = SystemFontResolver::instance();
|
||||||
|
|||||||
Reference in New Issue
Block a user