|
|
|
@ -0,0 +1,112 @@
|
|
|
|
|
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
|
|
|
|
# SPDX-License-Identifier: Unlicense
|
|
|
|
|
|
|
|
|
|
import std/[asyncdispatch, os, osproc, strutils]
|
|
|
|
|
import preserves, syndicate, syndicate/[patterns]
|
|
|
|
|
import ./protocol
|
|
|
|
|
|
|
|
|
|
{.passC: staticExec("pkg-config --cflags fontconfig").}
|
|
|
|
|
{.passL: staticExec("pkg-config --libs fontconfig").}
|
|
|
|
|
|
|
|
|
|
{.pragma: fcHeader, header: "<fontconfig/fontconfig.h>".}
|
|
|
|
|
{.pragma: importFc, fcHeader, importc: "Fc$1".}
|
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
FcFalse = cint 0
|
|
|
|
|
|
|
|
|
|
FC_FAMILY = "family"
|
|
|
|
|
FC_STYLE = "style"
|
|
|
|
|
FC_WEIGHT = "weight"
|
|
|
|
|
FC_SIZE = "size"
|
|
|
|
|
FC_FILE = "file"
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
FcChar8* = uint8
|
|
|
|
|
FcBool* = cint
|
|
|
|
|
|
|
|
|
|
FcResult {.importc.} = enum
|
|
|
|
|
FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
|
|
|
|
|
FcResultOutOfMemory
|
|
|
|
|
|
|
|
|
|
FcPattern = distinct pointer
|
|
|
|
|
|
|
|
|
|
FcConfig = distinct pointer
|
|
|
|
|
|
|
|
|
|
proc Init(): FcBool {.importFc.} ## Initialize fontconfig library
|
|
|
|
|
proc Fini() {.importFc.} ## Finalize fontconfig library.
|
|
|
|
|
|
|
|
|
|
proc PatternCreate(): FcPattern {.importFc.}
|
|
|
|
|
proc PatternDestroy(p: FcPattern) {.importFc.}
|
|
|
|
|
|
|
|
|
|
proc PatternAddInteger(p: FcPattern; obj: cstring; i: cint): FcBool {.importFc.}
|
|
|
|
|
proc PatternAddDouble(p: FcPattern; obj: cstring; d: cdouble): FcBool {.importFc.}
|
|
|
|
|
proc PatternAddString(p: FcPattern; obj, s: cstring): FcBool {.importFc.}
|
|
|
|
|
proc DefaultSubstitute(p: FcPattern) {.importFc.}
|
|
|
|
|
proc PatternPrint(p: FcPattern) {.importFc.}
|
|
|
|
|
|
|
|
|
|
proc FontMatch(cfg: FcConfig; p: FcPattern; r: var FcResult): FcPattern {.importFc.}
|
|
|
|
|
|
|
|
|
|
proc PatternGetString(p: FcPattern; obj: cstring; n: cint;
|
|
|
|
|
s: ptr cstring): FcResult {.importFc.}
|
|
|
|
|
|
|
|
|
|
proc findSystemTypeface*(family = ""; style = ""; weight = 0; size = 0.0): string =
|
|
|
|
|
## Find a path to an appropriate system typeface for the given parameters.
|
|
|
|
|
## This proc always returns a path to a typeface file, results may vary.
|
|
|
|
|
# TODO: only return font in supported formats
|
|
|
|
|
if Init() == FcFalse:
|
|
|
|
|
raise newException(IOError, "Failed to initialize FontConfig")
|
|
|
|
|
|
|
|
|
|
var pat = PatternCreate()
|
|
|
|
|
DefaultSubstitute(pat)
|
|
|
|
|
if family != "":
|
|
|
|
|
discard PatternAddString(pat, FC_FAMILY, family);
|
|
|
|
|
if style != "":
|
|
|
|
|
discard PatternAddString(pat, FC_STYLE, style);
|
|
|
|
|
if weight != 0:
|
|
|
|
|
discard PatternAddInteger(pat, FC_WEIGHT, cint weight);
|
|
|
|
|
if size != 0.0:
|
|
|
|
|
discard PatternAddDouble(pat, FC_SIZE, size);
|
|
|
|
|
|
|
|
|
|
var
|
|
|
|
|
res = FcResultNoMatch
|
|
|
|
|
font = FontMatch(nil, pat, res)
|
|
|
|
|
if res == FcResultMatch:
|
|
|
|
|
# PatternPrint(font);
|
|
|
|
|
var path: cstring
|
|
|
|
|
if PatternGetString(font, FC_FILE, 0, addr path) == FcResultMatch:
|
|
|
|
|
result = $path
|
|
|
|
|
PatternDestroy(font)
|
|
|
|
|
|
|
|
|
|
PatternDestroy(pat)
|
|
|
|
|
Fini()
|
|
|
|
|
if result == "":
|
|
|
|
|
raise newException(IOError, "Failed to find a system typeface")
|
|
|
|
|
|
|
|
|
|
proc serve(ds: Ref; turn: var Turn) =
|
|
|
|
|
let observation = ?Observe(pattern: !FontAssertion) ?? {0: grabDict()}
|
|
|
|
|
during(turn, ds, observation) do (properties: Assertion):
|
|
|
|
|
stderr.writeLine "looking for ", properties
|
|
|
|
|
|
|
|
|
|
#[
|
|
|
|
|
let propPat = { toSymbol("family", Ref) : ?"Foo" }.dictionaryPattern
|
|
|
|
|
let testPat = FontAssertion ? { 0: propPat, 1: grab(), 2: grab() }
|
|
|
|
|
|
|
|
|
|
onPublish(turn, ds, testPat) do (file: string, index: int):
|
|
|
|
|
stderr.writeLine "found file ", file, " with index ", index
|
|
|
|
|
|
|
|
|
|
during(turn, ds, Observe ? { 0: grab() }) do (pat: Assertion):
|
|
|
|
|
stderr.writeLine "observed request for ", pat
|
|
|
|
|
|
|
|
|
|
during(turn, ds, Observe ? { 0: ?(FontAssertion ? { 0: drop()}) }) do:
|
|
|
|
|
stderr.writeLine "fontconfig observe found! "
|
|
|
|
|
]#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bootDataspace("main") do (root: Ref; turn: var Turn):
|
|
|
|
|
connectStdio(root, turn)
|
|
|
|
|
if Init() == FcFalse:
|
|
|
|
|
quit"Failed to initialize FontConfig"
|
|
|
|
|
during(turn, root, ?Serve) do (ds: Ref):
|
|
|
|
|
serve(ds, turn)
|
|
|
|
|
|
|
|
|
|
runForever()
|