@@ -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