added iOS source code
[wl-app.git] / iOS / Pods / FontBlaster / Sources / FontBlaster.swift
diff --git a/iOS/Pods/FontBlaster/Sources/FontBlaster.swift b/iOS/Pods/FontBlaster/Sources/FontBlaster.swift
new file mode 100644 (file)
index 0000000..91d07b5
--- /dev/null
@@ -0,0 +1,182 @@
+//
+//  FontBlaster.swift
+//  FontBlaster
+//
+//  Created by Arthur Sabintsev on 5/5/15.
+//  Copyright (c) 2015 Arthur Ariel Sabintsev. All rights reserved.
+//
+
+import CoreGraphics
+import CoreText
+import Foundation
+import UIKit
+
+// MARK: - FontBlaster
+
+final public class FontBlaster {
+
+    fileprivate enum SupportedFontExtensions: String {
+        case TrueTypeFont = ".ttf"
+        case OpenTypeFont = ".otf"
+    }
+
+    fileprivate typealias FontPath = String
+    fileprivate typealias FontName = String
+    fileprivate typealias FontExtension = String
+    fileprivate typealias Font = (path: FontPath, name: FontName, ext: FontExtension)
+
+    /// Toggles debug print() statements
+    public static var debugEnabled = false
+
+    /// A list of the loaded fonts
+    public static var loadedFonts: [String] = []
+
+    /// Load all fonts found in a specific bundle. If no value is entered, it defaults to the main bundle.
+    public class func blast(bundle: Bundle = Bundle.main) {
+        blast(bundle: bundle, completion: nil)
+    }
+
+    /**
+     Load all fonts found in a specific bundle. If no value is entered, it defaults to the main bundle.
+
+     - returns: An array of strings constaining the names of the fonts that were loaded.
+     */
+    public class func blast(bundle: Bundle = Bundle.main, completion handler: (([String])->Void)?) {
+        let path = bundle.bundlePath
+        loadFontsForBundle(withPath: path)
+        loadFontsFromBundlesFoundInBundle(path: path)
+        handler?(loadedFonts)
+    }
+}
+
+// MARK: - Helpers (Font Loading)
+
+private extension FontBlaster {
+    /// Loads all fonts found in a bundle.
+    ///
+    /// - Parameter path: The absolute path to the bundle.
+    class func loadFontsForBundle(withPath path: String) {
+        do {
+            let contents = try FileManager.default.contentsOfDirectory(atPath: path) as [String]
+            let loadedFonts = fonts(fromPath: path, withContents: contents)
+            if !loadedFonts.isEmpty {
+                for font in loadedFonts {
+                    loadFont(font: font)
+                }
+            } else {
+                printDebugMessage(message: "No fonts were found in the bundle path: \(path).")
+            }
+        } catch let error as NSError {
+            printDebugMessage(message: "There was an error loading fonts from the bundle. \nPath: \(path).\nError: \(error)")
+        }
+    }
+
+    /// Loads all fonts found in a bundle that is loaded within another bundle.
+    ///
+    /// - Parameter path: The absolute path to the bundle.
+    class func loadFontsFromBundlesFoundInBundle(path: String) {
+        do {
+            let contents = try FileManager.default.contentsOfDirectory(atPath: path)
+            for item in contents {
+                if let url = URL(string: path),
+                    item.contains(".bundle") {
+                    let urlPathString = url.appendingPathComponent(item).absoluteString
+                    loadFontsForBundle(withPath: urlPathString)
+                }
+            }
+        } catch let error as NSError {
+            printDebugMessage(message: "There was an error accessing bundle with path. \nPath: \(path).\nError: \(error)")
+        }
+    }
+
+    /// Loads a specific font.
+    ///
+    /// - Parameter font: The font to load.
+    class func loadFont(font: Font) {
+        let fontPath: FontPath = font.path
+        let fontName: FontName = font.name
+        let fontExtension: FontExtension = font.ext
+        let fontFileURL = URL(fileURLWithPath: fontPath).appendingPathComponent(fontName).appendingPathExtension(fontExtension)
+
+        var fontError: Unmanaged<CFError>?
+        if let fontData = try? Data(contentsOf: fontFileURL) as CFData,
+            let dataProvider = CGDataProvider(data: fontData) {
+
+            /// Fixes deadlocking issue caused by `let fontRef = CGFont(dataProvider)`.
+            /// Temporary fix until rdar://18778790 is addressed.
+            /// Open Radar at http://www.openradar.me/18778790
+            /// Discussion at https://github.com/ArtSabintsev/FontBlaster/issues/19
+            _ = UIFont()
+
+            let fontRef = CGFont(dataProvider)
+
+            if CTFontManagerRegisterGraphicsFont(fontRef!, &fontError) {
+
+                if let postScriptName = fontRef?.postScriptName {
+                    printDebugMessage(message: "Successfully loaded font: '\(postScriptName)'.")
+                    loadedFonts.append(String(postScriptName))
+                }
+
+            } else if let fontError = fontError?.takeRetainedValue() {
+                let errorDescription = CFErrorCopyDescription(fontError)
+                printDebugMessage(message: "Failed to load font '\(fontName)': \(String(describing: errorDescription))")
+            }
+        } else {
+            guard let fontError = fontError?.takeRetainedValue() else {
+                printDebugMessage(message: "Failed to load font '\(fontName)'.")
+                return
+            }
+
+            let errorDescription = CFErrorCopyDescription(fontError)
+            printDebugMessage(message: "Failed to load font '\(fontName)': \(String(describing: errorDescription))")
+        }
+    }
+}
+
+// MARK: - Helpers (Miscellaneous)
+
+private extension FontBlaster {
+    /// Parses all of the fonts into their name and extension components.
+    ///
+    /// - Parameters:
+    ///     - path: The absolute path to the font file.
+    ///     - contents: The contents of an Bundle as an array of String objects.
+    /// 
+    /// - Returns: A an array of Font objects.
+    class func fonts(fromPath path: String, withContents contents: [String]) -> [Font] {
+        var fonts = [Font]()
+        for fontName in contents {
+            var parsedFont: (FontName, FontExtension)?
+
+            if fontName.contains(SupportedFontExtensions.TrueTypeFont.rawValue) || fontName.contains(FontBlaster.SupportedFontExtensions.OpenTypeFont.rawValue) {
+                parsedFont = font(fromName: fontName)
+            }
+
+            if let parsedFont = parsedFont {
+                let font: Font = (path, parsedFont.0, parsedFont.1)
+                fonts.append(font)
+            }
+        }
+
+        return fonts
+    }
+
+    /// Parses a font into its name and extension components.
+    ///
+    /// - Parameter name: The name of the font.
+    /// 
+    /// - Returns: A tuple with the font's name and extension.
+    class func font(fromName name: String) -> (FontName, FontExtension) {
+        let components = name.split{$0 == "."}.map { String($0) }
+        return (components[0], components[1])
+    }
+
+    /// Prints debug messages to the console if debugEnabled is set to true.
+    ///
+    /// - Parameter message: The status to print to the console.
+    class func printDebugMessage(message: String) {
+        if debugEnabled == true {
+            print("[FontBlaster]: \(message)")
+        }
+    }
+}