1 /*	Public domain	*/
2 
3 #ifndef _AGAR_GUI_TEXT_H_
4 #define _AGAR_GUI_TEXT_H_
5 
6 #include <agar/gui/surface.h>
7 #include <agar/gui/drv.h>
8 
9 #include <agar/gui/begin.h>
10 
11 #define AG_GLYPH_NBUCKETS 1024	/* Buckets for glyph cache table */
12 #define AG_TEXT_STATES_MAX 128	/* Maximum number of saved text states */
13 
14 struct ag_window;
15 struct ag_button;
16 
17 enum ag_text_justify {
18 	AG_TEXT_LEFT,
19 	AG_TEXT_CENTER,
20 	AG_TEXT_RIGHT
21 };
22 enum ag_text_valign {
23 	AG_TEXT_TOP,
24 	AG_TEXT_MIDDLE,
25 	AG_TEXT_BOTTOM
26 };
27 enum ag_text_msg_title {
28 	AG_MSG_ERROR,
29 	AG_MSG_WARNING,
30 	AG_MSG_INFO
31 };
32 
33 struct ag_font;
34 
35 /* Font specification (may be obtained from fontconfig) */
36 enum ag_font_type {
37 	AG_FONT_VECTOR,				/* Vectorial font */
38 	AG_FONT_BITMAP				/* Raw glyph pixmaps */
39 };
40 enum ag_font_spec_source {
41 	AG_FONT_SOURCE_FILE,			/* Load from file */
42 	AG_FONT_SOURCE_MEMORY			/* Read from memory */
43 };
44 typedef struct ag_font_spec {
45 	enum ag_font_type type;
46 	enum ag_font_spec_source sourceType;
47 	union {
48 		char file[AG_PATHNAME_MAX];	/* Font file */
49 		struct {
50 			const Uint8 *data;	/* Memory region */
51 			size_t size;
52 		} mem;
53 	} source;
54 	int index;				/* Font index */
55 	double size;				/* Font size */
56 	struct {				/* Transform matrix */
57 		double xx, xy;
58 		double yx, yy;
59 	} matrix;
60 } AG_FontSpec;
61 
62 /* Cached glyph surface/texture information. */
63 typedef struct ag_glyph {
64 	struct ag_font *font;		/* Font face */
65 	AG_Color        color;		/* Glyph color */
66 	Uint32          ch;		/* Unicode character */
67 	AG_Surface     *su;		/* Rendered surface */
68 	int             advance;	/* Pixel advance */
69 	Uint            texture;	/* Cached texture (driver-specific) */
70 	AG_TexCoord     texcoords;	/* Texture coordinates */
71 	AG_SLIST_ENTRY(ag_glyph) glyphs;
72 } AG_Glyph;
73 
74 /* Loaded font */
75 typedef struct ag_font {
76 	struct ag_object obj;
77 	AG_FontSpec spec;		/* Input font specification */
78 	Uint flags;
79 #define AG_FONT_BOLD		0x01	/* Render as bold */
80 #define AG_FONT_ITALIC		0x02	/* Render as italic */
81 #define AG_FONT_UNDERLINE	0x04	/* Render with underline */
82 #define AG_FONT_UPPERCASE	0x08	/* Force uppercase display */
83 	int height;			/* Body size in pixels */
84 	int ascent;			/* Ascent (relative to baseline) */
85 	int descent;			/* Descent (relative to baseline) */
86 	int lineskip;			/* Multiline y-increment */
87 	void *ttf;			/* TTF object */
88 	char bspec[32];			/* Bitmap font specification */
89 	AG_Surface **bglyphs;		/* Bitmap glyphs */
90 	Uint nglyphs;			/* Bitmap glyph count */
91 	Uint32 c0, c1;			/* Bitmap glyph range */
92 	Uint nRefs;			/* Reference count */
93 	AG_TAILQ_ENTRY(ag_font) fonts;
94 } AG_Font;
95 
96 /*
97  * State variables for text rendering.
98  * SYNC: AG_TextStateCompare()
99  */
100 typedef struct ag_text_state {
101 	AG_Font *font;			/* Font face */
102 	AG_Color color;			/* Foreground text color */
103 	AG_Color colorBG;		/* Background color */
104 	enum ag_text_justify justify;	/* Justification mode */
105 	enum ag_text_valign valign;	/* Vertical alignment mode */
106 	int tabWd;			/* Width of \t in pixels */
107 } AG_TextState;
108 
109 /* Description of font stored in data segment. */
110 typedef struct ag_static_font {
111 	const char *name;		/* Identifier */
112 	enum ag_font_type type;		/* Type of font */
113 	Uint32 size;			/* Size in bytes */
114 	const Uint8 *data;		/* Font data */
115 	AG_Font *font;			/* Initialized font structure */
116 } AG_StaticFont;
117 
118 /* Measures of rendered text. */
119 typedef struct ag_text_metrics {
120 	int w, h;			/* Dimensions in pixels */
121 	Uint *wLines;			/* Width of each line */
122 	Uint  nLines;			/* Total line count */
123 } AG_TextMetrics;
124 
125 typedef struct ag_glyph_cache {
126 	AG_SLIST_HEAD_(ag_glyph) glyphs;
127 } AG_GlyphCache;
128 
129 __BEGIN_DECLS
130 extern AG_ObjectClass agFontClass;
131 extern AG_Font *agDefaultFont;
132 extern int agTextFontHeight;
133 extern int agTextFontAscent;
134 extern int agTextFontDescent;
135 extern int agTextFontLineSkip;
136 extern int agFreetypeInited;
137 extern int agRTL;
138 extern int agGlyphGC;
139 extern AG_TextState *agTextState;
140 extern AG_Mutex agTextLock;
141 extern AG_StaticFont *agBuiltinFonts[];
142 extern const int agBuiltinFontCount;
143 
144 int	 AG_InitTextSubsystem(void);
145 void	 AG_DestroyTextSubsystem(void);
146 
147 void	 AG_TextParseFontSpec(const char *);
148 AG_Font	*AG_FetchFont(const char *, int, int);
149 void     AG_UnusedFont(AG_Font *);
150 void	 AG_SetDefaultFont(AG_Font *);
151 void	 AG_SetRTL(int);
152 
153 void	 AG_PushTextState(void);
154 void	 AG_PopTextState(void);
155 AG_Font *AG_TextFontLookup(const char *, int, Uint);
156 AG_Font *AG_TextFontPts(int);
157 AG_Font *AG_TextFontPct(int);
158 
159 void	 AG_TextSize(const char *, int *, int *);
160 void	 AG_TextSizeMulti(const char *, int *, int *, Uint **, Uint *);
161 void	 AG_TextSizeUCS4(const Uint32 *, int *, int *);
162 void	 AG_TextSizeMultiUCS4(const Uint32 *, int *, int *, Uint **, Uint *);
163 
164 AG_Surface *AG_TextRenderf(const char *, ...);
165 AG_Surface *AG_TextRenderUCS4(const Uint32 *);
166 
167 void AG_TextMsgS(enum ag_text_msg_title, const char *);
168 void AG_TextMsg(enum ag_text_msg_title, const char *, ...)
169                 FORMAT_ATTRIBUTE(printf,2,3)
170 		NONNULL_ATTRIBUTE(2);
171 
172 void AG_TextTmsgS(enum ag_text_msg_title, Uint32, const char *);
173 void AG_TextTmsg(enum ag_text_msg_title, Uint32, const char *, ...)
174 	         FORMAT_ATTRIBUTE(printf,3,4)
175 		 NONNULL_ATTRIBUTE(3);
176 
177 void AG_TextInfoS(const char *, const char *);
178 void AG_TextInfo(const char *, const char *, ...)
179 	         FORMAT_ATTRIBUTE(printf,2,3)
180 		 NONNULL_ATTRIBUTE(2);
181 
182 void AG_TextWarningS(const char *, const char *);
183 void AG_TextWarning(const char *, const char *, ...)
184 	            FORMAT_ATTRIBUTE(printf,2,3)
185 	            NONNULL_ATTRIBUTE(2);
186 
187 void AG_TextErrorS(const char *);
188 void AG_TextError(const char *, ...)
189 	          FORMAT_ATTRIBUTE(printf,1,2)
190 	          NONNULL_ATTRIBUTE(1);
191 
192 void AG_TextEditFloat(double *, double, double, const char *,
193 		      const char *, ...)
194 		      FORMAT_ATTRIBUTE(printf,5,6)
195 		      NONNULL_ATTRIBUTE(5);
196 void AG_TextEditString(char *, size_t, const char *, ...)
197 		       FORMAT_ATTRIBUTE(printf,3,4)
198 		       NONNULL_ATTRIBUTE(3);
199 struct ag_window *AG_TextPromptOptions(struct ag_button **, Uint, const char *, ...);
200 
201 void      AG_TextInitGlyphCache(AG_Driver *);
202 void      AG_TextClearGlyphCache(AG_Driver *);
203 void      AG_TextDestroyGlyphCache(AG_Driver *);
204 AG_Glyph *AG_TextRenderGlyphMiss(AG_Driver *, Uint32);
205 
206 void AG_TextAlign(int *, int *, int, int, int, int, int, int, int,
207                   int, enum ag_text_justify, enum ag_text_valign);
208 
209 #define AG_TextMsgFromError() \
210 	AG_TextMsgS(AG_MSG_ERROR, AG_GetError())
211 
212 /* Compare two text states. */
213 static __inline__ int
AG_TextStateCompare(const AG_TextState * s1,const AG_TextState * s2)214 AG_TextStateCompare(const AG_TextState *s1, const AG_TextState *s2)
215 {
216 	if (s1->font == s2->font &&
217 	    AG_ColorCompare(s1->color,s2->color) == 0 &&
218 	    AG_ColorCompare(s1->colorBG,s2->colorBG) == 0 &&
219 	    s1->justify == s2->justify &&
220 	    s1->valign == s2->valign &&
221 	    s1->tabWd == s2->tabWd) {
222 		return (0);
223 	}
224 	return (1);
225 }
226 
227 /*
228  * Return the offset in pixels needed to align text based on the current
229  * justification mode.
230  */
231 static __inline__ int
AG_TextJustifyOffset(int w,int wLine)232 AG_TextJustifyOffset(int w, int wLine)
233 {
234 	switch (agTextState->justify) {
235 	case AG_TEXT_LEFT:	return (0);
236 	case AG_TEXT_CENTER:	return (w/2 - wLine/2);
237 	case AG_TEXT_RIGHT:	return (w - wLine);
238 	}
239 	return (0);
240 }
241 
242 /*
243  * Return the offset in pixels needed to align text based on the current
244  * vertical alignment mode.
245  */
246 static __inline__ int
AG_TextValignOffset(int h,int hLine)247 AG_TextValignOffset(int h, int hLine)
248 {
249 	switch (agTextState->valign) {
250 	case AG_TEXT_TOP:	return (0);
251 	case AG_TEXT_MIDDLE:	return (h/2 - hLine/2);
252 	case AG_TEXT_BOTTOM:	return (h - hLine);
253 	}
254 	return (0);
255 }
256 
257 /*
258  * Allocate a transparent surface and render text from a C string.
259  * The string may contain UTF-8 sequences.
260  */
261 static __inline__ AG_Surface *
AG_TextRender(const char * text)262 AG_TextRender(const char *text)
263 {
264 	Uint32 *ucs;
265 	AG_Surface *su;
266 
267 	if ((ucs = AG_ImportUnicode("UTF-8", text, NULL, NULL)) != NULL) {
268 		su = AG_TextRenderUCS4(ucs);
269 		AG_Free(ucs);
270 		return (su);
271 	}
272 	return (NULL);
273 }
274 
275 /*
276  * Lookup/insert a glyph in the glyph cache.
277  * Must be called from GUI rendering context.
278  */
279 static __inline__ AG_Glyph *
AG_TextRenderGlyph(AG_Driver * drv,Uint32 ch)280 AG_TextRenderGlyph(AG_Driver *drv, Uint32 ch)
281 {
282 	AG_Glyph *gl;
283 	Uint h = (Uint)(ch % AG_GLYPH_NBUCKETS);
284 
285 	AG_SLIST_FOREACH(gl, &drv->glyphCache[h].glyphs, glyphs) {
286 		if (ch == gl->ch &&
287 		    agTextState->font == gl->font &&
288 		    AG_ColorCompare(agTextState->color,gl->color) == 0)
289 			break;
290 	}
291 	if (gl == NULL) {
292 		gl = AG_TextRenderGlyphMiss(drv, ch);
293 		AG_SLIST_INSERT_HEAD(&drv->glyphCache[h].glyphs, gl, glyphs);
294 	}
295 	return (gl);
296 }
297 
298 
299 /* Set active text color. */
300 static __inline__ void
AG_TextColor(AG_Color C)301 AG_TextColor(AG_Color C)
302 {
303 	AG_MutexLock(&agTextLock);
304 	agTextState->color = C;
305 	AG_MutexUnlock(&agTextLock);
306 }
307 static __inline__ void
AG_TextColorRGB(Uint8 r,Uint8 g,Uint8 b)308 AG_TextColorRGB(Uint8 r, Uint8 g, Uint8 b)
309 {
310 	AG_MutexLock(&agTextLock);
311 	agTextState->color = AG_ColorRGB(r,g,b);
312 	AG_MutexUnlock(&agTextLock);
313 }
314 static __inline__ void
AG_TextColorRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)315 AG_TextColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
316 {
317 	AG_MutexLock(&agTextLock);
318 	agTextState->color = AG_ColorRGBA(r,g,b,a);
319 	AG_MutexUnlock(&agTextLock);
320 }
321 
322 /* Set text color from 0xRRGGBBAA format. */
323 static __inline__ void
AG_TextColorHex(Uint32 c)324 AG_TextColorHex(Uint32 c)
325 {
326 	AG_MutexLock(&agTextLock);
327 	agTextState->color = AG_ColorHex(c);
328 	AG_MutexUnlock(&agTextLock);
329 }
330 
331 /* Set active text background color. */
332 static __inline__ void
AG_TextBGColor(AG_Color C)333 AG_TextBGColor(AG_Color C)
334 {
335 	AG_MutexLock(&agTextLock);
336 	agTextState->colorBG = C;
337 	AG_MutexUnlock(&agTextLock);
338 }
339 static __inline__ void
AG_TextBGColorRGB(Uint8 r,Uint8 g,Uint8 b)340 AG_TextBGColorRGB(Uint8 r, Uint8 g, Uint8 b)
341 {
342 	AG_MutexLock(&agTextLock);
343 	agTextState->colorBG = AG_ColorRGB(r,g,b);
344 	AG_MutexUnlock(&agTextLock);
345 }
346 static __inline__ void
AG_TextBGColorRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)347 AG_TextBGColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
348 {
349 	AG_MutexLock(&agTextLock);
350 	agTextState->colorBG = AG_ColorRGBA(r,g,b,a);
351 	AG_MutexUnlock(&agTextLock);
352 }
353 
354 /* Set text BG color from 0xRRGGBBAA format. */
355 static __inline__ void
AG_TextBGColorHex(Uint32 c)356 AG_TextBGColorHex(Uint32 c)
357 {
358 	AG_MutexLock(&agTextLock);
359 	agTextState->colorBG = AG_ColorHex(c);
360 	AG_MutexUnlock(&agTextLock);
361 }
362 
363 /* Select a specific font face to use in rendering text. */
364 static __inline__ void
AG_TextFont(AG_Font * font)365 AG_TextFont(AG_Font *font)
366 {
367 	AG_MutexLock(&agTextLock);
368 	agTextState->font = font;
369 	AG_MutexUnlock(&agTextLock);
370 }
371 
372 /* Select the justification mode to use in rendering text. */
373 static __inline__ void
AG_TextJustify(enum ag_text_justify mode)374 AG_TextJustify(enum ag_text_justify mode)
375 {
376 	AG_MutexLock(&agTextLock);
377 	agTextState->justify = mode;
378 	AG_MutexUnlock(&agTextLock);
379 }
380 
381 /* Select the vertical alignment mode to use in rendering text. */
382 static __inline__ void
AG_TextValign(enum ag_text_valign mode)383 AG_TextValign(enum ag_text_valign mode)
384 {
385 	AG_MutexLock(&agTextLock);
386 	agTextState->valign = mode;
387 	AG_MutexUnlock(&agTextLock);
388 }
389 
390 /* Select the tab width in pixels for rendering text. */
391 static __inline__ void
AG_TextTabWidth(int px)392 AG_TextTabWidth(int px)
393 {
394 	AG_MutexLock(&agTextLock);
395 	agTextState->tabWd = px;
396 	AG_MutexUnlock(&agTextLock);
397 }
398 
399 #ifdef AG_LEGACY
400 #define AG_TextFormat AG_TextRenderf
401 
402 static __inline__ void
AG_TextColor32(Uint32 px)403 AG_TextColor32(Uint32 px)
404 {
405 	AG_Color C;
406 
407 	C = AG_GetColorRGB(px, agSurfaceFmt);
408 	AG_MutexLock(&agTextLock);
409 	agTextState->color = C;
410 	AG_MutexUnlock(&agTextLock);
411 }
412 #endif /* AG_LEGACY */
413 
414 __END_DECLS
415 
416 #include <agar/gui/close.h>
417 #endif	/* _AGAR_GUI_TEXT_H_ */
418