diff --git a/Headers/Additions/GNUstepGUI/GSFontAssetDownloader.h b/Headers/Additions/GNUstepGUI/GSFontAssetDownloader.h
new file mode 100644
index 000000000..d60b370b6
--- /dev/null
+++ b/Headers/Additions/GNUstepGUI/GSFontAssetDownloader.h
@@ -0,0 +1,287 @@
+/* Definition of class GSFontAssetDownloader
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ By: Gregory John Casamento
+ Date: September 5, 2024
+
+ This file is part of the GNUstep Library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110 USA.
+*/
+
+#ifndef _GSFontAssetDownloader_h_GNUSTEP_GUI_INCLUDE
+#define _GSFontAssetDownloader_h_GNUSTEP_GUI_INCLUDE
+#import
+
+#import
+#import
+
+@class NSFontDescriptor;
+@class NSURL;
+@class NSString;
+@class NSPanel;
+@class NSProgressIndicator;
+@class NSTextField;
+@class NSButton;
+
+#if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST)
+
+/**
+ * GSFontAssetDownloader provides a pluggable mechanism for downloading
+ * and installing font assets from various sources. This class can be
+ * subclassed to implement custom font downloading strategies, such as
+ * downloading from different font services, using authentication, or
+ * implementing custom validation and installation procedures.
+ *
+ * The default implementation supports downloading fonts from HTTP/HTTPS
+ * URLs and local file URLs, with basic validation and cross-platform
+ * installation to standard font directories.
+ *
+ * Subclasses can override individual methods to customize specific
+ * aspects of the download and installation process while reusing
+ * other parts of the default implementation.
+ *
+ * CLASS REPLACEMENT SYSTEM:
+ *
+ * GSFontAssetDownloader supports a class replacement system that allows
+ * applications to register a custom downloader class to be used globally.
+ * This enables complete customization of font downloading behavior without
+ * needing to modify every NSFontAssetRequest instance.
+ *
+ * Example usage:
+ *
+ * // Define a custom downloader class
+ * @interface MyCustomFontDownloader : GSFontAssetDownloader
+ * @end
+ *
+ * @implementation MyCustomFontDownloader
+ * - (NSURL *) fontURLForDescriptor: (NSFontDescriptor *)descriptor {
+ * // Custom URL resolution logic
+ * return [NSURL URLWithString: @"https://my-font-service.com/..."];
+ * }
+ * @end
+ *
+ * // Register the custom class globally
+ * [GSFontAssetDownloader setDefaultDownloaderClass: [MyCustomFontDownloader class]];
+ *
+ * // Or through NSFontAssetRequest
+ * [NSFontAssetRequest setDefaultDownloaderClass: [MyCustomFontDownloader class]];
+ *
+ * // All new font asset requests will now use the custom downloader
+ * NSFontAssetRequest *request = [[NSFontAssetRequest alloc]
+ * initWithFontDescriptors: descriptors options: 0];
+ *
+ * PROGRESS PANEL USAGE:
+ *
+ * To show a progress panel during font download, use the NSFontAssetRequestOptionUsesStandardUI option:
+ *
+ * NSFontDescriptor *descriptor = [NSFontDescriptor fontDescriptorWithName: @"Inconsolata" size: 12];
+ * GSFontAssetDownloader *downloader = [GSFontAssetDownloader downloaderWithOptions: NSFontAssetRequestOptionUsesStandardUI];
+ * NSError *error = nil;
+ * BOOL success = [downloader downloadAndInstallFontWithDescriptor: descriptor error: &error];
+ *
+ * The progress panel will automatically appear with:
+ * - A progress bar showing download/installation progress
+ * - Status messages describing the current operation
+ * - A cancel button (posts GSFontAssetDownloadCancelled notification when pressed)
+ */
+GS_EXPORT_CLASS
+@interface GSFontAssetDownloader : NSObject
+{
+ NSUInteger _options;
+ NSPanel *_progressPanel;
+ NSProgressIndicator *_progressIndicator;
+ NSTextField *_statusLabel;
+ NSButton *_cancelButton;
+}
+
+/**
+ * Registers a custom downloader class to be used instead of the default
+ * GSFontAssetDownloader class. The registered class must be a subclass
+ * of GSFontAssetDownloader. Pass nil to restore the default behavior.
+ */
++ (void) setDefaultDownloaderClass: (Class)downloaderClass;
+
+/**
+ * Returns the currently registered downloader class, or GSFontAssetDownloader
+ * if no custom class has been registered.
+ */
++ (Class) defaultDownloaderClass;
+
+/**
+ * Creates a new font asset downloader instance using the currently
+ * registered downloader class. This is the preferred method for creating
+ * downloader instances as it respects any custom downloader class that
+ * has been registered.
+ */
++ (instancetype) downloaderWithOptions: (NSUInteger)options;
+
+/**
+ * Creates a new font asset downloader with the specified options.
+ * The options parameter contains flags that control the download
+ * and installation behavior, such as whether to use standard UI
+ * or install to user vs system directories.
+ */
+- (instancetype) initWithOptions: (NSUInteger)options;
+
+/**
+ * Downloads and installs a font from the specified descriptor.
+ * This is the main entry point for font downloading. The method
+ * orchestrates the complete process: URL resolution, download,
+ * validation, and installation. Returns YES if the font was
+ * successfully downloaded and installed, NO otherwise.
+ */
+- (BOOL) downloadAndInstallFontWithDescriptor: (NSFontDescriptor *)descriptor
+ error: (NSError **)error;
+
+/**
+ * Downloads and installs a font from the specified descriptor with a preferred format.
+ * This variant allows specifying the preferred font format (e.g., "woff2", "woff", "ttf")
+ * when downloading from CSS URLs. For direct font URLs, the format parameter is ignored.
+ * Returns YES if the font was successfully downloaded and installed, NO otherwise.
+ */
+- (BOOL) downloadAndInstallFontWithDescriptor: (NSFontDescriptor *)descriptor
+ preferredFormat: (NSString *)format
+ error: (NSError **)error;
+
+/**
+ * Resolves a font URL from a font descriptor.
+ * This method can be overridden to implement custom URL resolution
+ * strategies, such as querying different font services or using
+ * authentication tokens. The default implementation looks for a
+ * custom URL attribute or constructs URLs from font names.
+ */
+- (NSURL *) fontURLForDescriptor: (NSFontDescriptor *)descriptor;
+
+/**
+ * Downloads a font file from the specified URL.
+ * This method can be overridden to implement custom download
+ * strategies, such as using authentication, custom headers, or
+ * progress callbacks. Returns the path to the downloaded temporary
+ * file, or nil on failure.
+ */
+- (NSString *) downloadFontFromURL: (NSURL *)fontURL
+ error: (NSError **)error;
+
+/**
+ * Downloads a font file from the specified URL with a given font name.
+ * This variant allows specifying the font name for better filename generation.
+ * The downloaded file will be saved with a name based on the font name and
+ * appropriate extension. Returns the path to the downloaded temporary file,
+ * or nil on failure.
+ */
+- (NSString *) downloadFontFromURL: (NSURL *)fontURL
+ fontName: (NSString *)fontName
+ error: (NSError **)error;
+
+/**
+ * Extracts font URLs from CSS content based on the specified format.
+ * This method parses CSS @font-face declarations and extracts URLs
+ * that match the given format (e.g., "woff2", "woff", "ttf").
+ * Returns an array of NSURL objects, or nil on error.
+ */
+- (NSArray *) extractFontURLsFromCSS: (NSString *)cssContent
+ withFormat: (NSString *)format
+ error: (NSError **)error;
+
+/**
+ * Downloads font data from a CSS URL that contains @font-face declarations.
+ * This method first downloads the CSS content, parses it to extract font URLs
+ * based on the specified format, and then downloads the first matching font.
+ * Returns the path to the downloaded temporary file, or nil on failure.
+ */
+- (NSString *) downloadFontDataFromCSSURL: (NSURL *)cssURL
+ withFormat: (NSString *)format
+ error: (NSError **)error;
+
+/**
+ * Downloads font data from a CSS URL with a given font name.
+ * This variant allows specifying the font name for better filename generation.
+ * The downloaded file will be saved with a name based on the font name and
+ * appropriate extension. Returns the path to the downloaded temporary file,
+ * or nil on failure.
+ */
+- (NSString *) downloadFontDataFromCSSURL: (NSURL *)cssURL
+ withFormat: (NSString *)format
+ fontName: (NSString *)fontName
+ error: (NSError **)error;
+
+/**
+ * Validates a downloaded font file.
+ * This method can be overridden to implement custom validation
+ * logic, such as checking font metadata, licensing information,
+ * or performing security scans. The default implementation
+ * checks file existence, size, and format signatures.
+ */
+- (BOOL) validateFontFile: (NSString *)fontPath
+ error: (NSError **)error;
+
+/**
+ * Installs a font file to the appropriate system location.
+ * This method can be overridden to implement custom installation
+ * strategies, such as using system APIs, registering with font
+ * management services, or applying custom permissions. Returns
+ * YES if installation was successful, NO otherwise.
+ */
+- (BOOL) installFontAtPath: (NSString *)fontPath
+ error: (NSError **)error;
+
+/**
+ * Returns the system fonts directory for the current platform.
+ * This method can be overridden to customize the system font
+ * installation location or to support additional platforms.
+ */
+- (NSString *) systemFontsDirectory;
+
+/**
+ * Returns the user fonts directory for the current platform.
+ * This method can be overridden to customize the user font
+ * installation location or to support additional platforms.
+ */
+- (NSString *) userFontsDirectory;
+
+/**
+ * Returns the options that were specified when creating this downloader.
+ */
+- (NSUInteger) options;
+
+/**
+ * Shows a progress panel for font downloading when NSFontAssetRequestOptionUsesStandardUI is set.
+ * This method creates and displays a modal panel with a progress indicator and status text.
+ */
+- (void) showProgressPanelWithMessage: (NSString *)message;
+
+/**
+ * Updates the progress panel with current status and progress value.
+ * The progress parameter should be a value between 0.0 and 1.0.
+ */
+- (void) updateProgressPanel: (double)progress withMessage: (NSString *)message;
+
+/**
+ * Hides and releases the progress panel.
+ */
+- (void) hideProgressPanel;
+
+/**
+ * Action method called when the cancel button in the progress panel is pressed.
+ */
+- (void) cancelDownload: (id)sender;
+
+@end
+
+#endif /* GS_API_MACOSX */
+
+#endif /* _GSFontAssetDownloader_h_GNUSTEP_GUI_INCLUDE */
diff --git a/Headers/Additions/GNUstepGUI/GSFontInfo.h b/Headers/Additions/GNUstepGUI/GSFontInfo.h
index 2b0283a3f..a3dabf777 100644
--- a/Headers/Additions/GNUstepGUI/GSFontInfo.h
+++ b/Headers/Additions/GNUstepGUI/GSFontInfo.h
@@ -7,7 +7,7 @@
Author: Adam Fedor
Date: Mar 2000
-
+
This file is part of the GNUstep.
This library is free software; you can redistribute it and/or
@@ -22,8 +22,8 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
- If not, see or write to the
- Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
@@ -48,11 +48,18 @@ APPKIT_EXPORT_CLASS
+ (void) setDefaultClass: (Class)defaultClass;
+ (GSFontEnumerator*) sharedEnumerator;
+
+// Font enumeration and caching
- (void) enumerateFontsAndFamilies;
+- (void) refreshFontCache;
+
+// Querying available fonts
- (NSArray*) availableFonts;
- (NSArray*) availableFontFamilies;
- (NSArray*) availableMembersOfFontFamily: (NSString*)family;
- (NSArray*) availableFontDescriptors;
+
+// Font matching and searching
- (NSArray *) availableFontNamesMatchingFontDescriptor: (NSFontDescriptor *)descriptor;
- (NSArray *) matchingFontDescriptorsFor: (NSDictionary *)attributes;
- (NSArray *) matchingDescriptorsForFamily: (NSString *)family
@@ -60,6 +67,7 @@ APPKIT_EXPORT_CLASS
inclusion: (NSArray *)queryDescriptors
exculsion: (NSArray *)exclusionDescriptors;
+// Default system font names (called once, backends may override)
/* Note that these are only called once. NSFont will remember the returned
values. Backends may override these. */
- (NSString *) defaultSystemFontName;
@@ -97,7 +105,7 @@ APPKIT_EXPORT_CLASS
NSFontDescriptor *fontDescriptor;
}
-+ (GSFontInfo*) fontInfoForFontName: (NSString*)fontName
++ (GSFontInfo*) fontInfoForFontName: (NSString*)fontName
matrix: (const CGFloat*)fmatrix
screenFont: (BOOL)screenFont;
+ (void) setDefaultClass: (Class)defaultClass;
@@ -132,22 +140,22 @@ APPKIT_EXPORT_CLASS
- (NSSize) minimumAdvancement;
- (NSStringEncoding) mostCompatibleStringEncoding;
- (NSUInteger) numberOfGlyphs;
-- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
- forCharacter: (unichar)aChar
+- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
+ forCharacter: (unichar)aChar
struckOverRect: (NSRect)aRect;
- (NSPoint) positionOfGlyph: (NSGlyph)curGlyph
precededByGlyph: (NSGlyph)prevGlyph
isNominal: (BOOL*)nominal;
-- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
- struckOverGlyph: (NSGlyph)baseGlyph
+- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
+ struckOverGlyph: (NSGlyph)baseGlyph
metricsExist: (BOOL *)flag;
-- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
- struckOverRect: (NSRect)aRect
+- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
+ struckOverRect: (NSRect)aRect
metricsExist: (BOOL *)flag;
-- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
- withRelation: (NSGlyphRelation)relation
+- (NSPoint) positionOfGlyph: (NSGlyph)aGlyph
+ withRelation: (NSGlyphRelation)relation
toBaseGlyph: (NSGlyph)baseGlyph
- totalAdvancement: (NSSize *)offset
+ totalAdvancement: (NSSize *)offset
metricsExist: (BOOL *)flag;
- (NSFontTraitMask) traits;
- (CGFloat) underlinePosition;
diff --git a/Headers/AppKit/NSFontAssetRequest.h b/Headers/AppKit/NSFontAssetRequest.h
index 0dae5781f..44a430fbd 100644
--- a/Headers/AppKit/NSFontAssetRequest.h
+++ b/Headers/AppKit/NSFontAssetRequest.h
@@ -28,6 +28,7 @@
#import
#import
+#import
/**
* Block type for font asset download completion handling.
@@ -39,8 +40,8 @@
*/
DEFINE_BLOCK_TYPE(GSFontAssetCompletionHandler, BOOL, NSError*);
-@class NSProgress;
-// @protocol NSProgressReporting;
+@class NSFontDescriptor;
+@class GSFontAssetDownloader;
#if OS_API_VERSION(MAC_OS_X_VERSION_10_13, GS_API_LATEST)
@@ -83,7 +84,15 @@ typedef NSUInteger NSFontAssetRequestOptions;
* operation while fonts are being retrieved.
*/
APPKIT_EXPORT_CLASS
-@interface NSFontAssetRequest : NSObject //
+@interface NSFontAssetRequest : NSObject
+{
+ NSArray *_fontDescriptors;
+ NSFontAssetRequestOptions _options;
+ NSMutableArray *_downloadedFontDescriptors;
+ NSProgress *_progress;
+ BOOL _downloadInProgress;
+ GSFontAssetDownloader *_downloader;
+}
/**
* Initializes a font asset request with the specified font descriptors and options.
@@ -138,6 +147,40 @@ APPKIT_EXPORT_CLASS
@end
+@interface NSFontAssetRequest (GNUstep)
+
+/**
+ * Sets the default downloader class to be used for all new font asset requests.
+ * The specified class must be a subclass of GSFontAssetDownloader.
+ * Pass nil to restore the default GSFontAssetDownloader behavior.
+ */
++ (void) setDefaultDownloaderClass: (Class)downloaderClass;
+
+/**
+ * Returns the currently registered default downloader class.
+ */
++ (Class) defaultDownloaderClass;
+
+/**
+ * Sets a custom font asset downloader.
+ * This allows clients to provide custom downloading strategies
+ * by subclassing GSFontAssetDownloader and overriding specific
+ * methods for URL resolution, downloading, validation, or installation.
+ * The downloader parameter specifies the custom downloader to use,
+ * replacing the default downloader instance.
+ */
+- (void) setFontAssetDownloader: (GSFontAssetDownloader *)downloader;
+
+/**
+ * Returns the current font asset downloader.
+ * This can be used to inspect or modify the downloader's configuration,
+ * or to access the downloader for direct use in custom scenarios.
+ * Returns the GSFontAssetDownloader instance currently being used.
+ */
+- (GSFontAssetDownloader *) fontAssetDownloader;
+
+@end
+
#if defined(__cplusplus)
}
#endif
diff --git a/Headers/AppKit/NSFontManager.h b/Headers/AppKit/NSFontManager.h
index edb79b4fd..21d97a87e 100644
--- a/Headers/AppKit/NSFontManager.h
+++ b/Headers/AppKit/NSFontManager.h
@@ -1,34 +1,34 @@
-/*
- NSFontManager.h
+/*
+ NSFontManager.h
- Manages system and user fonts
+ Manages system and user fonts
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996 Free Software Foundation, Inc.
- Author: Scott Christley
- Date: 1996
- Modified: Fred Kiefer
- Date: January 2000
- Almost complete rewrite.
+ Author: Scott Christley
+ Date: 1996
+ Modified: Fred Kiefer
+ Date: January 2000
+ Almost complete rewrite.
- This file is part of the GNUstep GUI Library.
+ This file is part of the GNUstep GUI Library.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; see the file COPYING.LIB.
- If not, see or write to the
- Free Software Foundation, 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; see the file COPYING.LIB.
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
#ifndef _GNUstep_H_NSFontManager
#define _GNUstep_H_NSFontManager
@@ -48,9 +48,9 @@
#if OS_API_VERSION(MAC_OS_X_VERSION_10_3, GS_API_LATEST)
enum _NSFontManagerAddCollectionOptions
-{
- NSFontCollectionApplicationOnlyMask = 1 << 0
-};
+ {
+ NSFontCollectionApplicationOnlyMask = 1 << 0
+ };
#endif
typedef unsigned int NSFontTraitMask;
@@ -163,8 +163,8 @@ APPKIT_EXPORT_CLASS
//
- (NSFontTraitMask)traitsOfFont:(NSFont *)aFont;
- (int)weightOfFont:(NSFont *)fontObject;
-- (BOOL)fontNamed:(NSString *)typeface
- hasTraits:(NSFontTraitMask)fontTraitMask;
+- (BOOL)fontNamed:(NSString *)typeface
+ hasTraits:(NSFontTraitMask)fontTraitMask;
//
// Enabling
@@ -201,19 +201,28 @@ APPKIT_EXPORT_CLASS
- (BOOL)removeCollection:(NSString *)collection;
- (NSArray *)collectionNames;
-- (void)addFontDescriptors:(NSArray *)descriptors
- toCollection:(NSString *)collection;
-- (void)removeFontDescriptor:(NSFontDescriptor *)descriptor
- fromCollection:(NSString *)collection;
+- (void)addFontDescriptors:(NSArray *)descriptors
+ toCollection:(NSString *)collection;
+- (void)removeFontDescriptor:(NSFontDescriptor *)descriptor
+ fromCollection:(NSString *)collection;
- (NSArray *)fontDescriptorsInCollection:(NSString *)collection;
- (NSArray *)availableFontNamesMatchingFontDescriptor:(NSFontDescriptor *)descriptor;
- (NSDictionary *)convertAttributes:(NSDictionary *)attributes;
-- (void)setSelectedAttributes:(NSDictionary *)attributes
- isMultiple:(BOOL)flag;
+- (void)setSelectedAttributes:(NSDictionary *)attributes
+ isMultiple:(BOOL)flag;
#endif
@end
+#if OS_API_VERSION(GS_API_NONE, GS_API_LATEST)
+@interface NSFontManager (Private)
+//
+// GNUstep extensions
+//
+- (void) refreshAvailableFonts;
+@end
+#endif
+
@interface NSObject (NSFontManagerDelegate)
//
// Methods Implemented by the Delegate
@@ -221,6 +230,7 @@ APPKIT_EXPORT_CLASS
- (BOOL)fontManager:(id)sender willIncludeFont:(NSString *)fontName;
@end
-#endif // _GNUstep_H_NSFontManager
-
+// Notifications
+APPKIT_EXPORT NSString * const GSFontManagerAvailableFontsDidChangeNotification;
+#endif // _GNUstep_H_NSFontManager
diff --git a/Headers/AppKit/NSProgressIndicator.h b/Headers/AppKit/NSProgressIndicator.h
index 3bfbe1ae3..9374af55b 100644
--- a/Headers/AppKit/NSProgressIndicator.h
+++ b/Headers/AppKit/NSProgressIndicator.h
@@ -61,7 +61,9 @@ typedef enum _NSProgressIndicatorThickness
typedef enum _NSProgressIndicatorStyle
{
NSProgressIndicatorBarStyle = 0,
- NSProgressIndicatorSpinningStyle = 1
+ NSProgressIndicatorStyleBar = NSProgressIndicatorBarStyle,
+ NSProgressIndicatorSpinningStyle = 1,
+ NSProgressIndicatorStyleSpinning = NSProgressIndicatorSpinningStyle
} NSProgressIndicatorStyle;
APPKIT_EXPORT_CLASS
diff --git a/Source/GNUmakefile b/Source/GNUmakefile
index 51fb140bb..1aefa2cf1 100644
--- a/Source/GNUmakefile
+++ b/Source/GNUmakefile
@@ -18,8 +18,8 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; see the file COPYING.LIB.
-# If not, see or write to the
-# Free Software Foundation, 51 Franklin Street, Fifth Floor,
+# If not, see or write to the
+# Free Software Foundation, 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.
PACKAGE_NAME = gnustep-gui
@@ -374,7 +374,8 @@ GSCSStrength.m \
GSCSEditInfo.m \
GSCSEditVariableManager.m \
GSCSTableau.m \
-GSColorSliderCell.m
+GSColorSliderCell.m \
+GSFontAssetDownloader.m
# Turn off NSMenuItem warning that NSMenuItem conforms to ,
# but does not implement 's methods itself (it inherits
@@ -389,7 +390,7 @@ libgnustep-gui_HEADER_FILES_DIR = ../Headers/Additions/GNUstepGUI
libgnustep-gui_HEADER_FILES_INSTALL_DIR = /GNUstepGUI
COCOA_HEADERS = \
-Cocoa.h
+Cocoa.h
APPKIT_HEADERS = \
AppKit.h \
@@ -646,7 +647,7 @@ NSUserInterfaceItemSearching.h \
NSUserInterfaceItemIdentification.h \
NSUserInterfaceValidation.h \
DPSOperators.h \
-PSOperators.h
+PSOperators.h
GUI_HEADERS = \
GSVersion.h \
@@ -693,7 +694,8 @@ GSWindowDecorationView.h \
GSXibElement.h \
GSXibLoading.h \
GSXibKeyedUnarchiver.h \
-GSHelpAttachment.h
+GSHelpAttachment.h \
+GSFontAssetDownloader.h
libgnustep-gui_HEADER_FILES = ${GUI_HEADERS}
diff --git a/Source/GSFontAssetDownloader.m b/Source/GSFontAssetDownloader.m
new file mode 100644
index 000000000..6317e497c
--- /dev/null
+++ b/Source/GSFontAssetDownloader.m
@@ -0,0 +1,956 @@
+/* Implementation of class GSFontAssetDownloader
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+ By: Gregory John Casamento
+ Date: September 5, 2025
+
+ This file is part of the GNUstep Library.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110 USA.
+*/
+
+#import
+#import "GNUstepGUI/GSFontAssetDownloader.h"
+
+#import "AppKit/NSEvent.h"
+#import "AppKit/NSFontDescriptor.h"
+#import "AppKit/NSFontAssetRequest.h"
+#import "AppKit/NSFontManager.h"
+#import "AppKit/NSPanel.h"
+#import "AppKit/NSProgressIndicator.h"
+#import "AppKit/NSTextField.h"
+#import "AppKit/NSButton.h"
+#import "AppKit/NSApplication.h"
+
+static Class _defaultDownloaderClass = nil;
+
+/*
+ * EXAMPLE USAGE OF CLASS REPLACEMENT SYSTEM:
+ *
+ * // Custom downloader that logs all operations
+ * @interface LoggingFontDownloader : GSFontAssetDownloader
+ * @end
+ *
+ * @implementation LoggingFontDownloader
+ * - (NSURL *) fontURLForDescriptor: (NSFontDescriptor *)descriptor {
+ * NSLog(@"Resolving URL for font: %@", [descriptor objectForKey: NSFontNameAttribute]);
+ * return [super fontURLForDescriptor: descriptor];
+ * }
+ *
+ * - (NSString *) downloadFontFromURL: (NSURL *)fontURL error: (NSError **)error {
+ * NSLog(@"Downloading font from: %@", fontURL);
+ * return [super downloadFontFromURL: fontURL error: error];
+ * }
+ * @end
+ *
+ * // To use the custom downloader globally:
+ * [GSFontAssetDownloader setDefaultDownloaderClass: [LoggingFontDownloader class]];
+ *
+ * // To restore default behavior:
+ * [GSFontAssetDownloader setDefaultDownloaderClass: nil];
+ */
+
+@implementation GSFontAssetDownloader
+
+- (instancetype) initWithOptions: (NSUInteger)options
+{
+ self = [super init];
+ if (self != nil)
+ {
+ _options = options;
+ }
+ return self;
+}
+
+- (instancetype) init
+{
+ return [self initWithOptions: 0];
+}
+
+- (void) dealloc
+{
+ [self hideProgressPanel];
+ [super dealloc];
+}
+
++ (void) setDefaultDownloaderClass: (Class)downloaderClass
+{
+ if (downloaderClass != nil && ![downloaderClass isSubclassOfClass: [GSFontAssetDownloader class]])
+ {
+ [NSException raise: NSInvalidArgumentException
+ format: @"Downloader class must be a subclass of GSFontAssetDownloader"];
+ return;
+ }
+ _defaultDownloaderClass = downloaderClass;
+}
+
++ (Class) defaultDownloaderClass
+{
+ return _defaultDownloaderClass ? _defaultDownloaderClass : [GSFontAssetDownloader class];
+}
+
++ (instancetype) downloaderWithOptions: (NSUInteger)options
+{
+ Class downloaderClass = [self defaultDownloaderClass];
+ return [[downloaderClass alloc] initWithOptions: options];
+}
+
+- (BOOL) downloadAndInstallFontWithDescriptor: (NSFontDescriptor *)descriptor
+ error: (NSError **)error
+{
+ // Delegate to the format-specific method with default format
+ return [self downloadAndInstallFontWithDescriptor: descriptor
+ preferredFormat: nil
+ error: error];
+}
+
+- (BOOL) downloadAndInstallFontWithDescriptor: (NSFontDescriptor *)descriptor
+ preferredFormat: (NSString *)format
+ error: (NSError **)error
+{
+ if (descriptor == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font descriptor is nil"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -1001
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ NSError *localError = nil;
+ NSString *downloadedPath = nil;
+ BOOL success = NO;
+
+ // Show progress panel if standard UI is requested
+ NSString *fontName = [descriptor objectForKey: NSFontNameAttribute];
+ if (fontName == nil)
+ {
+ fontName = [descriptor objectForKey: NSFontFamilyAttribute];
+ }
+ if (fontName == nil)
+ {
+ fontName = @"Font";
+ }
+
+ NSString *progressMessage = [NSString stringWithFormat: @"Downloading %@...", fontName];
+ [self showProgressPanelWithMessage: progressMessage];
+ [self updateProgressPanel: 0.1 withMessage: progressMessage];
+
+ NS_DURING
+ {
+ // Get font URL from descriptor
+ [self updateProgressPanel: 0.2 withMessage: @"Resolving font URL..."];
+ NSURL *fontURL = [self fontURLForDescriptor: descriptor];
+ if (fontURL == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"No font URL available for descriptor"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -1002
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Download the font file
+ [self updateProgressPanel: 0.3 withMessage: @"Starting download..."];
+ // Check if this is a CSS URL (like Google Fonts API) and handle appropriately
+ NSString *urlString = [fontURL absoluteString];
+ if ([urlString containsString: @"fonts.googleapis.com/css"] ||
+ [urlString containsString: @"fonts.google.com/css"] ||
+ [urlString containsString: @"fonts.gstatic.com/css"] ||
+ [urlString hasSuffix: @".css"] ||
+ [[fontURL pathExtension] isEqualToString: @"css"])
+ {
+ // This is a CSS URL containing @font-face declarations
+ // Use the specified format, or default to truetype/ttf if none specified
+ NSString *preferredFormat = format ? format : @"truetype";
+ [self updateProgressPanel: 0.4 withMessage: @"Downloading CSS and extracting font URLs..."];
+ downloadedPath = [self downloadFontDataFromCSSURL: fontURL withFormat: preferredFormat fontName: fontName error: &localError];
+ }
+ else
+ {
+ // This is a direct font file URL
+ [self updateProgressPanel: 0.4 withMessage: @"Downloading font file..."];
+ downloadedPath = [self downloadFontFromURL: fontURL fontName: fontName error: &localError];
+ }
+
+ if (downloadedPath == nil)
+ {
+ [self hideProgressPanel];
+ if (error != NULL)
+ {
+ *error = localError;
+ }
+ return NO;
+ }
+
+ // Validate the downloaded font file
+ [self updateProgressPanel: 0.7 withMessage: @"Validating font file..."];
+ if (![self validateFontFile: downloadedPath error: &localError])
+ {
+ [self hideProgressPanel];
+ if (error != NULL)
+ {
+ *error = localError;
+ }
+ return NO;
+ }
+
+ // Install the font
+ [self updateProgressPanel: 0.8 withMessage: @"Installing font..."];
+ success = [self installFontAtPath: downloadedPath error: &localError];
+ if (success)
+ {
+ [self updateProgressPanel: 1.0 withMessage: @"Font installed successfully!"];
+
+ // Refresh font cache so newly installed font appears in font panel
+ [[NSFontManager sharedFontManager] refreshAvailableFonts];
+
+ // Brief delay to show completion
+ [NSThread sleepForTimeInterval: 0.5];
+ }
+ else if (error != NULL)
+ {
+ *error = localError;
+ }
+ }
+ NS_HANDLER
+ {
+ [self hideProgressPanel];
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Font download and installation failed", NSLocalizedDescriptionKey,
+ [localException reason], NSLocalizedFailureReasonErrorKey,
+ nil];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -1003
+ userInfo: userInfo];
+ }
+ success = NO;
+ }
+ NS_ENDHANDLER;
+
+ // Clean up temporary download file
+ if (downloadedPath != nil)
+ {
+ [[NSFileManager defaultManager] removeItemAtPath: downloadedPath error: nil];
+ }
+
+ // Hide progress panel
+ [self hideProgressPanel];
+
+ return success;
+}
+
+- (NSURL *) fontURLForDescriptor: (NSFontDescriptor *)descriptor
+{
+ // Check if descriptor has a URL attribute (custom extension)
+ NSURL *fontURL = [descriptor objectForKey: @"NSFontURLAttribute"];
+ if (fontURL != nil)
+ {
+ return fontURL;
+ }
+
+ // Try to construct URL from font name for common font sources
+ NSString *fontName = [descriptor objectForKey: NSFontNameAttribute];
+ NSString *familyName = [descriptor objectForKey: NSFontFamilyAttribute];
+
+ if (fontName == nil && familyName == nil)
+ {
+ return nil;
+ }
+
+ NSString *searchName = fontName ? fontName : familyName;
+ NSString *encodedName = [searchName stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
+
+ // Example: Try Google Fonts API (this is simplified - real implementation would use proper API)
+ NSString *urlString = [NSString stringWithFormat: @"https://fonts.googleapis.com/css2?family=%@", encodedName];
+
+ return [NSURL URLWithString: urlString];
+}
+
+- (NSArray *) extractFontURLsFromCSS: (NSString *)cssContent
+ withFormat: (NSString *)format
+ error: (NSError **)error
+{
+ if (cssContent == nil || [cssContent length] == 0)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"CSS content is nil or empty"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2100
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ NSMutableArray *fontURLs = [NSMutableArray array];
+
+ // Regular expression to match src: url(...) format('...') patterns
+ NSString *pattern = @"src:\\s*url\\(([^)]+)\\)\\s*format\\(['\"]([^'\"]+)['\"]\\)";
+ NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: pattern
+ options: NSRegularExpressionCaseInsensitive
+ error: error];
+ if (regex == nil)
+ {
+ return nil;
+ }
+
+ NSArray *matches = [regex matchesInString: cssContent
+ options: 0
+ range: NSMakeRange(0, [cssContent length])];
+ NSEnumerator *men = [matches objectEnumerator];
+ NSTextCheckingResult *match = nil;
+
+ while ((match = [men nextObject]) != nil)
+ {
+ if ([match numberOfRanges] >= 3)
+ {
+ NSRange urlRange = [match rangeAtIndex: 1];
+ NSRange formatRange = [match rangeAtIndex: 2];
+
+ NSString *urlString = [cssContent substringWithRange: urlRange];
+ NSString *formatString = [cssContent substringWithRange: formatRange];
+
+ // Clean up URL string (remove quotes if present)
+ urlString = [urlString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"\"' "]];
+
+ // Check if format matches what we're looking for
+ if (format == nil || [formatString isEqualToString: format])
+ {
+ NSURL *url = [NSURL URLWithString: urlString];
+ if (url != nil)
+ {
+ [fontURLs addObject: url];
+ }
+ }
+ }
+ }
+
+ return [fontURLs copy];
+}
+
+- (NSString *) downloadFontDataFromCSSURL: (NSURL *)cssURL
+ withFormat: (NSString *)format
+ error: (NSError **)error
+{
+ // Use a generic font name since we don't have the font descriptor here
+ NSString *genericFontName = @"WebFont";
+
+ // Try to extract font name from CSS URL if it's a Google Fonts URL
+ NSString *urlString = [cssURL absoluteString];
+ if ([urlString containsString: @"fonts.googleapis.com/css"] || [urlString containsString: @"fonts.google.com/css"])
+ {
+ // Try to extract font family from URL parameters
+ NSString *query = [cssURL query];
+ if (query != nil)
+ {
+ NSArray *queryParts = [query componentsSeparatedByString: @"&"];
+ for (NSString *part in queryParts)
+ {
+ if ([part hasPrefix: @"family="])
+ {
+ NSString *familyPart = [part substringFromIndex: 7]; // Skip "family="
+ // Take first font name if multiple are specified
+ NSArray *families = [familyPart componentsSeparatedByString: @"|"];
+ if ([families count] > 0)
+ {
+ genericFontName = [families objectAtIndex: 0];
+ // Clean up URL encoding
+ genericFontName = [genericFontName stringByRemovingPercentEncoding];
+ // Replace + with spaces (URL encoding)
+ genericFontName = [genericFontName stringByReplacingOccurrencesOfString: @"+" withString: @" "];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Delegate to the method that takes font name
+ return [self downloadFontDataFromCSSURL: cssURL withFormat: format fontName: genericFontName error: error];
+}
+
+- (NSString *) downloadFontDataFromCSSURL: (NSURL *)cssURL
+ withFormat: (NSString *)format
+ fontName: (NSString *)fontName
+ error: (NSError **)error
+{
+ if (cssURL == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"CSS URL is nil"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2101
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ // First, download the CSS content
+ NSString *cssContent = nil;
+ NSError *cssError = nil;
+
+ [self updateProgressPanel: 0.45 withMessage: @"Downloading CSS file..."];
+
+ NS_DURING
+ {
+ NSData *cssData = [NSData dataWithContentsOfURL: cssURL];
+ if (cssData != nil)
+ {
+ cssContent = [[NSString alloc] initWithData: cssData encoding: NSUTF8StringEncoding];
+ }
+ }
+ NS_HANDLER
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Failed to download CSS from URL", NSLocalizedDescriptionKey,
+ [localException reason], NSLocalizedFailureReasonErrorKey,
+ nil];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2102
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+ NS_ENDHANDLER;
+
+ if (cssContent == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Failed to parse CSS content"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2103
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ // Extract font URLs from CSS
+ [self updateProgressPanel: 0.5 withMessage: @"Parsing CSS and extracting font URLs..."];
+ NSArray *fontURLs = [self extractFontURLsFromCSS: cssContent
+ withFormat: format
+ error: &cssError];
+ if (fontURLs == nil || [fontURLs count] == 0)
+ {
+ if (error != NULL)
+ {
+ *error = cssError ?: [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2104
+ userInfo: [NSDictionary dictionaryWithObject: @"No font URLs found in CSS"
+ forKey: NSLocalizedDescriptionKey]];
+ }
+ return nil;
+ }
+
+ // Download the first matching font URL using the font name
+ [self updateProgressPanel: 0.6 withMessage: @"Downloading font file from extracted URL..."];
+ NSURL *fontURL = [fontURLs firstObject];
+ return [self downloadFontFromURL: fontURL fontName: fontName error: error];
+}
+
+- (NSString *) downloadFontFromURL: (NSURL *)fontURL
+ error: (NSError **)error
+{
+ // Extract font name from URL or use generic name
+ NSString *fontName = @"UnknownFont";
+ NSString *lastComponent = [fontURL lastPathComponent];
+ if (lastComponent != nil && [lastComponent length] > 0)
+ {
+ // Remove file extension to get just the name
+ fontName = [lastComponent stringByDeletingPathExtension];
+ if ([fontName length] == 0)
+ {
+ fontName = @"UnknownFont";
+ }
+ }
+
+ // Delegate to the method that takes font name
+ return [self downloadFontFromURL: fontURL fontName: fontName error: error];
+}
+
+- (NSString *) downloadFontFromURL: (NSURL *)fontURL
+ fontName: (NSString *)fontName
+ error: (NSError **)error
+{
+ if (fontURL == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font URL is nil"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2001
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ // Create temporary file for download using font name
+ NSString *tempDir = NSTemporaryDirectory();
+ NSString *filename = nil;
+
+ // Clean font name for use in filename (remove spaces and special characters)
+ NSString *cleanFontName = fontName;
+ if (cleanFontName != nil && [cleanFontName length] > 0)
+ {
+ // Replace spaces and special characters with underscores
+ NSMutableString *mutableName = [cleanFontName mutableCopy];
+ [mutableName replaceOccurrencesOfString: @" " withString: @"_" options: 0 range: NSMakeRange(0, [mutableName length])];
+ [mutableName replaceOccurrencesOfString: @"-" withString: @"_" options: 0 range: NSMakeRange(0, [mutableName length])];
+ [mutableName replaceOccurrencesOfString: @"+" withString: @"_" options: 0 range: NSMakeRange(0, [mutableName length])];
+ cleanFontName = [NSString stringWithString: mutableName];
+ [mutableName release];
+ }
+ else
+ {
+ cleanFontName = @"UnknownFont";
+ }
+
+ // Determine appropriate file extension based on URL
+ NSString *extension = @"ttf"; // default
+ NSString *urlPath = [fontURL path];
+ if ([urlPath containsString: @".woff2"])
+ {
+ extension = @"woff2";
+ }
+ else if ([urlPath containsString: @".woff"])
+ {
+ extension = @"woff";
+ }
+ else if ([urlPath containsString: @".otf"])
+ {
+ extension = @"otf";
+ }
+ else if ([urlPath containsString: @".ttf"])
+ {
+ extension = @"ttf";
+ }
+
+ // Create filename with font name and appropriate extension
+ filename = [NSString stringWithFormat: @"%@.%@", cleanFontName, extension];
+ NSString *tempPath = [tempDir stringByAppendingPathComponent: filename];
+
+ // Download the font file
+ NSData *fontData = nil;
+
+ NS_DURING
+ {
+ // For HTTPS URLs, try to download
+ if ([[fontURL scheme] isEqualToString: @"https"] || [[fontURL scheme] isEqualToString: @"http"])
+ {
+ fontData = [NSData dataWithContentsOfURL: fontURL];
+ }
+ // For file URLs, copy the file
+ else if ([[fontURL scheme] isEqualToString: @"file"])
+ {
+ fontData = [NSData dataWithContentsOfURL: fontURL];
+ }
+ }
+ NS_HANDLER
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Failed to download font from URL", NSLocalizedDescriptionKey,
+ [localException reason], NSLocalizedFailureReasonErrorKey,
+ nil];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2002
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+ NS_ENDHANDLER;
+
+ if (fontData == nil || [fontData length] == 0)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"No data received from font URL"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2003
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ // Write font data to temporary file
+ if (![fontData writeToFile: tempPath atomically: YES])
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Failed to write font data to temporary file"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -2004
+ userInfo: userInfo];
+ }
+ return nil;
+ }
+
+ return tempPath;
+}
+
+- (BOOL) validateFontFile: (NSString *)fontPath
+ error: (NSError **)error
+{
+ if (fontPath == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font path is nil"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -3001
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Check if file exists
+ if (![[NSFileManager defaultManager] fileExistsAtPath: fontPath])
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font file does not exist"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -3002
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Basic validation - check file size and magic bytes
+ NSData *fontData = [NSData dataWithContentsOfFile: fontPath];
+ if (fontData == nil || [fontData length] < 12)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font file is too small or unreadable"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -3003
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Check for common font file signatures (TTF, OTF, WOFF, WOFF2)
+ const unsigned char *bytes = [fontData bytes];
+
+ // TTF signature: 0x00, 0x01, 0x00, 0x00 or 'true'
+ // OTF signature: 'OTTO'
+ // WOFF signature: 'wOFF'
+ // WOFF2 signature: 'wOF2'
+ if ((bytes[0] == 0x00 && bytes[1] == 0x01 && bytes[2] == 0x00 && bytes[3] == 0x00) ||
+ (bytes[0] == 't' && bytes[1] == 'r' && bytes[2] == 'u' && bytes[3] == 'e') ||
+ (bytes[0] == 'O' && bytes[1] == 'T' && bytes[2] == 'T' && bytes[3] == 'O') ||
+ (bytes[0] == 'w' && bytes[1] == 'O' && bytes[2] == 'F' && bytes[3] == 'F') ||
+ (bytes[0] == 'w' && bytes[1] == 'O' && bytes[2] == 'F' && bytes[3] == '2'))
+ {
+ return YES;
+ }
+
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font file does not have a valid font signature"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -3004
+ userInfo: userInfo];
+ }
+ return NO;
+}
+
+- (BOOL) installFontAtPath: (NSString *)fontPath
+ error: (NSError **)error
+{
+ if (fontPath == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font path is nil"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -4001
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ NSString *filename = [fontPath lastPathComponent];
+ NSString *destinationDir;
+
+ // Determine installation directory based on options
+ if (_options & NSFontAssetRequestOptionUsesStandardUI)
+ {
+ // Install to user fonts directory for user-level installation
+ destinationDir = [self userFontsDirectory];
+ }
+ else
+ {
+ // Try system fonts directory, fall back to user directory
+ destinationDir = [self systemFontsDirectory];
+ if (destinationDir == nil)
+ {
+ destinationDir = [self userFontsDirectory];
+ }
+ }
+
+ if (destinationDir == nil)
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Cannot determine font installation directory"
+ forKey: NSLocalizedDescriptionKey];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -4002
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Create destination directory if needed
+ NSError *dirError = nil;
+ if (![[NSFileManager defaultManager] createDirectoryAtPath: destinationDir
+ withIntermediateDirectories: YES
+ attributes: nil
+ error: &dirError])
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Failed to create font installation directory", NSLocalizedDescriptionKey,
+ [dirError localizedDescription], NSLocalizedFailureReasonErrorKey,
+ nil];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -4003
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Copy font to destination
+ NSString *destinationPath = [destinationDir stringByAppendingPathComponent: filename];
+ NSError *copyError = nil;
+
+ // Remove existing font file if present
+ if ([[NSFileManager defaultManager] fileExistsAtPath: destinationPath])
+ {
+ [[NSFileManager defaultManager] removeItemAtPath: destinationPath error: nil];
+ }
+
+ if (![[NSFileManager defaultManager] copyItemAtPath: fontPath
+ toPath: destinationPath
+ error: ©Error])
+ {
+ if (error != NULL)
+ {
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Failed to copy font to installation directory", NSLocalizedDescriptionKey,
+ [copyError localizedDescription], NSLocalizedFailureReasonErrorKey,
+ nil];
+ *error = [NSError errorWithDomain: @"GSFontAssetDownloaderErrorDomain"
+ code: -4004
+ userInfo: userInfo];
+ }
+ return NO;
+ }
+
+ // Notify system of new font (platform-specific)
+#ifdef __APPLE__
+ // On macOS, fonts are automatically detected when placed in font directories
+ NSLog(@"Font installed to: %@", destinationPath);
+#else
+ NS_DURING
+ {
+ NSTask *task = [[NSTask alloc] init];
+ [task setLaunchPath: @"/usr/bin/fc-cache"];
+ [task setArguments: [NSArray arrayWithObject: @"-f"]];
+ [task launch];
+ [task waitUntilExit];
+ if ([task terminationStatus] == 0)
+ {
+ NSLog(@"Font installed and cache updated: %@", destinationPath);
+ }
+ else
+ {
+ NSLog(@"Font installed, but fc-cache failed with status: %d", [task terminationStatus]);
+ }
+ }
+ NS_HANDLER
+ {
+ NSLog(@"Font installed, but failed to run fc-cache: %@", localException);
+ }
+ NS_ENDHANDLER;
+#endif
+
+ return YES;
+}
+
+- (NSString *) systemFontsDirectory
+{
+#ifdef __APPLE__
+ return @"/Library/Fonts";
+#else
+ return @"/usr/local/share/fonts";
+#endif
+}
+
+- (NSString *) userFontsDirectory
+{
+ NSString *homeDir = NSHomeDirectory();
+
+#ifdef __APPLE__
+ return [homeDir stringByAppendingPathComponent: @"Library/Fonts"];
+#else
+ // Generic Unix/other systems
+ return [homeDir stringByAppendingPathComponent: @".fonts"];
+#endif
+}
+
+- (NSUInteger) options
+{
+ return _options;
+}
+
+- (void) showProgressPanelWithMessage: (NSString *)message
+{
+ if (!(_options & NSFontAssetRequestOptionUsesStandardUI))
+ {
+ return; // Don't show UI if not requested
+ }
+
+ if (_progressPanel != nil)
+ {
+ [self hideProgressPanel]; // Hide existing panel if any
+ }
+
+ // Create the progress panel
+ NSRect panelFrame = NSMakeRect(0, 0, 400, 120);
+ _progressPanel = [[NSPanel alloc] initWithContentRect: panelFrame
+ styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskClosable
+ backing: NSBackingStoreBuffered
+ defer: NO];
+ [_progressPanel setTitle: @"Font Download"];
+ [_progressPanel setLevel: NSModalPanelWindowLevel];
+ [_progressPanel setReleasedWhenClosed: NO];
+
+ // Create and configure the status label
+ NSRect labelFrame = NSMakeRect(20, 70, 360, 20);
+ _statusLabel = [[NSTextField alloc] initWithFrame: labelFrame];
+ [_statusLabel setStringValue: message ? message : @"Downloading font..."];
+ [_statusLabel setBezeled: NO];
+ [_statusLabel setDrawsBackground: NO];
+ [_statusLabel setEditable: NO];
+ [_statusLabel setSelectable: NO];
+ [[_progressPanel contentView] addSubview: _statusLabel];
+ RELEASE(_statusLabel);
+
+ // Create and configure the progress indicator
+ NSRect progressFrame = NSMakeRect(20, 40, 360, 20);
+ _progressIndicator = [[NSProgressIndicator alloc] initWithFrame: progressFrame];
+ [_progressIndicator setStyle: NSProgressIndicatorStyleBar];
+ [_progressIndicator setIndeterminate: NO];
+ [_progressIndicator setMinValue: 0.0];
+ [_progressIndicator setMaxValue: 1.0];
+ [_progressIndicator setDoubleValue: 0.0];
+ [[_progressPanel contentView] addSubview: _progressIndicator];
+ RELEASE(_progressIndicator);
+
+ // Create and configure the cancel button
+ NSRect buttonFrame = NSMakeRect(310, 10, 80, 25);
+ _cancelButton = [[NSButton alloc] initWithFrame: buttonFrame];
+ [_cancelButton setTitle: @"Cancel"];
+ [_cancelButton setTarget: self];
+ [_cancelButton setAction: @selector(cancelDownload:)];
+ [[_progressPanel contentView] addSubview: _cancelButton];
+ RELEASE(_cancelButton);
+
+ // Center and show the panel
+ [_progressPanel center];
+ [_progressPanel makeKeyAndOrderFront: nil];
+}
+
+- (void) updateProgressPanel: (double)progress withMessage: (NSString *)message
+{
+ if (_progressPanel == nil || !(_options & NSFontAssetRequestOptionUsesStandardUI))
+ {
+ return;
+ }
+
+ if (_progressIndicator != nil)
+ {
+ [_progressIndicator setDoubleValue: progress];
+ }
+
+ if (_statusLabel != nil && message != nil)
+ {
+ [_statusLabel setStringValue: message];
+ }
+
+ // Process events to update the UI
+ NSEvent *event;
+ while ((event = [NSApp nextEventMatchingMask: NSAnyEventMask
+ untilDate: [NSDate distantPast]
+ inMode: NSDefaultRunLoopMode
+ dequeue: YES]))
+ {
+ [NSApp sendEvent: event];
+ }
+}
+
+- (void) hideProgressPanel
+{
+ if (_progressPanel != nil)
+ {
+ [_progressPanel orderOut: nil];
+ DESTROY(_progressPanel);
+ }
+}
+
+- (void) cancelDownload: (id)sender
+{
+ // For now, just hide the panel
+ // In a full implementation, this would cancel the actual download operation
+ [self hideProgressPanel];
+
+ // Post a notification that download was cancelled
+ [[NSNotificationCenter defaultCenter]
+ postNotificationName: @"GSFontAssetDownloadCancelled"
+ object: self];
+}
+
+@end
diff --git a/Source/GSFontInfo.m b/Source/GSFontInfo.m
index cb667faad..22f162cf4 100644
--- a/Source/GSFontInfo.m
+++ b/Source/GSFontInfo.m
@@ -76,9 +76,9 @@ - (void) dealloc
+ (GSFontEnumerator*) sharedEnumerator
{
NSAssert(fontEnumeratorClass,
- @"Called with fontEnumeratorClass unset."
- @" The shared NSApplication instance must be created before methods that"
- @" need the backend may be called.");
+ @"Called with fontEnumeratorClass unset."
+ @" The shared NSApplication instance must be created before methods that"
+ @" need the backend may be called.");
if (!sharedEnumerator)
sharedEnumerator = [[fontEnumeratorClass alloc] init];
return sharedEnumerator;
@@ -90,6 +90,22 @@ - (void) enumerateFontsAndFamilies
[self subclassResponsibility: _cmd];
}
+- (void) refreshFontCache
+{
+ // Release old cached data
+ RELEASE(allFontNames);
+ RELEASE(allFontFamilies);
+ RELEASE(allFontDescriptors);
+
+ // Reset to nil so they get rebuilt
+ allFontNames = nil;
+ allFontFamilies = nil;
+ allFontDescriptors = nil;
+
+ // Re-enumerate fonts and families to rebuild cache
+ [self enumerateFontsAndFamilies];
+}
+
- (NSArray*) availableFonts
{
return allFontNames;
@@ -117,38 +133,38 @@ - (NSArray*) availableFontDescriptors
fontDescriptors = [[NSMutableArray alloc] init];
keyEnumerator = [allFontFamilies keyEnumerator];
while ((family = [keyEnumerator nextObject]) != nil)
- {
- NSArray *fontDefs = [allFontFamilies objectForKey: family];
- NSEnumerator *fdEnumerator;
- NSArray *fontDef;
-
- fdEnumerator = [fontDefs objectEnumerator];
- while ((fontDef = [fdEnumerator nextObject]) != nil)
- {
- NSFontDescriptor *fd;
- NSDictionary *attributes;
- NSNumber *weight = [fontDef objectAtIndex: 2];
- NSNumber *traits = [fontDef objectAtIndex: 3];
- NSDictionary *fontTraits;
- float fweight = ([weight intValue] - 6) / 6.0;
-
- fontTraits = [NSDictionary dictionaryWithObjectsAndKeys:
- traits, NSFontSymbolicTrait,
- [NSNumber numberWithFloat: fweight],
- NSFontWeightTrait,
- nil];
- attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- family, NSFontFamilyAttribute,
- [fontDef objectAtIndex: 0], NSFontNameAttribute,
- [fontDef objectAtIndex: 1], NSFontFaceAttribute,
- fontTraits, NSFontTraitsAttribute,
- nil];
- fd = [[NSFontDescriptor alloc] initWithFontAttributes: attributes];
-
- [fontDescriptors addObject: fd];
- RELEASE(fd);
- }
- }
+ {
+ NSArray *fontDefs = [allFontFamilies objectForKey: family];
+ NSEnumerator *fdEnumerator;
+ NSArray *fontDef;
+
+ fdEnumerator = [fontDefs objectEnumerator];
+ while ((fontDef = [fdEnumerator nextObject]) != nil)
+ {
+ NSFontDescriptor *fd;
+ NSDictionary *attributes;
+ NSNumber *weight = [fontDef objectAtIndex: 2];
+ NSNumber *traits = [fontDef objectAtIndex: 3];
+ NSDictionary *fontTraits;
+ float fweight = ([weight intValue] - 6) / 6.0;
+
+ fontTraits = [NSDictionary dictionaryWithObjectsAndKeys:
+ traits, NSFontSymbolicTrait,
+ [NSNumber numberWithFloat: fweight],
+ NSFontWeightTrait,
+ nil];
+ attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ family, NSFontFamilyAttribute,
+ [fontDef objectAtIndex: 0], NSFontNameAttribute,
+ [fontDef objectAtIndex: 1], NSFontFaceAttribute,
+ fontTraits, NSFontTraitsAttribute,
+ nil];
+ fd = [[NSFontDescriptor alloc] initWithFontAttributes: attributes];
+
+ [fontDescriptors addObject: fd];
+ RELEASE(fd);
+ }
+ }
allFontDescriptors = fontDescriptors;
}
@@ -178,9 +194,9 @@ - (NSArray *) availableFontNamesMatchingFontDescriptor: (NSFontDescriptor *)desc
{
fontName = [fd objectForKey: NSFontNameAttribute];
if (fontName != nil)
- {
- [found addObject: fontName];
- }
+ {
+ [found addObject: fontName];
+ }
}
return found;
@@ -200,47 +216,47 @@ - (BOOL) _fontDescriptor: (NSFontDescriptor *)fd matches: (NSDictionary *)attrib
id valueA = [attributes objectForKey: key];
if (valueA != nil)
- {
- id valueB = [fd objectForKey: key];
-
- if (valueB == nil)
- {
- match = NO;
- break;
- }
-
- // Special handling for NSFontTraitsAttribute
- if ([key isEqual: NSFontTraitsAttribute])
- {
- NSNumber *traitsA = [valueA objectForKey: NSFontSymbolicTrait];
- NSNumber *traitsB = [valueB objectForKey: NSFontSymbolicTrait];
-
- // FIXME: For now we only compare symbolic traits
- if ((traitsA != nil) &&
- ((traitsB == nil) ||
- ([traitsA unsignedIntValue] != [traitsB unsignedIntValue])))
- {
- match = NO;
- break;
- }
- }
- else if ([key isEqual: NSFontCharacterSetAttribute])
- {
- if (![valueB isSupersetOfSet: valueA])
- {
- match = NO;
- break;
- }
- }
- else
- {
- if (![valueA isEqual: valueB])
- {
- match = NO;
- break;
- }
- }
- }
+ {
+ id valueB = [fd objectForKey: key];
+
+ if (valueB == nil)
+ {
+ match = NO;
+ break;
+ }
+
+ // Special handling for NSFontTraitsAttribute
+ if ([key isEqual: NSFontTraitsAttribute])
+ {
+ NSNumber *traitsA = [valueA objectForKey: NSFontSymbolicTrait];
+ NSNumber *traitsB = [valueB objectForKey: NSFontSymbolicTrait];
+
+ // FIXME: For now we only compare symbolic traits
+ if ((traitsA != nil) &&
+ ((traitsB == nil) ||
+ ([traitsA unsignedIntValue] != [traitsB unsignedIntValue])))
+ {
+ match = NO;
+ break;
+ }
+ }
+ else if ([key isEqual: NSFontCharacterSetAttribute])
+ {
+ if (![valueB isSupersetOfSet: valueA])
+ {
+ match = NO;
+ break;
+ }
+ }
+ else
+ {
+ if (![valueA isEqual: valueB])
+ {
+ match = NO;
+ break;
+ }
+ }
+ }
}
return match;
@@ -258,9 +274,9 @@ - (NSArray *) matchingFontDescriptorsFor: (NSDictionary *)attributes
while ((fd = [fdEnumerator nextObject]) != nil)
{
if ([self _fontDescriptor: fd matches: attributes])
- {
- [found addObject: fd];
- }
+ {
+ [found addObject: fd];
+ }
}
return found;
@@ -276,9 +292,9 @@ - (BOOL) _fontDescriptor: (NSFontDescriptor *)fd matchesAny: (NSArray *)a
while ((o = [en nextObject]) != nil)
{
if ([self _fontDescriptor: fd matches: [o fontAttributes]])
- {
- return YES;
- }
+ {
+ return YES;
+ }
}
return NO;
@@ -290,9 +306,9 @@ - (BOOL) _fontDescriptor: (NSFontDescriptor *)fd matchesAny: (NSArray *)a
* Currently we ignore the options as these may only be implemented in the backend.
*/
- (NSArray *) matchingDescriptorsForFamily: (NSString *)family
- options: (NSDictionary *)options
- inclusion: (NSArray *)queryDescriptors
- exculsion: (NSArray *)exclusionDescriptors
+ options: (NSDictionary *)options
+ inclusion: (NSArray *)queryDescriptors
+ exculsion: (NSArray *)exclusionDescriptors
{
NSMutableArray *r = [NSMutableArray arrayWithCapacity: 50];
NSEnumerator *en = [[self availableFontDescriptors] objectEnumerator];
@@ -302,22 +318,22 @@ - (NSArray *) matchingDescriptorsForFamily: (NSString *)family
{
// Check if the font descriptor matches the family value if one is given
if ((family != nil) &&
- ![[fd objectForKey: NSFontFamilyAttribute] isEqualToString: family])
- {
- continue;
- }
+ ![[fd objectForKey: NSFontFamilyAttribute] isEqualToString: family])
+ {
+ continue;
+ }
// Check if the font descriptor matches any of the query descriptors
if (![self _fontDescriptor: fd matchesAny: queryDescriptors])
- {
- continue;
- }
+ {
+ continue;
+ }
// Check if the font descriptor matches none of the exclusion descriptors
if ([self _fontDescriptor: fd matchesAny: exclusionDescriptors])
- {
- continue;
- }
+ {
+ continue;
+ }
// Add it to the result
[r addObject: fd];
@@ -357,7 +373,7 @@ + (void) setDefaultClass: (Class)defaultClass
}
+ (GSFontInfo*) fontInfoForFontName: (NSString*)nfontName
- matrix: (const CGFloat *)fmatrix
+ matrix: (const CGFloat *)fmatrix
screenFont: (BOOL)screenFont;
{
NSAssert(fontInfoClass,
@@ -506,53 +522,53 @@ - (NSDictionary*) afmDictionary
[fontDictionary setObject: fontName forKey: NSAFMFontName];
if (familyName != nil)
- {
+ {
[fontDictionary setObject: familyName
forKey: NSAFMFamilyName];
}
if (ascender != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: ascender]
forKey: NSAFMAscender];
}
if (descender != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: descender]
forKey: NSAFMDescender];
}
if (xHeight != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: xHeight]
forKey: NSAFMXHeight];
}
if (capHeight != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: capHeight]
forKey: NSAFMCapHeight];
}
if (italicAngle != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: italicAngle]
forKey: NSAFMItalicAngle];
}
if (underlinePosition != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: underlinePosition]
forKey: NSAFMUnderlinePosition];
}
if (underlineThickness != 0.0)
- {
+ {
[fontDictionary setObject: [NSNumber numberWithFloat: underlineThickness]
forKey: NSAFMUnderlineThickness];
}
weightString = [GSFontInfo stringForWeight: weight];
if (weightString != nil)
- {
+ {
[fontDictionary setObject: weightString forKey: NSAFMWeight];
}
if (encodingScheme != nil)
- {
+ {
[fontDictionary setObject: encodingScheme
forKey: NSAFMEncodingScheme];
}
@@ -837,32 +853,32 @@ - (NSFontDescriptor*) fontDescriptor
{
// Create a new one
if ((matrix[0] == matrix[3]) && (matrix[1] == 0.0) &&
- (matrix[2] == 0.0) && (matrix[4] == 0.0) && (matrix[5] == 0.0))
- {
- ASSIGN(fontDescriptor, [NSFontDescriptor fontDescriptorWithName: fontName
- size: matrix[0]]);
- }
+ (matrix[2] == 0.0) && (matrix[4] == 0.0) && (matrix[5] == 0.0))
+ {
+ ASSIGN(fontDescriptor, [NSFontDescriptor fontDescriptorWithName: fontName
+ size: matrix[0]]);
+ }
else
- {
- NSAffineTransform *transform = [NSAffineTransform new];
- NSAffineTransformStruct ats;
- NSDictionary *attributes;
-
- ats.m11 = matrix[0];
- ats.m12 = matrix[1];
- ats.m21 = matrix[2];
- ats.m22 = matrix[3];
- ats.tX = matrix[4];
- ats.tY = matrix[5];
- [transform setTransformStruct: ats];
-
- attributes = [NSDictionary dictionaryWithObjectsAndKeys:
- fontName, NSFontNameAttribute,
- transform, NSFontMatrixAttribute,
- nil];
- RELEASE(transform);
- fontDescriptor = [[NSFontDescriptor alloc] initWithFontAttributes: attributes];
- }
+ {
+ NSAffineTransform *transform = [NSAffineTransform new];
+ NSAffineTransformStruct ats;
+ NSDictionary *attributes;
+
+ ats.m11 = matrix[0];
+ ats.m12 = matrix[1];
+ ats.m21 = matrix[2];
+ ats.m22 = matrix[3];
+ ats.tX = matrix[4];
+ ats.tY = matrix[5];
+ [transform setTransformStruct: ats];
+
+ attributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ fontName, NSFontNameAttribute,
+ transform, NSFontMatrixAttribute,
+ nil];
+ RELEASE(transform);
+ fontDescriptor = [[NSFontDescriptor alloc] initWithFontAttributes: attributes];
+ }
}
return fontDescriptor;
}
diff --git a/Source/NSFontAssetRequest.m b/Source/NSFontAssetRequest.m
index c5d0bf587..a2932e8af 100644
--- a/Source/NSFontAssetRequest.m
+++ b/Source/NSFontAssetRequest.m
@@ -1,21 +1,21 @@
/* Implementation of class NSFontAssetRequest
Copyright (C) 2019 Free Software Foundation, Inc.
-
+
By: Gregory John Casamento
Date: Tue Apr 7 08:06:56 EDT 2020
This file is part of the GNUstep Library.
-
+
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
-
+
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
-
+
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
@@ -24,33 +24,223 @@
#import
#import "AppKit/NSFontAssetRequest.h"
+#import "AppKit/NSFontDescriptor.h"
+#import "GNUstepGUI/GSFontAssetDownloader.h"
+
+@interface NSFontAssetRequest (Private)
+- (void) _performFontDownloadWithCompletionHandler: (GSFontAssetCompletionHandler)completionHandler;
+- (void) _updateProgressWithDescription: (NSString *)description;
+- (void) _completeDownloadWithError: (NSError *)error
+ completionHandler: (GSFontAssetCompletionHandler)completionHandler;
+@end
+
+@implementation NSFontAssetRequest (GNUstep)
+
++ (void) setDefaultDownloaderClass: (Class)downloaderClass
+{
+ [GSFontAssetDownloader setDefaultDownloaderClass: downloaderClass];
+}
+
++ (Class) defaultDownloaderClass
+{
+ return [GSFontAssetDownloader defaultDownloaderClass];
+}
+
+- (void) setFontAssetDownloader: (GSFontAssetDownloader *)downloader
+{
+ ASSIGN(_downloader, downloader);
+}
+
+- (GSFontAssetDownloader *) fontAssetDownloader
+{
+ return _downloader;
+}
+
+@end
+
@implementation NSFontAssetRequest
- (instancetype) initWithFontDescriptors: (NSArray *)fontDescriptors
options: (NSFontAssetRequestOptions)options
{
- return [super init];
+ self = [super init];
+ if (self != nil)
+ {
+ _fontDescriptors = [fontDescriptors copy];
+ _options = options;
+ _downloadedFontDescriptors = [[NSMutableArray alloc] init];
+ _progress = RETAIN([NSProgress progressWithTotalUnitCount: [fontDescriptors count]]);
+ [_progress setCompletedUnitCount: 0];
+ _downloadInProgress = NO;
+ _downloader = [[GSFontAssetDownloader alloc] initWithOptions: options];
+ [_progress setLocalizedDescription: @"Downloading fonts..."];
+ [_progress setLocalizedAdditionalDescription: @"Preparing to download font assets"];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ RELEASE(_fontDescriptors);
+ RELEASE(_downloadedFontDescriptors);
+ RELEASE(_progress);
+ RELEASE(_downloader);
+ [super dealloc];
}
- (NSArray *) downloadedFontDescriptors
{
- return nil;
+ return [[_downloadedFontDescriptors copy] autorelease];
}
- (NSProgress *) progress
{
- return nil; // [NSProgress progressWithTotalUnitCount: 0.0];
+ return _progress;
}
- (void) downloadFontAssetsWithCompletionHandler:
(GSFontAssetCompletionHandler)completionHandler
{
- NSError *error = nil;
-
NSAssert(completionHandler != NULL, NSInvalidArgumentException);
- CALL_NON_NULL_BLOCK(completionHandler, error);
+
+ if (_downloadInProgress)
+ {
+ // Already downloading, call completion handler with error
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font asset download already in progress"
+ forKey: NSLocalizedDescriptionKey];
+ NSError *error = [NSError errorWithDomain: @"NSFontAssetRequestErrorDomain"
+ code: -1001
+ userInfo: userInfo];
+ CALL_NON_NULL_BLOCK(completionHandler, error);
+ return;
+ }
+
+ _downloadInProgress = YES;
+
+ // Use timer-based simulation instead of GCD blocks for compatibility
+ [self performSelector: @selector(_performFontDownloadWithCompletionHandler:)
+ withObject: completionHandler
+ afterDelay: 0.0];
}
-@end
+- (void) _performFontDownloadWithCompletionHandler: (GSFontAssetCompletionHandler)completionHandler
+{
+ NSError *downloadError = nil;
+ BOOL success = YES;
+ NSUInteger i, count;
+
+ NS_DURING
+ {
+ count = [_fontDescriptors count];
+
+ // Process each font descriptor
+ for (i = 0; i < count; i++)
+ {
+ NSFontDescriptor *descriptor = [_fontDescriptors objectAtIndex: i];
+ NSError *fontError = nil;
+
+ // Update progress description
+ NSString *fontName = [descriptor objectForKey: NSFontNameAttribute];
+ if (fontName == nil)
+ {
+ fontName = @"Unknown";
+ }
+ NSString *progressDescription = [NSString stringWithFormat: @"Processing font: %@", fontName];
+ [self _updateProgressWithDescription: progressDescription];
+
+ // Check if progress was cancelled
+ if ([_progress isCancelled])
+ {
+ success = NO;
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObject: @"Font asset download was cancelled"
+ forKey: NSLocalizedDescriptionKey];
+ downloadError = [NSError errorWithDomain: @"NSFontAssetRequestErrorDomain"
+ code: -1002
+ userInfo: userInfo];
+ break;
+ }
+
+ // Use the downloader to download and install the font
+ if ([_downloader downloadAndInstallFontWithDescriptor: descriptor error: &fontError])
+ {
+ // Successfully downloaded and installed
+ [_downloadedFontDescriptors addObject: descriptor];
+ NSLog(@"Successfully installed font: %@", fontName);
+ }
+ else
+ {
+ NSLog(@"Failed to download/install font %@: %@", fontName, [fontError localizedDescription]);
+ }
+
+ // Update progress
+ [_progress setCompletedUnitCount: i + 1];
+ }
+ if (success)
+ {
+ [self _updateProgressWithDescription: @"Font download and installation completed"];
+ }
+ }
+ NS_HANDLER
+ {
+ success = NO;
+ NSString *reason = [localException reason];
+ if (reason == nil)
+ {
+ reason = @"Unknown error";
+ }
+ NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"Font asset download failed", NSLocalizedDescriptionKey,
+ reason, NSLocalizedFailureReasonErrorKey,
+ nil];
+ downloadError = [NSError errorWithDomain: @"NSFontAssetRequestErrorDomain"
+ code: -1003
+ userInfo: userInfo];
+ }
+ NS_ENDHANDLER
+
+ [self _completeDownloadWithError: downloadError
+ completionHandler: completionHandler];
+}
+
+- (void) _updateProgressWithDescription: (NSString *)description
+{
+ [_progress setLocalizedAdditionalDescription: description];
+}
+
+- (void) _completeDownloadWithError: (NSError *)downloadError
+ completionHandler: (GSFontAssetCompletionHandler)completionHandler
+{
+ _downloadInProgress = NO;
+
+ if (downloadError == nil)
+ {
+ // Success case - no error
+ CALL_NON_NULL_BLOCK(completionHandler, nil);
+ }
+ else
+ {
+ // Error case
+ CALL_NON_NULL_BLOCK(completionHandler, downloadError);
+ }
+}
+
+// Additional helper methods that could be useful
+
+- (NSArray *) fontDescriptors
+{
+ return AUTORELEASE([_fontDescriptors copy]);
+}
+
+- (NSFontAssetRequestOptions) options
+{
+ return _options;
+}
+
+- (BOOL) isDownloadInProgress
+{
+ return _downloadInProgress;
+}
+
+@end
diff --git a/Source/NSFontManager.m b/Source/NSFontManager.m
index e8e6f91ad..62d41a0dd 100644
--- a/Source/NSFontManager.m
+++ b/Source/NSFontManager.m
@@ -7,7 +7,7 @@
Author: Fred Kiefer
Date: January 2000
Almost complete rewrite.
-
+
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
@@ -22,10 +22,10 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
- If not, see or write to the
- Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
-*/
+*/
#include "config.h"
#import
@@ -43,6 +43,8 @@
#import "AppKit/NSMenuItem.h"
#import "GNUstepGUI/GSFontInfo.h"
+/* Notification names */
+NSString * const GSFontManagerAvailableFontsDidChangeNotification = @"GSFontManagerAvailableFontsDidChangeNotification";
/*
* Class variables
@@ -76,7 +78,7 @@ + (void) initialize
implementing your own class ( a subclass of NSFontManager )
This class is init into +sharedFontManager
See Also: +sharedFontManager
- */
+*/
+ (void) setFontManagerFactory: (Class)aClass
{
fontManagerClass = aClass;
@@ -85,7 +87,7 @@ + (void) setFontManagerFactory: (Class)aClass
/**Sets the class used to create a NSFontPanel. If you want to use
a custom class it should be NSFontPanel subclass
See Also: -fontPanel:
- */
+*/
+ (void) setFontPanelFactory: (Class)aClass
{
fontPanelClass = aClass;
@@ -146,6 +148,15 @@ - (NSArray*) availableFontFamilies
return [_fontEnumerator availableFontFamilies];
}
+- (void) refreshAvailableFonts
+{
+ [_fontEnumerator refreshFontCache];
+
+ // Post notification that available fonts have changed
+ [[NSNotificationCenter defaultCenter] postNotificationName: GSFontManagerAvailableFontsDidChangeNotification
+ object: self];
+}
+
- (NSArray*) availableFontNamesWithTraits: (NSFontTraitMask)fontTraitMask
{
unsigned int i, j;
@@ -160,18 +171,18 @@ - (NSArray*) availableFontNamesWithTraits: (NSFontTraitMask)fontTraitMask
for (i = 0; i < [fontFamilies count]; i++)
{
- NSArray *fontDefs = [self availableMembersOfFontFamily:
- [fontFamilies objectAtIndex: i]];
-
+ NSArray *fontDefs = [self availableMembersOfFontFamily:
+ [fontFamilies objectAtIndex: i]];
+
for (j = 0; j < [fontDefs count]; j++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: j];
-
- traits = [[fontDef objectAtIndex: 3] unsignedIntValue];
- // Check if the font has exactly the given mask
- if (traits == fontTraitMask)
- [fontNames addObject: [fontDef objectAtIndex: 0]];
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: j];
+
+ traits = [[fontDef objectAtIndex: 3] unsignedIntValue];
+ // Check if the font has exactly the given mask
+ if (traits == fontTraitMask)
+ [fontNames addObject: [fontDef objectAtIndex: 0]];
+ }
}
return fontNames;
@@ -193,8 +204,8 @@ - (NSArray *) matchingFontDescriptorsFor: (NSDictionary *)attributes
return [_fontEnumerator matchingFontDescriptorsFor: attributes];
}
-- (NSString*) localizedNameForFamily: (NSString*)family
- face: (NSString*)face
+- (NSString*) localizedNameForFamily: (NSString*)family
+ face: (NSString*)face
{
// TODO
return [NSString stringWithFormat: @"%@-%@", family, face];
@@ -203,19 +214,19 @@ - (NSString*) localizedNameForFamily: (NSString*)family
/**
*/
- (void) setSelectedFont: (NSFont*)fontObject
- isMultiple: (BOOL)flag
+ isMultiple: (BOOL)flag
{
if (_selectedFont == fontObject)
{
if (flag != _multiple)
- {
- _multiple = flag;
- // The panel should also know if multiple changed
- if (fontPanel != nil)
- {
- [fontPanel setPanelFont: fontObject isMultiple: flag];
- }
- }
+ {
+ _multiple = flag;
+ // The panel should also know if multiple changed
+ if (fontPanel != nil)
+ {
+ [fontPanel setPanelFont: fontObject isMultiple: flag];
+ }
+ }
return;
}
@@ -227,7 +238,7 @@ - (void) setSelectedFont: (NSFont*)fontObject
{
[fontPanel setPanelFont: fontObject isMultiple: flag];
}
-
+
if (_fontMenu != nil)
{
id menuItem;
@@ -238,42 +249,42 @@ - (void) setSelectedFont: (NSFont*)fontObject
* We keep the tag, to mark the item
*/
if (trait & NSItalicFontMask)
- {
- menuItem = [_fontMenu itemWithTag: NSItalicFontMask];
- if (menuItem != nil)
- {
- [menuItem setTitle: @"Unitalic"];
- [menuItem setAction: @selector(removeFontTrait:)];
- }
- }
+ {
+ menuItem = [_fontMenu itemWithTag: NSItalicFontMask];
+ if (menuItem != nil)
+ {
+ [menuItem setTitle: @"Unitalic"];
+ [menuItem setAction: @selector(removeFontTrait:)];
+ }
+ }
else
- {
- menuItem = [_fontMenu itemWithTag: NSItalicFontMask];
- if (menuItem != nil)
- {
- [menuItem setTitle: @"Italic"];
- [menuItem setAction: @selector(addFontTrait:)];
- }
- }
+ {
+ menuItem = [_fontMenu itemWithTag: NSItalicFontMask];
+ if (menuItem != nil)
+ {
+ [menuItem setTitle: @"Italic"];
+ [menuItem setAction: @selector(addFontTrait:)];
+ }
+ }
if (trait & NSBoldFontMask)
- {
- menuItem = [_fontMenu itemWithTag: NSBoldFontMask];
- if (menuItem != nil)
- {
- [menuItem setTitle: @"Unbold"];
- [menuItem setAction: @selector(removeFontTrait:)];
- }
- }
+ {
+ menuItem = [_fontMenu itemWithTag: NSBoldFontMask];
+ if (menuItem != nil)
+ {
+ [menuItem setTitle: @"Unbold"];
+ [menuItem setAction: @selector(removeFontTrait:)];
+ }
+ }
else
- {
- menuItem = [_fontMenu itemWithTag: NSBoldFontMask];
- if (menuItem != nil)
- {
- [menuItem setTitle: @"Bold"];
- [menuItem setAction: @selector(addFontTrait:)];
- }
- }
+ {
+ menuItem = [_fontMenu itemWithTag: NSBoldFontMask];
+ if (menuItem != nil)
+ {
+ [menuItem setTitle: @"Bold"];
+ [menuItem setAction: @selector(addFontTrait:)];
+ }
+ }
// TODO Update the rest of the font menu to reflect this font
}
@@ -309,9 +320,9 @@ - (void) addFontTrait: (id)sender
NSFont *newFont = [self convertFont: _selectedFont];
if (newFont != nil)
- {
- [self setSelectedFont: newFont isMultiple: _multiple];
- }
+ {
+ [self setSelectedFont: newFont isMultiple: _multiple];
+ }
}
}
@@ -327,9 +338,9 @@ - (void) removeFontTrait: (id)sender
NSFont *newFont = [self convertFont: _selectedFont];
if (newFont != nil)
- {
- [self setSelectedFont: newFont isMultiple: _multiple];
- }
+ {
+ [self setSelectedFont: newFont isMultiple: _multiple];
+ }
}
}
@@ -344,9 +355,9 @@ - (void) modifyFont: (id)sender
NSFont *newFont = [self convertFont: _selectedFont];
if (newFont != nil)
- {
- [self setSelectedFont: newFont isMultiple: _multiple];
- }
+ {
+ [self setSelectedFont: newFont isMultiple: _multiple];
+ }
}
}
@@ -361,15 +372,15 @@ - (void) modifyFontViaPanel: (id)sender
NSFont *newFont = [self convertFont: _selectedFont];
if (newFont != nil)
- {
- [self setSelectedFont: newFont isMultiple: _multiple];
- }
+ {
+ [self setSelectedFont: newFont isMultiple: _multiple];
+ }
}
}
/**Converts the NSFont fontObject according to user changes
in the Font panel or the font menu
- See Also: -addFontTrait: -removeFontTrait: -modifyFont:
+
See Also: -addFontTrait: -removeFontTrait: -modifyFont:
-modifyFontViaPanel: -convertFont:toHaveTrait: -convertFont:toNotHaveTrait:
-convertFont:toSize: -convertFont:toFamily: -convertWeight:ofFont:
*/
@@ -378,60 +389,60 @@ - (NSFont*) convertFont: (NSFont*)fontObject
NSFont *newFont = fontObject;
int i;
float size;
- float sizes[] = {4.0, 6.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
- 14.0, 16.0, 18.0, 24.0, 36.0, 48.0, 64.0};
+ float sizes[] = {4.0, 6.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
+ 14.0, 16.0, 18.0, 24.0, 36.0, 48.0, 64.0};
if (fontObject == nil)
return nil;
switch (_storedTag)
{
- case NSNoFontChangeAction:
- break;
- case NSViaPanelFontAction:
- if (fontPanel != nil)
- {
- newFont = [fontPanel panelConvertFont: fontObject];
- }
- break;
- case NSAddTraitFontAction:
- newFont = [self convertFont: fontObject toHaveTrait: _trait];
- break;
- case NSRemoveTraitFontAction:
- newFont = [self convertFont: fontObject toNotHaveTrait: _trait];
- break;
- case NSSizeUpFontAction:
- size = [fontObject pointSize];
- for (i = 0; i < sizeof(sizes)/sizeof(float); i++)
- {
- if (sizes[i] > size)
- {
- size = sizes[i];
- break;
- }
- }
- newFont = [self convertFont: fontObject
- toSize: size];
- break;
- case NSSizeDownFontAction:
- size = [fontObject pointSize];
- for (i = sizeof(sizes)/sizeof(float) -1; i >= 0; i--)
- {
- if (sizes[i] < size)
- {
- size = sizes[i];
- break;
- }
- }
- newFont = [self convertFont: fontObject
- toSize: size];
- break;
- case NSHeavierFontAction:
- newFont = [self convertWeight: YES ofFont: fontObject];
- break;
- case NSLighterFontAction:
- newFont = [self convertWeight: NO ofFont: fontObject];
- break;
+ case NSNoFontChangeAction:
+ break;
+ case NSViaPanelFontAction:
+ if (fontPanel != nil)
+ {
+ newFont = [fontPanel panelConvertFont: fontObject];
+ }
+ break;
+ case NSAddTraitFontAction:
+ newFont = [self convertFont: fontObject toHaveTrait: _trait];
+ break;
+ case NSRemoveTraitFontAction:
+ newFont = [self convertFont: fontObject toNotHaveTrait: _trait];
+ break;
+ case NSSizeUpFontAction:
+ size = [fontObject pointSize];
+ for (i = 0; i < sizeof(sizes)/sizeof(float); i++)
+ {
+ if (sizes[i] > size)
+ {
+ size = sizes[i];
+ break;
+ }
+ }
+ newFont = [self convertFont: fontObject
+ toSize: size];
+ break;
+ case NSSizeDownFontAction:
+ size = [fontObject pointSize];
+ for (i = sizeof(sizes)/sizeof(float) -1; i >= 0; i--)
+ {
+ if (sizes[i] < size)
+ {
+ size = sizes[i];
+ break;
+ }
+ }
+ newFont = [self convertFont: fontObject
+ toSize: size];
+ break;
+ case NSHeavierFontAction:
+ newFont = [self convertWeight: YES ofFont: fontObject];
+ break;
+ case NSLighterFontAction:
+ newFont = [self convertWeight: NO ofFont: fontObject];
+ break;
}
return newFont;
@@ -439,7 +450,7 @@ - (NSFont*) convertFont: (NSFont*)fontObject
- (NSFont*) convertFont: (NSFont*)fontObject
- toFamily: (NSString*)family
+ toFamily: (NSString*)family
{
if ([family isEqualToString: [fontObject familyName]])
{
@@ -454,19 +465,19 @@ - (NSFont*) convertFont: (NSFont*)fontObject
int weight = [self weightOfFont: fontObject];
float size = [fontObject pointSize];
- newFont = [self fontWithFamily: family
- traits: trait
- weight: weight
- size: size];
+ newFont = [self fontWithFamily: family
+ traits: trait
+ weight: weight
+ size: size];
if (newFont == nil)
- return fontObject;
- else
- return newFont;
+ return fontObject;
+ else
+ return newFont;
}
}
- (NSFont*) convertFont: (NSFont*)fontObject
- toFace: (NSString*)typeface
+ toFace: (NSString*)typeface
{
NSFont *newFont;
@@ -479,12 +490,12 @@ - (NSFont*) convertFont: (NSFont*)fontObject
newFont = [NSFont fontWithName: typeface size: [fontObject pointSize]];
if (newFont == nil)
return fontObject;
- else
+ else
return newFont;
}
- (NSFont*) convertFont: (NSFont*)fontObject
- toHaveTrait: (NSFontTraitMask)trait
+ toHaveTrait: (NSFontTraitMask)trait
{
NSFontTraitMask t = [self traitsOfFont: fontObject];
@@ -503,42 +514,42 @@ - (NSFont*) convertFont: (NSFont*)fontObject
NSString *family = [fontObject familyName];
if (trait & NSBoldFontMask)
- {
- // We cannot reuse the weight in a bold
- weight = 9;
- t = t & ~NSUnboldFontMask;
- }
+ {
+ // We cannot reuse the weight in a bold
+ weight = 9;
+ t = t & ~NSUnboldFontMask;
+ }
else if (trait & NSUnboldFontMask)
- {
- // We cannot reuse the weight in an unbold
- weight = 5;
- t = t & ~NSBoldFontMask;
- }
+ {
+ // We cannot reuse the weight in an unbold
+ weight = 5;
+ t = t & ~NSBoldFontMask;
+ }
if (trait == NSItalicFontMask)
- {
- t = t & ~NSUnitalicFontMask;
- }
+ {
+ t = t & ~NSUnitalicFontMask;
+ }
else if (trait & NSUnitalicFontMask)
- {
- t = t & ~NSItalicFontMask;
- }
+ {
+ t = t & ~NSItalicFontMask;
+ }
t = t | trait;
- newFont = [self fontWithFamily: family
- traits: t
- weight: weight
- size: size];
+ newFont = [self fontWithFamily: family
+ traits: t
+ weight: weight
+ size: size];
if (newFont == nil)
- return fontObject;
- else
- return newFont;
+ return fontObject;
+ else
+ return newFont;
}
}
- (NSFont*) convertFont: (NSFont*)fontObject
- toNotHaveTrait: (NSFontTraitMask)trait
+ toNotHaveTrait: (NSFontTraitMask)trait
{
NSFontTraitMask t = [self traitsOfFont: fontObject];
@@ -557,40 +568,40 @@ - (NSFont*) convertFont: (NSFont*)fontObject
NSString *family = [fontObject familyName];
if (trait & NSBoldFontMask)
- {
- // We cannot reuse the weight in an unbold
- weight = 5;
- t = (t | NSUnboldFontMask);
- }
+ {
+ // We cannot reuse the weight in an unbold
+ weight = 5;
+ t = (t | NSUnboldFontMask);
+ }
else if (trait & NSUnboldFontMask)
- {
- // We cannot reuse the weight in a bold
- weight = 9;
- t = (t | NSBoldFontMask);
- }
+ {
+ // We cannot reuse the weight in a bold
+ weight = 9;
+ t = (t | NSBoldFontMask);
+ }
if (trait & NSItalicFontMask)
- {
- t = (t | NSUnitalicFontMask);
- }
+ {
+ t = (t | NSUnitalicFontMask);
+ }
else if (trait & NSUnitalicFontMask)
- {
- t = (t | NSItalicFontMask);
- }
-
+ {
+ t = (t | NSItalicFontMask);
+ }
+
t &= ~trait;
- newFont = [self fontWithFamily: family
- traits: t
- weight: weight
- size: size];
+ newFont = [self fontWithFamily: family
+ traits: t
+ weight: weight
+ size: size];
if (newFont == nil)
- return fontObject;
- else
- return newFont;
+ return fontObject;
+ else
+ return newFont;
}
}
- (NSFont*) convertFont: (NSFont*)fontObject
- toSize: (float)size
+ toSize: (float)size
{
if ([fontObject pointSize] == size)
{
@@ -602,17 +613,17 @@ - (NSFont*) convertFont: (NSFont*)fontObject
// Else convert it
NSFont *newFont;
- newFont = [NSFont fontWithName: [fontObject fontName]
- size: size];
+ newFont = [NSFont fontWithName: [fontObject fontName]
+ size: size];
if (newFont == nil)
- return fontObject;
- else
- return newFont;
+ return fontObject;
+ else
+ return newFont;
}
}
- (NSFont*) convertWeight: (BOOL)upFlag
- ofFont: (NSFont*)fontObject
+ ofFont: (NSFont*)fontObject
{
NSFont *newFont = nil;
NSString *fontName = nil;
@@ -632,36 +643,36 @@ - (NSFont*) convertWeight: (BOOL)upFlag
int next_w = 15;
for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- int w1 = [[fontDef objectAtIndex: 2] intValue];
-
- if (w1 > w && w1 < next_w &&
- [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
- {
- next_w = w1;
- fontName = [fontDef objectAtIndex: 0];
- }
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ int w1 = [[fontDef objectAtIndex: 2] intValue];
+
+ if (w1 > w && w1 < next_w &&
+ [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
+ {
+ next_w = w1;
+ fontName = [fontDef objectAtIndex: 0];
+ }
+ }
if (fontName == nil)
- {
- // Not found, try again with changed trait
- trait |= NSBoldFontMask;
-
- for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- int w1 = [[fontDef objectAtIndex: 2] intValue];
-
- if (w1 > w && w1 < next_w &&
- [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
- {
- next_w = w1;
- fontName = [fontDef objectAtIndex: 0];
- }
- }
- }
+ {
+ // Not found, try again with changed trait
+ trait |= NSBoldFontMask;
+
+ for (i = 0; i < [fontDefs count]; i++)
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ int w1 = [[fontDef objectAtIndex: 2] intValue];
+
+ if (w1 > w && w1 < next_w &&
+ [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
+ {
+ next_w = w1;
+ fontName = [fontDef objectAtIndex: 0];
+ }
+ }
+ }
}
else
{
@@ -669,46 +680,46 @@ - (NSFont*) convertWeight: (BOOL)upFlag
int next_w = 0;
for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- int w1 = [[fontDef objectAtIndex: 2] intValue];
-
- if (w1 < w && w1 > next_w
- && [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
- {
- next_w = w1;
- fontName = [fontDef objectAtIndex: 0];
- }
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ int w1 = [[fontDef objectAtIndex: 2] intValue];
+
+ if (w1 < w && w1 > next_w
+ && [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
+ {
+ next_w = w1;
+ fontName = [fontDef objectAtIndex: 0];
+ }
+ }
if (fontName == nil)
- {
- // Not found, try again with changed trait
- trait &= ~NSBoldFontMask;
-
- for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- int w1 = [[fontDef objectAtIndex: 2] intValue];
-
- if (w1 < w && w1 > next_w
- && [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
- {
- next_w = w1;
- fontName = [fontDef objectAtIndex: 0];
- }
- }
- }
+ {
+ // Not found, try again with changed trait
+ trait &= ~NSBoldFontMask;
+
+ for (i = 0; i < [fontDefs count]; i++)
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ int w1 = [[fontDef objectAtIndex: 2] intValue];
+
+ if (w1 < w && w1 > next_w
+ && [[fontDef objectAtIndex: 3] unsignedIntValue] == trait)
+ {
+ next_w = w1;
+ fontName = [fontDef objectAtIndex: 0];
+ }
+ }
+ }
}
if (fontName != nil)
{
newFont = [NSFont fontWithName: fontName
- size: size];
+ size: size];
}
if (newFont == nil)
return fontObject;
- else
+ else
return newFont;
}
@@ -716,9 +727,9 @@ - (NSFont*) convertWeight: (BOOL)upFlag
* Getting a font
*/
- (NSFont*) fontWithFamily: (NSString*)family
- traits: (NSFontTraitMask)traits
- weight: (int)weight
- size: (float)size
+ traits: (NSFontTraitMask)traits
+ weight: (int)weight
+ size: (float)size
{
NSArray *fontDefs = [self availableMembersOfFontFamily: family];
unsigned int i;
@@ -730,78 +741,78 @@ - (NSFont*) fontWithFamily: (NSString*)family
{
NSArray *fontDef = [fontDefs objectAtIndex: i];
- //NSLog(@"Testing font %@: %i: %i", [fontDef objectAtIndex: 0],
- // [[fontDef objectAtIndex: 2] intValue],
- // [[fontDef objectAtIndex: 3] unsignedIntValue]);
+ //NSLog(@"Testing font %@: %i: %i", [fontDef objectAtIndex: 0],
+ // [[fontDef objectAtIndex: 2] intValue],
+ // [[fontDef objectAtIndex: 3] unsignedIntValue]);
if (([[fontDef objectAtIndex: 2] intValue] == weight) &&
- ([[fontDef objectAtIndex: 3] unsignedIntValue] == traits))
- {
- //NSLog(@"Found font");
- return [NSFont fontWithName: [fontDef objectAtIndex: 0]
- size: size];
- }
+ ([[fontDef objectAtIndex: 3] unsignedIntValue] == traits))
+ {
+ //NSLog(@"Found font");
+ return [NSFont fontWithName: [fontDef objectAtIndex: 0]
+ size: size];
+ }
}
// Try to find something close by ignoring some trait flags
traits &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
- | NSUnitalicFontMask | NSUnboldFontMask);
+ | NSUnitalicFontMask | NSUnboldFontMask);
for (i = 0; i < [fontDefs count]; i++)
{
NSArray *fontDef = [fontDefs objectAtIndex: i];
NSFontTraitMask t = [[fontDef objectAtIndex: 3] unsignedIntValue];
t &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
- | NSUnitalicFontMask | NSUnboldFontMask);
+ | NSUnitalicFontMask | NSUnboldFontMask);
if (([[fontDef objectAtIndex: 2] intValue] == weight) &&
- (t == traits))
- {
- //NSLog(@"Found font");
- return [NSFont fontWithName: [fontDef objectAtIndex: 0]
- size: size];
- }
+ (t == traits))
+ {
+ //NSLog(@"Found font");
+ return [NSFont fontWithName: [fontDef objectAtIndex: 0]
+ size: size];
+ }
}
if (traits & NSBoldFontMask)
{
//NSLog(@"Trying ignore weights for bold font");
for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- NSFontTraitMask t = [[fontDef objectAtIndex: 3] unsignedIntValue];
-
- t &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
- | NSUnitalicFontMask | NSUnboldFontMask);
- if (t == traits)
- {
- //NSLog(@"Found font");
- return [NSFont fontWithName: [fontDef objectAtIndex: 0]
- size: size];
- }
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ NSFontTraitMask t = [[fontDef objectAtIndex: 3] unsignedIntValue];
+
+ t &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
+ | NSUnitalicFontMask | NSUnboldFontMask);
+ if (t == traits)
+ {
+ //NSLog(@"Found font");
+ return [NSFont fontWithName: [fontDef objectAtIndex: 0]
+ size: size];
+ }
+ }
}
-
+
if (weight == 5 || weight == 6)
{
//NSLog(@"Trying alternate non-bold weights for non-bold font");
for (i = 0; i < [fontDefs count]; i++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: i];
- NSFontTraitMask t = [[fontDef objectAtIndex: 3] unsignedIntValue];
-
- t &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
- | NSUnitalicFontMask | NSUnboldFontMask);
- if ((([[fontDef objectAtIndex: 2] intValue] == 5) ||
- ([[fontDef objectAtIndex: 2] intValue] == 6)) &&
- (t == traits))
- {
- //NSLog(@"Found font");
- return [NSFont fontWithName: [fontDef objectAtIndex: 0]
- size: size];
- }
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: i];
+ NSFontTraitMask t = [[fontDef objectAtIndex: 3] unsignedIntValue];
+
+ t &= ~(NSNonStandardCharacterSetFontMask | NSFixedPitchFontMask
+ | NSUnitalicFontMask | NSUnboldFontMask);
+ if ((([[fontDef objectAtIndex: 2] intValue] == 5) ||
+ ([[fontDef objectAtIndex: 2] intValue] == 6)) &&
+ (t == traits))
+ {
+ //NSLog(@"Found font");
+ return [NSFont fontWithName: [fontDef objectAtIndex: 0]
+ size: size];
+ }
+ }
}
- //NSLog(@"Didnt find font");
+ //NSLog(@"Didnt find font");
return nil;
}
@@ -820,42 +831,42 @@ - (int) weightOfFont: (NSFont*)fontObject
return [[fontObject fontInfo] weight];
}
-- (BOOL) fontNamed: (NSString*)typeface
- hasTraits: (NSFontTraitMask)fontTraitMask
+- (BOOL) fontNamed: (NSString*)typeface
+ hasTraits: (NSFontTraitMask)fontTraitMask
{
- // TODO: This method is implemented very slow, but I dont
+ // TODO: This method is implemented very slow, but I dont
// see any use for it, so why change it?
unsigned int i, j;
NSArray *fontFamilies = [self availableFontFamilies];
NSFontTraitMask traits;
-
+
for (i = 0; i < [fontFamilies count]; i++)
{
- NSArray *fontDefs = [self availableMembersOfFontFamily:
- [fontFamilies objectAtIndex: i]];
-
+ NSArray *fontDefs = [self availableMembersOfFontFamily:
+ [fontFamilies objectAtIndex: i]];
+
for (j = 0; j < [fontDefs count]; j++)
- {
- NSArray *fontDef = [fontDefs objectAtIndex: j];
-
- if ([[fontDef objectAtIndex: 0] isEqualToString: typeface])
- {
- traits = [[fontDef objectAtIndex: 3] unsignedIntValue];
- // FIXME: This is not exactly the right condition
- if ((traits & fontTraitMask) == fontTraitMask)
- {
- return YES;
- }
- else
- return NO;
- }
- }
+ {
+ NSArray *fontDef = [fontDefs objectAtIndex: j];
+
+ if ([[fontDef objectAtIndex: 0] isEqualToString: typeface])
+ {
+ traits = [[fontDef objectAtIndex: 3] unsignedIntValue];
+ // FIXME: This is not exactly the right condition
+ if ((traits & fontTraitMask) == fontTraitMask)
+ {
+ return YES;
+ }
+ else
+ return NO;
+ }
+ }
}
-
+
return NO;
}
-/**Returns whether the NSFontPanel is enabled ( if exists )
+/**Returns whether the NSFontPanel is enabled ( if exists )
*/
- (BOOL) isEnabled
{
@@ -867,7 +878,7 @@ - (BOOL) isEnabled
return NO;
}
-/**Enables/disables the NSFontPanel and the font menu ( if they exist )
+/**Enables/disables the NSFontPanel and the font menu ( if they exist )
See Also: -isEnabled
*/
- (void) setEnabled: (BOOL)flag
@@ -877,16 +888,16 @@ - (void) setEnabled: (BOOL)flag
if (_fontMenu != nil)
{
for (i = 0; i < [_fontMenu numberOfItems]; i++)
- {
- [[_fontMenu itemAtIndex: i] setEnabled: flag];
- }
+ {
+ [[_fontMenu itemAtIndex: i] setEnabled: flag];
+ }
}
if (fontPanel != nil)
[fontPanel setEnabled: flag];
}
-/**Returns the font menu, creates it (if needed ) if create
+/**
Returns the font menu, creates it (if needed ) if create
is YES.
See Also: -setFontMenu:
*/
- (NSMenu*) fontMenu: (BOOL)create
@@ -894,57 +905,57 @@ - (NSMenu*) fontMenu: (BOOL)create
if (create && _fontMenu == nil)
{
id menuItem;
-
- // As the font menu is stored in a instance variable we
+
+ // As the font menu is stored in a instance variable we
// dont autorelease it
_fontMenu = [NSMenu new];
[_fontMenu setTitle: @"Font Menu"];
// First an entry to start the font panel
menuItem = [_fontMenu addItemWithTitle: @"Font Panel"
- action: @selector(orderFrontFontPanel:)
- keyEquivalent: @"t"];
+ action: @selector(orderFrontFontPanel:)
+ keyEquivalent: @"t"];
[menuItem setTarget: self];
// Entry for italic
menuItem = [_fontMenu addItemWithTitle: @"Italic"
- action: @selector(addFontTrait:)
- keyEquivalent: @"i"];
+ action: @selector(addFontTrait:)
+ keyEquivalent: @"i"];
[menuItem setTag: NSItalicFontMask];
[menuItem setTarget: self];
// Entry for bold
menuItem = [_fontMenu addItemWithTitle: @"Bold"
- action: @selector(addFontTrait:)
- keyEquivalent: @"b"];
+ action: @selector(addFontTrait:)
+ keyEquivalent: @"b"];
[menuItem setTag: NSBoldFontMask];
[menuItem setTarget: self];
// Entry to increase weight
menuItem = [_fontMenu addItemWithTitle: @"Heavier"
- action: @selector(modifyFont:)
- keyEquivalent: @""];
+ action: @selector(modifyFont:)
+ keyEquivalent: @""];
[menuItem setTag: NSHeavierFontAction];
[menuItem setTarget: self];
-
+
// Entry to decrease weight
menuItem = [_fontMenu addItemWithTitle: @"Lighter"
- action: @selector(modifyFont:)
- keyEquivalent: @""];
+ action: @selector(modifyFont:)
+ keyEquivalent: @""];
[menuItem setTag: NSLighterFontAction];
[menuItem setTarget: self];
-
+
// Entry to increase size
menuItem = [_fontMenu addItemWithTitle: @"Larger"
- action: @selector(modifyFont:)
- keyEquivalent: @"+"];
+ action: @selector(modifyFont:)
+ keyEquivalent: @"+"];
[menuItem setTag: NSSizeUpFontAction];
[menuItem setTarget: self];
// Entry to decrease size
menuItem = [_fontMenu addItemWithTitle: @"Smaller"
- action: @selector(modifyFont:)
- keyEquivalent: @"-"];
+ action: @selector(modifyFont:)
+ keyEquivalent: @"-"];
[menuItem setTag: NSSizeDownFontAction];
[menuItem setTarget: self];
}
@@ -956,7 +967,7 @@ - (NSMenu*) fontMenu: (BOOL)create
*/
- (void) setFontMenu: (NSMenu*)newMenu
{
- ASSIGN(_fontMenu, newMenu);
+ ASSIGN(_fontMenu, newMenu);
}
/**Returns the NSFontPanel, creates it ( if needed ) if create
@@ -1053,8 +1064,8 @@ - (NSArray *) collectionNames
return [_collections allKeys];
}
-- (void) addFontDescriptors: (NSArray *)descriptors
- toCollection: (NSString *)collection
+- (void) addFontDescriptors: (NSArray *)descriptors
+ toCollection: (NSString *)collection
{
NSMutableArray *a = [_collections objectForKey: collection];
@@ -1064,8 +1075,8 @@ - (void) addFontDescriptors: (NSArray *)descriptors
}
}
-- (void) removeFontDescriptor: (NSFontDescriptor *)descriptor
- fromCollection: (NSString *)collection
+- (void) removeFontDescriptor: (NSFontDescriptor *)descriptor
+ fromCollection: (NSString *)collection
{
NSMutableArray *a = [_collections objectForKey: collection];
@@ -1085,8 +1096,8 @@ - (NSDictionary *) convertAttributes: (NSDictionary *)attributes
NSMutableDictionary *newAttributes;
int i;
float size;
- float sizes[] = {4.0, 6.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
- 14.0, 16.0, 18.0, 24.0, 36.0, 48.0, 64.0};
+ float sizes[] = {4.0, 6.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0,
+ 14.0, 16.0, 18.0, 24.0, 36.0, 48.0, 64.0};
NSFontTraitMask t;
if (attributes == nil)
@@ -1095,96 +1106,96 @@ - (NSDictionary *) convertAttributes: (NSDictionary *)attributes
newAttributes = AUTORELEASE([attributes mutableCopy]);
switch (_storedTag)
{
- case NSNoFontChangeAction:
- break;
- case NSViaPanelFontAction:
- // FIXME
- break;
- case NSAddTraitFontAction:
- t = [[attributes objectForKey: NSFontSymbolicTrait] unsignedIntValue];
-
- if (t & _trait)
- {
- return newAttributes;
- }
- else if (_trait == NSUnboldFontMask)
- {
- t &= ~NSBoldFontMask;
- }
- else if (_trait == NSUnitalicFontMask)
- {
- t &= ~NSItalicFontMask;
- }
- else
- {
- t &= _trait;
- // FIXME: What about weight for NSBoldFontMask?
- }
- [newAttributes setObject: [NSNumber numberWithUnsignedInt: t]
- forKey: NSFontSymbolicTrait];
- break;
- case NSRemoveTraitFontAction:
- t = [[attributes objectForKey: NSFontSymbolicTrait] unsignedIntValue];
-
- if (!(t & _trait))
- {
- return newAttributes;
- }
- else if (_trait == NSUnboldFontMask)
- {
- t = (t | NSBoldFontMask) & ~NSUnboldFontMask;
- }
- else if (_trait == NSUnitalicFontMask)
- {
- t = (t | NSItalicFontMask) & ~NSUnitalicFontMask;
- }
- else
- {
- t &= ~_trait;
- // FIXME: What about weight for NSBoldFontMask?
- }
- [newAttributes setObject: [NSNumber numberWithUnsignedInt: t]
- forKey: NSFontSymbolicTrait];
- break;
- case NSSizeUpFontAction:
- size = [[attributes objectForKey: NSFontSizeAttribute] floatValue];
- for (i = 0; i < sizeof(sizes)/sizeof(float); i++)
- {
- if (sizes[i] > size)
- {
- size = sizes[i];
- break;
- }
- }
- [newAttributes setObject: [NSString stringWithFormat: @"%f", size]
- forKey: NSFontSizeAttribute];
- break;
- case NSSizeDownFontAction:
- size = [[attributes objectForKey: NSFontSizeAttribute] floatValue];
- for (i = sizeof(sizes)/sizeof(float) -1; i >= 0; i--)
- {
- if (sizes[i] < size)
- {
- size = sizes[i];
- break;
- }
- }
- [newAttributes setObject: [NSString stringWithFormat: @"%f", size]
- forKey: NSFontSizeAttribute];
- break;
- case NSHeavierFontAction:
- // FIXME
- break;
- case NSLighterFontAction:
- // FIXME
- break;
+ case NSNoFontChangeAction:
+ break;
+ case NSViaPanelFontAction:
+ // FIXME
+ break;
+ case NSAddTraitFontAction:
+ t = [[attributes objectForKey: NSFontSymbolicTrait] unsignedIntValue];
+
+ if (t & _trait)
+ {
+ return newAttributes;
+ }
+ else if (_trait == NSUnboldFontMask)
+ {
+ t &= ~NSBoldFontMask;
+ }
+ else if (_trait == NSUnitalicFontMask)
+ {
+ t &= ~NSItalicFontMask;
+ }
+ else
+ {
+ t &= _trait;
+ // FIXME: What about weight for NSBoldFontMask?
+ }
+ [newAttributes setObject: [NSNumber numberWithUnsignedInt: t]
+ forKey: NSFontSymbolicTrait];
+ break;
+ case NSRemoveTraitFontAction:
+ t = [[attributes objectForKey: NSFontSymbolicTrait] unsignedIntValue];
+
+ if (!(t & _trait))
+ {
+ return newAttributes;
+ }
+ else if (_trait == NSUnboldFontMask)
+ {
+ t = (t | NSBoldFontMask) & ~NSUnboldFontMask;
+ }
+ else if (_trait == NSUnitalicFontMask)
+ {
+ t = (t | NSItalicFontMask) & ~NSUnitalicFontMask;
+ }
+ else
+ {
+ t &= ~_trait;
+ // FIXME: What about weight for NSBoldFontMask?
+ }
+ [newAttributes setObject: [NSNumber numberWithUnsignedInt: t]
+ forKey: NSFontSymbolicTrait];
+ break;
+ case NSSizeUpFontAction:
+ size = [[attributes objectForKey: NSFontSizeAttribute] floatValue];
+ for (i = 0; i < sizeof(sizes)/sizeof(float); i++)
+ {
+ if (sizes[i] > size)
+ {
+ size = sizes[i];
+ break;
+ }
+ }
+ [newAttributes setObject: [NSString stringWithFormat: @"%f", size]
+ forKey: NSFontSizeAttribute];
+ break;
+ case NSSizeDownFontAction:
+ size = [[attributes objectForKey: NSFontSizeAttribute] floatValue];
+ for (i = sizeof(sizes)/sizeof(float) -1; i >= 0; i--)
+ {
+ if (sizes[i] < size)
+ {
+ size = sizes[i];
+ break;
+ }
+ }
+ [newAttributes setObject: [NSString stringWithFormat: @"%f", size]
+ forKey: NSFontSizeAttribute];
+ break;
+ case NSHeavierFontAction:
+ // FIXME
+ break;
+ case NSLighterFontAction:
+ // FIXME
+ break;
}
return newAttributes;
}
-- (void) setSelectedAttributes: (NSDictionary *)attributes
- isMultiple: (BOOL)flag
+- (void) setSelectedAttributes: (NSDictionary *)attributes
+ isMultiple: (BOOL)flag
{
ASSIGN(_selectedAttributes, attributes);
_multiple = flag;
diff --git a/Source/NSFontPanel.m b/Source/NSFontPanel.m
index 3b29c87c5..5f531e918 100644
--- a/Source/NSFontPanel.m
+++ b/Source/NSFontPanel.m
@@ -8,7 +8,7 @@
Date: Febuary 2000
Author: Nicola Pero
Date: January 2001 - sizings and resizings
-
+
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
@@ -23,10 +23,10 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; see the file COPYING.LIB.
- If not, see or write to the
- Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ If not, see or write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
-*/
+*/
#include "config.h"
#import
@@ -56,7 +56,7 @@
static inline void _setFloatValue (NSTextField *field, float size)
{
- /* If casting size to int and then back to float we get no change,
+ /* If casting size to int and then back to float we get no change,
it means it's an integer */
if ((float)((int)size) == size)
{
@@ -133,7 +133,7 @@ - (void) resizeWithOldSuperviewSize: (NSSize)oldSize
if (_autoresizingMask == NSViewNotSizable)
return;
-
+
if (!NSEqualRects(NSZeroRect, _autoresizingFrameError))
{
newFrame.origin.x -= _autoresizingFrameError.origin.x;
@@ -216,7 +216,7 @@ + (void) initialize
}
}
-/** Creates ( if needed ) and returns the shared NSFontPanel.
+/** Creates ( if needed ) and returns the shared NSFontPanel.
*/
+ (NSFontPanel*) sharedFontPanel
{
@@ -246,11 +246,19 @@ - (id) init
[self reloadDefaultFontFamilies];
[self _getOriginalSize];
+ // Observe font manager notifications to refresh panel when fonts are updated
+ [[NSNotificationCenter defaultCenter] addObserver: self
+ selector: @selector(fontManagerDidChangeAvailableFonts:)
+ name: GSFontManagerAvailableFontsDidChangeNotification
+ object: nil];
+
return self;
}
- (void) dealloc
{
+ [[NSNotificationCenter defaultCenter] removeObserver: self];
+
RELEASE(_panelFont);
RELEASE(_familyList);
TEST_RELEASE(_faceList);
@@ -314,13 +322,19 @@ - (void) reloadDefaultFontFamilies
DESTROY(_familyList);
_familyList = familyList;
- // Reload the display.
+ // Reload the display.
[familyBrowser loadColumnZero];
// Reselect the current font. (Hopefully still there)
[self setPanelFont: [fm selectedFont]
isMultiple: [fm isMultiple]];
}
+- (void) fontManagerDidChangeAvailableFonts: (NSNotification *)notification
+{
+ // Reload the font families when the font cache is updated
+ [self reloadDefaultFontFamilies];
+}
+
- (void) setPanelFont: (NSFont *)fontObject
isMultiple: (BOOL)flag
{
@@ -330,7 +344,7 @@ - (void) setPanelFont: (NSFont *)fontObject
ASSIGN(_panelFont, fontObject);
_multiple = flag;
-
+
if (fontObject == nil)
{
return;
@@ -353,11 +367,11 @@ - (void) setPanelFont: (NSFont *)fontObject
NSBrowser *faceBrowser = [[self contentView] viewWithTag: NSFPFaceBrowser];
NSString *face = @"";
unsigned int i;
-
+
// Store style information for font
_traits = [fm traitsOfFont: fontObject];
_weight = [fm weightOfFont: fontObject];
-
+
// Select the row for the font family
for (i = 0; i < [_familyList count]; i++)
{
@@ -376,7 +390,7 @@ - (void) setPanelFont: (NSFont *)fontObject
// Select the row for the font face
for (i = 0; i < [_faceList count]; i++)
{
- if ([[[_faceList objectAtIndex: i] objectAtIndex: 0]
+ if ([[[_faceList objectAtIndex: i] objectAtIndex: 0]
isEqualToString: fontName])
break;
}
@@ -393,7 +407,7 @@ - (void) setPanelFont: (NSFont *)fontObject
// Use in preview
[previewArea setFont: fontObject];
if (_previewString == nil)
- {
+ {
[previewArea setStringValue: [NSString stringWithFormat: @"%@ %@ %d PT",
family, face, (int)size]];
}
@@ -408,13 +422,13 @@ - (NSFont *) panelConvertFont: (NSFont *)fontObject
if (_multiple)
{
- //TODO: We go over every item in the panel and check if a
+ //TODO: We go over every item in the panel and check if a
// value is selected. If so we send it on to the manager
// newFont = [fm convertFont: fontObject toHaveTrait: NSItalicFontMask];
NSLog(@"Multiple font conversion not implemented in NSFontPanel");
newFont = [self _fontForSelection: fontObject];
}
- else
+ else
{
newFont = [self _fontForSelection: fontObject];
}
@@ -423,7 +437,7 @@ - (NSFont *) panelConvertFont: (NSFont *)fontObject
{
newFont = fontObject;
}
-
+
return newFont;
}
@@ -454,7 +468,7 @@ - (void) setAccessoryView: (NSView*)aView
if (aView == _accessoryView)
return;
-
+
/* The following code is very tricky. Please think and test a lot
before changing it. */
@@ -469,8 +483,8 @@ - (void) setAccessoryView: (NSView*)aView
could be a problem. */
[self setMinSize: _originalMinSize];
- /* Resize the panel to the height without the accessory view.
- This must be done with the special care of not resizing
+ /* Resize the panel to the height without the accessory view.
+ This must be done with the special care of not resizing
the heights of the other views. */
addedHeight = accessoryViewFrame.size.height + (_SAVE_PANEL_Y_PAD * 2);
contentSize = [[self contentView] frame].size;
@@ -480,15 +494,15 @@ - (void) setAccessoryView: (NSView*)aView
[self setContentSize: contentSize];
[_topView setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable];
}
-
+
/* Resize the panel to its original size. This resizes freely the
heights of the views. NB: minSize *must* come first */
[self setMinSize: _originalMinSize];
[self setContentSize: _originalSize];
-
+
/* Set the new accessory view */
_accessoryView = aView;
-
+
/* If there is a new accessory view, plug it in */
if (_accessoryView != nil)
{
@@ -496,9 +510,9 @@ - (void) setAccessoryView: (NSView*)aView
* and its position relative to the bottom of the superview must not
* change - so its position rlative to the top must be changable. */
[_accessoryView setAutoresizingMask: NSViewMaxYMargin
- | ([_accessoryView autoresizingMask]
- & ~(NSViewHeightSizable | NSViewMinYMargin))];
-
+ | ([_accessoryView autoresizingMask]
+ & ~(NSViewHeightSizable | NSViewMinYMargin))];
+
/* Compute size taken by the new accessory view */
accessoryViewFrame = [_accessoryView frame];
addedHeight = accessoryViewFrame.size.height + (_SAVE_PANEL_Y_PAD * 2);
@@ -511,7 +525,7 @@ - (void) setAccessoryView: (NSView*)aView
{
contentSize.width = accessoryWidth;
}
-
+
/* Set new content size without resizing heights of topView, bottomView */
// Our views should resize horizontally if needed, but not vertically
[_topView setAutoresizingMask: NSViewWidthSizable | NSViewMinYMargin];
@@ -524,7 +538,7 @@ - (void) setAccessoryView: (NSView*)aView
contentMinSize.height += addedHeight;
// width is more delicate
tmpRect = NSMakeRect (0, 0, contentMinSize.width, contentMinSize.height);
- tmpRect = [NSWindow contentRectForFrameRect: tmpRect
+ tmpRect = [NSWindow contentRectForFrameRect: tmpRect
styleMask: [self styleMask]];
if (accessoryWidth > tmpRect.size.width)
{
@@ -541,7 +555,7 @@ - (void) setAccessoryView: (NSView*)aView
bottomFrame = [_bottomView frame];
/* AccessoryView */
- accessoryViewFrame.origin.x
+ accessoryViewFrame.origin.x
= (contentSize.width - accessoryViewFrame.size.width) / 2;
accessoryViewFrame.origin.y = NSMaxY (bottomFrame) + _SAVE_PANEL_Y_PAD;
[_accessoryView setFrameOrigin: accessoryViewFrame.origin];
@@ -586,11 +600,11 @@ - (NSText *) fieldEditor: (BOOL)createFlag
&& ([anObject tag] == NSFPSizeField))
{
if ((sizeFieldText == nil) && createFlag)
- {
- sizeFieldText = [NSText new];
- [sizeFieldText setUsesFontPanel: NO];
- [sizeFieldText setFieldEditor: YES];
- }
+ {
+ sizeFieldText = [NSText new];
+ [sizeFieldText setUsesFontPanel: NO];
+ [sizeFieldText setFieldEditor: YES];
+ }
return sizeFieldText;
}
@@ -639,9 +653,9 @@ - (id) _initWithoutGModel
NSBox *slash;
unsigned int style = NSTitledWindowMask | NSClosableWindowMask
- | NSResizableWindowMask | NSUtilityWindowMask;
+ | NSResizableWindowMask | NSUtilityWindowMask;
- self = [super initWithContentRect: contentRect
+ self = [super initWithContentRect: contentRect
styleMask: style
backing: NSBackingStoreRetained
defer: YES
@@ -662,7 +676,7 @@ - (id) _initWithoutGModel
_topView = topArea;
splitView = [[NSSplitView alloc] initWithFrame: splitViewRect];
- [splitView setVertical: NO];
+ [splitView setVertical: NO];
[splitView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)];
topSplit = [[NSView alloc] initWithFrame: topSplitRect];
@@ -869,7 +883,7 @@ - (id) _initWithoutGModel
[self setInitialFirstResponder: setButton];
[self setBecomesKeyOnlyIfNeeded: YES];
-
+
return self;
}
@@ -896,12 +910,12 @@ - (void) _doPreview
}
if (_previewString == nil)
- {
+ {
NSTextField *sizeField = [[self contentView] viewWithTag: NSFPSizeField];
float size = [sizeField floatValue];
NSString *faceName;
NSString *familyName;
-
+
if (size == 0 && font != nil)
{
size = [font pointSize];
@@ -924,7 +938,7 @@ - (void) _doPreview
}
[previewArea setStringValue: [NSString stringWithFormat: @"%@ %@ %d PT",
familyName, faceName, (int)size]];
- }
+ }
}
- (void) ok: (id)sender
@@ -941,7 +955,7 @@ - (void) cancel: (id)sender
/*
* The cancel button has been pushed
- * we should reset the items in the panel
+ * we should reset the items in the panel
*/
[self setPanelFont: _panelFont
isMultiple: _multiple];
@@ -993,7 +1007,7 @@ the delegate has refused all fonts (so that our family and face lists
else
return nil;
}
-
+
// FIXME: We should check if the font is correct
return [NSFont fontWithName: fontName size: size];
}
@@ -1012,15 +1026,15 @@ -(void) _trySelectSize: (float)size
sizeField = [[self contentView] viewWithTag: NSFPSizeField];
_setFloatValue (sizeField, size);
}
-
- /* Make sure our column is loaded. */
+
+ /* Make sure our column is loaded. */
[sizeBrowser loadColumnZero];
for (i = 0; i < sizeof(sizes) / sizeof(float); i++)
{
if (size == sizes[i])
{
- /* select the cell */
+ /* select the cell */
[sizeBrowser selectRow: i inColumn: 0];
break;
}
@@ -1109,7 +1123,7 @@ - (void) _familySelectionChanged: (id)sender
NSMutableArray *faceList;
entireFaceList = [fm availableMembersOfFontFamily:
- [_familyList objectAtIndex: row]];
+ [_familyList objectAtIndex: row]];
faceList = [[NSMutableArray alloc] initWithCapacity: [entireFaceList count]];
@@ -1202,7 +1216,7 @@ - (void) _sizeSelectionChanged: (id)sender
sizeField = [[self contentView] viewWithTag: NSFPSizeField];
_setFloatValue (sizeField, sizes[row]);
-
+
[self _doPreview];
}
@@ -1211,7 +1225,7 @@ - (NSInteger) browser: (NSBrowser*)sender numberOfRowsInColumn: (NSInteger)colu
{
switch ([sender tag])
{
- case NSFPFamilyBrowser:
+ case NSFPFamilyBrowser:
{
return [_familyList count];
}
@@ -1249,9 +1263,9 @@ - (NSString*) browser: (NSBrowser*)sender titleOfColumn: (NSInteger)column
}
}
-- (void) browser: (NSBrowser *)sender
- willDisplayCell: (id)cell
- atRow: (NSInteger)row
+- (void) browser: (NSBrowser *)sender
+ willDisplayCell: (id)cell
+ atRow: (NSInteger)row
column: (NSInteger)column
{
NSString *value = nil;
@@ -1274,7 +1288,7 @@ - (void) browser: (NSBrowser *)sender
if ([_faceList count] > (NSUInteger)row)
{
value = [[_faceList objectAtIndex: row] objectAtIndex: 1];
- }
+ }
break;
}
case NSFPSizeBrowser:
@@ -1283,12 +1297,12 @@ - (void) browser: (NSBrowser *)sender
value = [NSString stringWithFormat: @"%d", (int) sizes[row]];
}
}
-
+
[cell setStringValue: value];
[cell setLeaf: YES];
}
-- (BOOL) browser: (NSBrowser *)sender
+- (BOOL) browser: (NSBrowser *)sender
isColumnValid: (NSInteger)column;
{
return NO;
@@ -1298,8 +1312,8 @@ - (BOOL) browser: (NSBrowser *)sender
@implementation NSFontPanel (NSSplitViewDelegate)
-- (void) splitView: (NSSplitView *)splitView
-constrainMinCoordinate: (CGFloat *)min
+- (void) splitView: (NSSplitView *)splitView
+constrainMinCoordinate: (CGFloat *)min
maxCoordinate: (CGFloat *)max
ofSubviewAt: (NSInteger)offset
{