diff --git a/Package.swift b/Package.swift index a094e76..0a655aa 100644 --- a/Package.swift +++ b/Package.swift @@ -60,11 +60,20 @@ let package = Package( // Targets can depend on other targets in this package and products from dependencies. .systemLibrary( name: "CSwingby", - path: "Sources/CSwingby", + path: "Sources/CSwingby" + ), + .systemLibrary( + name: "CFontconfig", + path: "Sources/CFontconfig" + ), + .systemLibrary( + name: "CPango", + path: "Sources/CPango", + pkgConfig: "pango" ), .target( name: "Blusher", - dependencies: ["CSwingby"], + dependencies: ["CSwingby", "CFontconfig", "CPango"], swiftSettings: [ .unsafeFlags(["-enable-library-evolution"]), .unsafeFlags(swingbyConf.includePathFlags), diff --git a/Sources/Blusher/Text/Font.swift b/Sources/Blusher/Text/Font.swift new file mode 100644 index 0000000..6b3c3f5 --- /dev/null +++ b/Sources/Blusher/Text/Font.swift @@ -0,0 +1,25 @@ +public struct Font { + public enum Weight { + case thin // 100 + case extraLight // 200 + case light // 300 + case regular // 400 + case medium // 500 + case semiBold // 600 + case bold // 700 + case extraBold // 800 + case black // 900 + } + + public var family: String + public var path: String + public var ttcIndex: Int + public var size: Float + + internal init() { + self.family = "" + self.path = "" + self.ttcIndex = 0 + self.size = 1.0 + } +} diff --git a/Sources/Blusher/Text/Glyph.swift b/Sources/Blusher/Text/Glyph.swift new file mode 100644 index 0000000..7fd8dae --- /dev/null +++ b/Sources/Blusher/Text/Glyph.swift @@ -0,0 +1,56 @@ +@_implementationOnly import Swingby + +public struct Glyph { + public var id: UInt32 = 0 + public var advance: Float = 0.0 + public var offset: Point = Point(x: 0.0, y: 0.0) + + public init(id: UInt32) { + self.id = id + } +} + +public class GlyphRun { + private var _sbGlyphRun: OpaquePointer? = nil + private var _glyphBuffer: [Glyph] = [] + + public var count: Int { + return Int(sb_glyph_run_count(_sbGlyphRun)) + } + + public init(count: Int) { + var sbFont = sb_font_t(path: nil, ttc_index: 0, size: 16.0) + let path = "/usr/share/fonts/noto/NotoSans-Regular.ttf" + path.withCString { cStr in + sbFont.path = cStr + } + sbFont.ttc_index = 0 + + _sbGlyphRun = sb_glyph_run_new(UInt32(count), &sbFont) + + for _ in 0...count { + _glyphBuffer.append(Glyph(id: 0)) + } + } + + deinit { + sb_glyph_run_free(_sbGlyphRun) + } + + public subscript(_ index: Int) -> Glyph { + get { + return _glyphBuffer[index] + } + set { + _glyphBuffer[index] = newValue + + if let cGlyphs = sb_glyph_run_glyphs(_sbGlyphRun) { + let cGlyph = cGlyphs + index + cGlyph.pointee.id = newValue.id + cGlyph.pointee.advance = newValue.advance + cGlyph.pointee.offset.x = newValue.offset.x + cGlyph.pointee.offset.y = newValue.offset.y + } + } + } +} diff --git a/Sources/Blusher/Text/TextLayout.swift b/Sources/Blusher/Text/TextLayout.swift new file mode 100644 index 0000000..67538b6 --- /dev/null +++ b/Sources/Blusher/Text/TextLayout.swift @@ -0,0 +1,35 @@ +@_implementationOnly import CPango + +public struct TextLayout { + public struct Line { + private var _runs: [GlyphRun] + } + + private var _pangoFontMap: UnsafeMutablePointer? + private var _pangoContext: OpaquePointer? + private var _pangoLayout: OpaquePointer? + private var _text: String = "" + private var _lines: [Line] = [] + + public var text: String { + get { _text } + set { + if _text != newValue { + _text = newValue + _text.withCString { cStr in + pango_layout_set_text(_pangoLayout, cStr, -1) + } + } + } + } + + public init() { + _pangoFontMap = pango_ft2_font_map_new() + _pangoContext = pango_font_map_create_context(_pangoFontMap) + _pangoLayout = pango_layout_new(_pangoContext) + } + + public func update() { + pango_layout_context_changed(_pangoLayout) + } +} diff --git a/Sources/Blusher/Utilities/FontLibrary.swift b/Sources/Blusher/Utilities/FontLibrary.swift new file mode 100644 index 0000000..625dc39 --- /dev/null +++ b/Sources/Blusher/Utilities/FontLibrary.swift @@ -0,0 +1,50 @@ +@_implementationOnly import CFontconfig + +public class FontLibrary { + nonisolated(unsafe) public static var shared: FontLibrary! + + private init() { + FcInit() + + FontLibrary.shared = self + } + + deinit { + FcFini() + } + + public static func findFont(family: String) -> Font { + var font = Font() + + let pattern = FcPatternCreate() + + family.withCString { cStr in + let _ = FcPatternAddString(pattern, FC_FAMILY, cStr) + } + FcConfigSubstitute(nil, pattern, FcMatchPattern) + FcDefaultSubstitute(pattern) + + var result = FcResultNoMatch + let match = FcFontMatch(nil, pattern, &result) + + FcPatternDestroy(pattern) + + // if result != FcResultMatch + + var path: UnsafeMutablePointer? = nil + var index: Int32 = 0 + var weight: Int32 = 0 + var size = 1.0 + + FcPatternGetString(match, FC_FILE, 0, &path) + FcPatternGetInteger(match, FC_INDEX, 0, &index) + FcPatternGetInteger(match, FC_WEIGHT, 0, &weight) + FcPatternGetDouble(match, FC_PIXEL_SIZE, 0, &size) + + font.path = String(cString: path!) + font.ttcIndex = Int(index) + font.size = Float(size) + + return font + } +} diff --git a/Sources/CFontconfig/CFontconfig.h b/Sources/CFontconfig/CFontconfig.h new file mode 100644 index 0000000..0b9b12a --- /dev/null +++ b/Sources/CFontconfig/CFontconfig.h @@ -0,0 +1,6 @@ +#ifndef BLUSHER_CFONTCONFIG_H +#define BLUSHER_CFONTCONFIG_H + +#include + +#endif diff --git a/Sources/CFontconfig/module.modulemap b/Sources/CFontconfig/module.modulemap new file mode 100644 index 0000000..689bde0 --- /dev/null +++ b/Sources/CFontconfig/module.modulemap @@ -0,0 +1,5 @@ +module CFontconfig [system] { + header "CFontconfig.h" + link "fontconfig" + export * +} diff --git a/Sources/CPango/CPango.h b/Sources/CPango/CPango.h new file mode 100644 index 0000000..0632d24 --- /dev/null +++ b/Sources/CPango/CPango.h @@ -0,0 +1,8 @@ +#ifndef BLUSHER_CPANGO_H +#define BLUSHER_CPANGO_H + +#include +#include +#include + +#endif diff --git a/Sources/CPango/module.modulemap b/Sources/CPango/module.modulemap new file mode 100644 index 0000000..3c9e445 --- /dev/null +++ b/Sources/CPango/module.modulemap @@ -0,0 +1,5 @@ +module CPango [system] { + header "CPango.h" + link "pango-1.0" + export * +}