1 ! Copyright (C) 2009, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien.c-types alien.data alien.strings arrays assocs
4 cache cairo cairo.ffi classes.struct combinators destructors fonts fry
5 gobject.ffi init io.encodings.utf8 kernel math math.rectangles
6 math.vectors memoize namespaces pango.cairo.ffi pango.ffi sequences
7 ui.text ui.text.private ;
10 : pango>float ( n -- x ) PANGO_SCALE /f ; inline
11 : float>pango ( x -- n ) PANGO_SCALE * >integer ; inline
13 MEMO:: (cache-font-description) ( name size bold? italic? -- description )
15 pango_font_description_new |pango_font_description_free {
16 [ name utf8 string>alien pango_font_description_set_family ]
17 [ size float>pango pango_font_description_set_size ]
18 [ bold? PANGO_WEIGHT_BOLD PANGO_WEIGHT_NORMAL ? pango_font_description_set_weight ]
19 [ italic? PANGO_STYLE_ITALIC PANGO_STYLE_NORMAL ? pango_font_description_set_style ]
24 : cache-font-description ( font -- description )
25 { [ name>> ] [ size>> ] [ bold?>> ] [ italic?>> ] } cleave
26 (cache-font-description) ;
28 TUPLE: layout < disposable font string selection layout metrics ink-rect logical-rect image ;
34 : set-layout-font ( font layout -- )
35 swap cache-font-description pango_layout_set_font_description ;
37 : set-layout-text ( str layout -- )
38 swap utf8 string>alien -1 pango_layout_set_text ;
40 : PangoRectangle>rect ( PangoRectangle -- rect )
41 [ [ x>> pango>float ] [ y>> pango>float ] bi 2array ]
42 [ [ width>> pango>float ] [ height>> pango>float ] bi 2array ] bi
45 : layout-extents ( layout -- ink-rect logical-rect )
48 [ pango_layout_get_extents ] 2keep
49 [ PangoRectangle>rect ] bi@ ;
51 : layout-baseline ( layout -- baseline )
52 pango_layout_get_iter &pango_layout_iter_free
53 pango_layout_iter_get_baseline
56 : set-foreground ( cr font -- )
57 foreground>> set-source-color ;
59 : fill-background ( cr font dim -- )
60 [ background>> set-source-color ]
61 [ [ { 0 0 } ] dip <rect> fill-rect ] bi-curry* bi ;
63 : rect-translate-x ( rect x -- rect' )
64 '[ _ 0 2array v- ] change-loc ;
66 : first-line ( layout -- line )
67 layout>> 0 pango_layout_get_line_readonly ;
69 : line-offset>x ( layout n -- x )
70 ! n is an index into the UTF8 encoding of the text
71 [ drop first-line ] [ swap string>> >utf8-index ] 2bi
72 f { int } [ pango_layout_line_index_to_x ] with-out-parameters
75 : x>line-offset ( layout x -- n )
76 ! n is an index into the UTF8 encoding of the text
81 [ pango_layout_line_x_to_index drop ] with-out-parameters
83 ] [ drop string>> ] 2bi utf8-index> + ;
85 : selection-start/end ( selection -- start end )
86 selection>> [ start>> ] [ end>> ] bi ;
88 : selection-rect ( layout -- rect )
89 [ ink-rect>> dim>> ] [ ] [ selection-start/end ] tri [ line-offset>x ] bi-curry@ bi
90 [ drop nip 0 2array ] [ swap - swap second 2array ] 3bi <rect> ;
92 : fill-selection-background ( cr layout -- )
94 [ selection>> color>> set-source-color ]
96 [ selection-rect ] [ ink-rect>> loc>> first ] bi
102 : text-position ( layout -- loc )
103 [ logical-rect>> ] [ ink-rect>> ] bi [ loc>> ] bi@ v- ;
105 : set-text-position ( cr loc -- )
106 first2 cairo_move_to ;
108 : draw-layout ( layout -- image )
109 dup ink-rect>> dim>> [ >fixnum ] map [
111 [ layout>> pango_cairo_update_layout ]
112 [ [ font>> ] [ ink-rect>> dim>> ] bi fill-background ]
113 [ fill-selection-background ]
114 [ text-position set-text-position ]
115 [ font>> set-foreground ]
116 [ layout>> pango_cairo_show_layout ]
118 ] make-bitmap-image ;
120 : escape-nulls ( str -- str' )
121 ! Replace nulls with something else since Pango uses null-terminated
123 H{ { 0 CHAR: zero-width-no-break-space } } substitute ;
125 : unpack-selection ( layout string/selection -- layout )
127 [ string>> escape-nulls >>string ] [ >>selection ] bi
128 ] [ escape-nulls >>string ] if ; inline
130 : set-layout-resolution ( layout -- )
131 pango_layout_get_context dpi get-global pango_cairo_context_set_resolution ;
133 : <PangoLayout> ( text font -- layout )
134 dummy-cairo pango_cairo_create_layout |g_object_unref
135 [ set-layout-resolution ] keep
136 [ set-layout-font ] keep
137 [ set-layout-text ] keep ;
139 : glyph-height ( font string -- y )
140 swap <PangoLayout> &g_object_unref layout-extents drop dim>> second ;
142 MEMO: missing-font-metrics ( font -- metrics )
143 ! Pango doesn't provide x-height and cap-height but Core Text does, so we
144 ! simulate them on Pango.
147 [ "x" glyph-height >>x-height ]
148 [ "Y" glyph-height >>cap-height ] bi
151 : layout-metrics ( layout -- metrics )
152 dup font>> missing-font-metrics clone
154 [ layout>> layout-baseline >>ascent ]
155 [ logical-rect>> dim>> [ first >>width ] [ second >>height ] bi ] bi
156 dup [ height>> ] [ ascent>> ] bi - >>descent ;
158 : <layout> ( font string -- line )
160 layout new-disposable
161 swap unpack-selection
163 dup [ string>> ] [ font>> ] bi <PangoLayout> >>layout
164 dup layout>> layout-extents [ >>ink-rect ] [ >>logical-rect ] bi*
165 dup layout-metrics >>metrics
168 M: layout dispose* layout>> g_object_unref ;
170 SYMBOL: cached-layouts
172 : cached-layout ( font string -- layout )
173 cached-layouts get-global [ <layout> ] 2cache ;
175 : cached-line ( font string -- line )
176 cached-layout layout>> first-line ;
178 : layout>image ( layout -- image )
179 dup image>> [ dup draw-layout >>image ] unless image>> ;
181 SINGLETON: pango-renderer
183 M: pango-renderer string-dim
184 [ " " string-dim { 0 1 } v* ]
185 [ cached-layout logical-rect>> dim>> v>integer ] if-empty ;
187 M: pango-renderer flush-layout-cache
188 cached-layouts get-global purge-cache ;
190 M: pango-renderer string>image
191 cached-layout [ layout>image ] [ text-position vneg ] bi ;
193 M: pango-renderer x>offset
194 cached-layout swap x>line-offset ;
196 M: pango-renderer offset>x
197 cached-layout swap line-offset>x ;
199 M: pango-renderer font-metrics
200 " " cached-layout metrics>> clone f >>width ;
202 M: pango-renderer line-metrics
203 [ " " line-metrics clone 0 >>width ]
204 [ cached-layout metrics>> ]
208 \ (cache-font-description) reset-memoized
209 <cache-assoc> cached-layouts set-global
210 ] "ui.text.pango" add-startup-hook
212 pango-renderer font-renderer set-global