Skip to content

Commit 6d9612a

Browse files
authored
GLGUI: reduce complexity of font operations. (#359)
Note: In order to keep the patch reasonably sized, this patch is only a first of a serious of changes. So far it only proofs the concept and cracks down on the most prominent cases profiling the app revealed. Over time the use of 'assoc' on fonts should be phased out and replaced with properly abstracted operations to enable the underlying implementation to be changed. Note2: This change overwrites assoc globally, but should do so in a benign manner!
1 parent c6ac370 commit 6d9612a

File tree

1 file changed

+115
-14
lines changed

1 file changed

+115
-14
lines changed

modules/ln_glgui/primitives.scm

Lines changed: 115 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,77 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
211211

212212
(glgui-utf8-set! #t)
213213

214+
;;; BEGIN CODE TRANSITION
215+
;;;
216+
;;; Reducing the computational complexity of font operations improves
217+
;;; rendering time.
218+
219+
(define-type ln-ttf:font
220+
macros: prefix: macro-
221+
desc ;; for now the legacy description of a font as a assoc-list
222+
char->desc-table
223+
)
224+
225+
(define (ln-ttf:font? obj) (macro-ln-ttf:font? obj))
226+
227+
(define find-font/desc)
228+
229+
(define (ln-ttf:font-ref font char) ;; -> glyph
230+
(cond
231+
((macro-ln-ttf:font? font) ;; TBD: leave this as the only case
232+
(table-ref (macro-ln-ttf:font-char->desc-table font) char #f))
233+
(else
234+
(ln-ttf:font-ref (find-font font) char))))
235+
236+
(define (make-ln-ttf:font/desc fnt)
237+
(let ((font-table (list->table
238+
(let ((double-the-key (lambda (x) (cons (car x) x))))
239+
;; TBD: get rid of the doubling - requires changes to call sites
240+
(map double-the-key fnt)))))
241+
(macro-make-ln-ttf:font fnt font-table)))
242+
243+
(define find-font
244+
;; TBD consider amount of fonts and decide on font cache data
245+
;; structure. Now assq-list; good for rather short lists, which
246+
;; are in line with good user interface design.
247+
(let ((by-desc '() #;(make-table hash: eq?-hash))
248+
(assq assq))
249+
(define (%find-font/desc fnt)
250+
(let ((hit (assq fnt by-desc) #;(table-ref by-desc fnt #f)))
251+
(if hit (cdr hit) #; hit
252+
(let ((font (make-ln-ttf:font/desc fnt)))
253+
#;(table-set! by-desc fnt font)
254+
(set! by-desc (cons (cons fnt font) by-desc))
255+
font))))
256+
(define (find-font fnt)
257+
(cond
258+
((macro-ln-ttf:font? fnt) ;; new style
259+
;; TBD: after transition phase warn if this case is hit.
260+
fnt)
261+
((and (pair? fnt) (pair? (car fnt))) ;; likely a legacy font
262+
(%find-font/desc fnt))
263+
(else
264+
(error "illegal font" fnt))))
265+
(set! find-font/desc %find-font/desc)
266+
find-font))
267+
268+
(define (install-font-cache-backward-compatible-override!)
269+
(let ((assoc.orig assoc))
270+
;; Backward compatibility: try to transparently hook into legacy lookups.
271+
;; TBD: 2020-08-23 This is an intermediate workaround to be removed ASAP.
272+
(define (transparent-font-assoc k coll)
273+
(cond
274+
((macro-ln-ttf:font? coll)
275+
;; TBD: after experimental phase warn if this case is hit.
276+
(ln-ttf:font-ref coll k))
277+
(else
278+
;; TBD: after transition phase error out if this case is hit.
279+
(assoc.orig k coll))))
280+
(set! assoc transparent-font-assoc)))
281+
282+
(install-font-cache-backward-compatible-override!)
283+
;;; End OF TRANSITIONAL CODE
284+
214285
(define (glgui:renderstring x y txt fnt color)
215286
(glCoreColor color)
216287
(let loop ((x0 (flo x)) (cs (glgui:string->glyphs txt)))
@@ -233,27 +304,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
233304
(cadr (cadr (car fnt)))))) h))
234305

235306
(define (glgui:stringheight txt fnt)
307+
(define font (find-font fnt))
236308
(let loop ((above 0.) (below 0.) (cs (glgui:string->glyphs txt)))
237309
(if (null? cs) (list above below)
238-
(let* ((g (assoc (car cs) fnt))
310+
(let* ((g (ln-ttf:font-ref font (car cs)))
239311
(i (if g (glgui:glyph-image g) #f))
240312
(gh (if i (flo (glgui:image-h i)) 0.))
241313
(goy (if g (flo (glgui:glyph-offsety g)) 0.)))
242314
(loop (flmax above goy) (flmin below (fl- goy gh)) (cdr cs))))))
243315

244316
; returns a fixnum width of the string, rounded up
245317
(define (glgui:stringwidth txt fnt)
246-
(let loop ((x 0.) (cs (glgui:string->glyphs txt)))
247-
(if (null? cs) (fix (ceiling x))
248-
(let* ((glyph (assoc (car cs) fnt))
249-
(ax (if glyph (flo (glgui:glyph-advancex glyph)) 0.)))
250-
(loop (fl+ x ax) (cdr cs))))))
318+
(let ((cs (glgui:string->glyphs txt))
319+
(fnt (find-font fnt)))
320+
(let loop ((x 0.) (cs cs))
321+
(if (null? cs)
322+
(fix (ceiling x))
323+
(let* ((key (car cs))
324+
(glyph (ln-ttf:font-ref fnt key))
325+
(ax (if glyph (flo (glgui:glyph-advancex glyph)) 0.)))
326+
(loop (fl+ x ax) (cdr cs)))))))
251327

252328
; returns a list of floats widths of the glyphs in the string
253329
(define (glgui:stringwidth-lst txt fnt)
330+
(define font (find-font fnt))
254331
(let loop ((cs (glgui:string->glyphs txt)) (ret '()))
255332
(if (null? cs) ret
256-
(let* ((glyph (assoc (car cs) fnt))
333+
(let* ((glyph (ln-ttf:font-ref font (car cs)))
257334
(ax (if glyph (flo (glgui:glyph-advancex glyph)) 0.)))
258335
(loop (cdr cs) (append ret (list ax)))))))
259336

@@ -289,14 +366,38 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
289366
(glgui:renderstring (fl+ (flo x) (flo w) (fl- strw)) centery label fnt color)))
290367

291368
(define (glgui:draw-text-center x y w h label fnt color . clipright)
292-
(let* ((strw (flo (glgui:stringwidth label fnt)))
369+
;; looks like a case of "premature optimization is the root of all evil"
370+
(let* ((strw-raw (glgui:stringwidth label fnt)) ;; fixnum
371+
;; `strh` list instead of two values (top bottom) relative to baseline
293372
(strh (map flo (glgui:stringheight (string-append label "|") fnt)))
294-
(centery (fl+ (flo y) (fl/ (if (fl> (flo h) 0.) (flo h) (fl- (car strh) (cadr strh))) 2.)
295-
(fl- (fl/ (fl+ (car strh) (cadr strh)) 2.))))
296-
(clipper (if (and (pair? clipright) (car clipright))
297-
glgui:stringclipright glgui:stringclipleft)))
298-
(glgui:renderstring (if (fl> strw (flo w)) x (fl+ (flo x) (fl/ (fl- (flo w) strw) 2.))) centery
299-
(if (fl> strw (flo w)) (clipper w label fnt) label) fnt color)))
373+
(first-char-height (car strh))
374+
(second-char-height (cadr strh))
375+
(h-flo (flo h))
376+
(y-flo (flo y)) ;; just used once (so far) for symmetry
377+
(centery ;; careful to have floating point only.
378+
;; This might be "premature optimization". The contributes
379+
;; next to nothing to the cumulative time
380+
;; `draw-text-center` needs.
381+
(fl+ y-flo
382+
(fl/ (if (fl> h-flo 0.)
383+
h-flo
384+
(fl- first-char-height second-char-height))
385+
2.)
386+
(fl- (fl/ (fl+ first-char-height second-char-height) 2.))))
387+
(clipper
388+
(let ((clipright (and (pair? clipright) (car clipright))))
389+
(if clipright glgui:stringclipright glgui:stringclipleft))))
390+
(let ((strw-flo (flo strw-raw)) ; with of the string
391+
(w-flo (flo w)))
392+
(glgui:renderstring
393+
;; FIXME: why enforce conversion to to flow in the first place?
394+
(if (fl> strw-flo w-flo) ;; needs full width
395+
x ;; start at left otherwise at half of empty space
396+
(fl+ (flo x) (fl/ (fl- w-flo strw-flo) 2.)))
397+
centery
398+
(if (fl> strw-flo w-flo) (clipper w label fnt) label)
399+
fnt color))))
400+
300401

301402
(define (string-split-width str w fnt)
302403
(if (string-contains str "\n")

0 commit comments

Comments
 (0)