diff --git a/Headers/Font.h b/Headers/Fonts.h similarity index 100% rename from Headers/Font.h rename to Headers/Fonts.h diff --git a/Makefile b/Makefile index e8a9450..4f79052 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = Bunny BUNDLE_NAME = BunnyResources -Bunny_FILES = $(shell find Sources -name "*.x" && find Sources -name "*.m") +Bunny_FILES = $(wildcard Sources/*.x Sources/*.m Sources/**/*.x Sources/**/*.m) Bunny_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers -Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics +Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics CoreText CoreFoundation BunnyResources_INSTALL_PATH = "/Library/Application\ Support/" BunnyResources_RESOURCE_DIRS = Resources diff --git a/Sources/Font.x b/Sources/Fonts.x similarity index 59% rename from Sources/Font.x rename to Sources/Fonts.x index 35e71ec..e3ae4ee 100644 --- a/Sources/Font.x +++ b/Sources/Fonts.x @@ -1,8 +1,9 @@ -#import "Font.h" +#import "Fonts.h" #import "Utils.h" #import "Logger.h" #import #import +#import NSMutableDictionary *fontMap; @@ -11,7 +12,11 @@ NSMutableDictionary *fontMap; + (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size { NSString *replacementName = fontMap[name]; if (replacementName) { - return %orig(replacementName, size); + UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; + UIFontDescriptor *fallbackDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorNameAttribute: @[name]}]; + UIFontDescriptor *finalDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute: @[fallbackDescriptor]}]; + + return [UIFont fontWithDescriptor:finalDescriptor size:size]; } return %orig; } @@ -27,13 +32,39 @@ NSMutableDictionary *fontMap; return %orig; } ++ (UIFont *)systemFontOfSize:(CGFloat)size { + NSString *replacementName = fontMap[@"systemFont"]; + if (replacementName) { + return [UIFont fontWithName:replacementName size:size]; + } + return %orig; +} + ++ (UIFont *)preferredFontForTextStyle:(UIFontTextStyle)style { + NSString *replacementName = fontMap[@"systemFont"]; + if (replacementName) { + return [UIFont fontWithName:replacementName size:[UIFont systemFontSize]]; + } + return %orig; +} + %end void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) { + BunnyLog(@"patchFonts called with fonts: %@ and def name: %@", mainFonts, fontDefName); + if (!fontMap) { + BunnyLog(@"Creating new fontMap"); fontMap = [NSMutableDictionary dictionary]; } + NSString *fontJson = [NSString stringWithContentsOfURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fonts.json"] + encoding:NSUTF8StringEncoding + error:nil]; + if (fontJson) { + BunnyLog(@"Found existing fonts.json: %@", fontJson); + } + for (NSString *fontName in mainFonts) { NSString *url = mainFonts[fontName]; BunnyLog(@"Replacing font %@ with URL: %@", fontName, url); @@ -75,16 +106,31 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD if (font) { CFStringRef postScriptName = CGFontCopyPostScriptName(font); + CTFontRef existingFont = CTFontCreateWithName(postScriptName, 0, NULL); + if (existingFont) { + CFErrorRef unregisterError = NULL; + if (!CTFontManagerUnregisterGraphicsFont(font, &unregisterError)) { + BunnyLog(@"Failed to deregister font %@: %@", (__bridge NSString *)postScriptName, + unregisterError ? (__bridge NSString *)CFErrorCopyDescription(unregisterError) : @"Unknown error"); + if (unregisterError) CFRelease(unregisterError); + } + CFRelease(existingFont); + } + CFErrorRef error = NULL; if (CTFontManagerRegisterGraphicsFont(font, &error)) { fontMap[fontName] = (__bridge NSString *)postScriptName; BunnyLog(@"Successfully registered font %@ to %@", fontName, (__bridge NSString *)postScriptName); + + NSError *jsonError; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:fontMap options:0 error:&jsonError]; + if (!jsonError) { + [jsonData writeToURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fontMap.json"] atomically:YES]; + } } else { NSString *errorDesc = error ? (__bridge NSString *)CFErrorCopyDescription(error) : @"Unknown error"; BunnyLog(@"Failed to register font %@: %@", fontName, errorDesc); - if (error) { - CFRelease(error); - } + if (error) CFRelease(error); } CFRelease(postScriptName); @@ -93,4 +139,12 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD CGDataProviderRelease(provider); } } +} + +%ctor { + @autoreleasepool { + fontMap = [NSMutableDictionary dictionary]; + BunnyLog(@"Font hooks initialized"); + %init; + } } \ No newline at end of file diff --git a/Sources/Tweak.x b/Sources/Tweak.x index 36ef121..26f995f 100644 --- a/Sources/Tweak.x +++ b/Sources/Tweak.x @@ -3,7 +3,7 @@ #import "Utils.h" #import "Logger.h" #import "Theme.h" -#import "Font.h" +#import "Fonts.h" #import "LoaderConfig.h" static NSURL *source; @@ -109,6 +109,16 @@ static LoaderConfig *loaderConfig; %orig([jsCode dataUsingEncoding:NSUTF8StringEncoding], source, async); } + NSData *fontData = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"fonts.json"]]; + if (fontData) { + NSError *jsonError; + NSDictionary *fontDict = [NSJSONSerialization JSONObjectWithData:fontData options:0 error:&jsonError]; + if (!jsonError && fontDict[@"main"]) { + BunnyLog(@"Found font configuration, applying..."); + patchFonts(fontDict[@"main"], fontDict[@"name"]); + } + } + if (bundle) { BunnyLog(@"Executing JS bundle"); %orig(bundle, source, async);