Mercurial > mplayer.hg
annotate gui/skin/font.c @ 34341:946ecaf41dc1
Don't allow option gui-include in config files.
This option may only be evaluated after MPlayer has called cfg_read()
or a segmentation fault occurs. Prevent this by restricting its usage.
author | ib |
---|---|
date | Sun, 11 Dec 2011 14:54:56 +0000 |
parents | d99f341d8442 |
children | abcf26dcec6b |
rev | line source |
---|---|
26458 | 1 /* |
2 * This file is part of MPlayer. | |
3 * | |
4 * MPlayer is free software; you can redistribute it and/or modify | |
5 * it under the terms of the GNU General Public License as published by | |
6 * the Free Software Foundation; either version 2 of the License, or | |
7 * (at your option) any later version. | |
8 * | |
9 * MPlayer is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License along | |
15 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
17 */ | |
23077 | 18 |
33973 | 19 /** |
20 * @file | |
21 * @brief Font file parser and font rendering | |
22 */ | |
23 | |
32851 | 24 #include <gtk/gtk.h> |
33123
9566100d88a1
Replace inttypes.h by stdint.h and remove inttypes.h where unneeded.
ib
parents:
33082
diff
changeset
|
25 #include <stdint.h> |
23077 | 26 #include <stdlib.h> |
27 #include <string.h> | |
28 | |
29 #include "font.h" | |
33046 | 30 #include "gui/util/cut.h" |
33739 | 31 #include "gui/util/mem.h" |
33048 | 32 #include "gui/util/string.h" |
32869 | 33 #include "skin.h" |
34 | |
35 #include "libavutil/avstring.h" | |
26382
b2f4abcf20ed
Make include paths consistent; do not use ../ in them.
diego
parents:
26365
diff
changeset
|
36 #include "mp_msg.h" |
32869 | 37 |
33269 | 38 #define MAX_FONTS 25 |
39 | |
40 #define fntAlignLeft 0 | |
41 #define fntAlignCenter 1 | |
42 #define fntAlignRight 2 | |
43 | |
32869 | 44 static bmpFont *Fonts[MAX_FONTS]; |
23077 | 45 |
33973 | 46 /** |
47 * @brief Add a font to #Fonts. | |
48 * | |
49 * @param name name of the font | |
50 * | |
51 * @return an identification >= 0 (ok), -1 (out of memory) or -2 (#MAX_FONTS exceeded) | |
52 */ | |
32869 | 53 static int fntAddNewFont(char *name) |
54 { | |
55 int id, i; | |
23077 | 56 |
32869 | 57 for (id = 0; id < MAX_FONTS; id++) |
58 if (!Fonts[id]) | |
59 break; | |
23077 | 60 |
32869 | 61 if (id == MAX_FONTS) |
62 return -2; | |
23077 | 63 |
32869 | 64 Fonts[id] = calloc(1, sizeof(*Fonts[id])); |
23077 | 65 |
32869 | 66 if (!Fonts[id]) |
67 return -1; | |
32839
2dd39155f320
Cosmetic: Make conditions more readable by having assignments outside.
ib
parents:
32838
diff
changeset
|
68 |
32869 | 69 av_strlcpy(Fonts[id]->name, name, MAX_FONT_NAME); |
23077 | 70 |
32869 | 71 for (i = 0; i < ASCII_CHRS + EXTRA_CHRS; i++) { |
72 Fonts[id]->Fnt[i].x = -1; | |
73 Fonts[id]->Fnt[i].y = -1; | |
74 Fonts[id]->Fnt[i].sx = -1; | |
75 Fonts[id]->Fnt[i].sy = -1; | |
76 } | |
23077 | 77 |
32869 | 78 return id; |
23077 | 79 } |
80 | |
33973 | 81 /** |
82 * @brief Free all memory allocated to fonts. | |
83 */ | |
32869 | 84 void fntFreeFont(void) |
23077 | 85 { |
32869 | 86 int i; |
87 | |
88 for (i = 0; i < MAX_FONTS; i++) { | |
89 if (Fonts[i]) { | |
32917
9949f3a123cf
Add new function bpFree() to free txSamples (bitmaps).
ib
parents:
32869
diff
changeset
|
90 bpFree(&Fonts[i]->Bitmap); |
33739 | 91 nfree(Fonts[i]); |
32869 | 92 } |
23077 | 93 } |
94 } | |
95 | |
33973 | 96 /** |
97 * @brief Read and parse a font file. | |
98 * | |
99 * @param path directory the font file is in | |
100 * @param fname name of the font | |
101 * | |
102 * @return 0 (ok), -1 or -2 (return code of #fntAddNewFont()), | |
103 * -3 (file error) or -4 (#skinImageRead() error) | |
104 */ | |
32869 | 105 int fntRead(char *path, char *fname) |
23077 | 106 { |
32869 | 107 FILE *f; |
33082 | 108 unsigned char buf[512]; |
109 unsigned char item[32]; | |
32869 | 110 unsigned char param[256]; |
111 int id, n, i; | |
32817 | 112 |
32869 | 113 id = fntAddNewFont(fname); |
114 | |
115 if (id < 0) | |
116 return id; | |
117 | |
33082 | 118 av_strlcpy(buf, path, sizeof(buf)); |
119 av_strlcat(buf, fname, sizeof(buf)); | |
120 av_strlcat(buf, ".fnt", sizeof(buf)); | |
121 f = fopen(buf, "rt"); | |
32839
2dd39155f320
Cosmetic: Make conditions more readable by having assignments outside.
ib
parents:
32838
diff
changeset
|
122 |
32869 | 123 if (!f) { |
33739 | 124 nfree(Fonts[id]); |
32869 | 125 return -3; |
126 } | |
32839
2dd39155f320
Cosmetic: Make conditions more readable by having assignments outside.
ib
parents:
32838
diff
changeset
|
127 |
33082 | 128 while (fgets(buf, sizeof(buf), f)) { |
129 buf[strcspn(buf, "\n\r")] = 0; // remove any kind of newline, if any | |
130 strswap(buf, '\t', ' '); | |
131 trim(buf); | |
132 decomment(buf); | |
32869 | 133 |
33082 | 134 if (!*buf) |
32869 | 135 continue; |
136 | |
33082 | 137 n = (strncmp(buf, "\"=", 2) == 0 ? 1 : 0); |
138 cutItem(buf, item, '=', n); | |
139 cutItem(buf, param, '=', n + 1); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
140 |
33082 | 141 if (item[0] == '"') { |
142 if (!item[1]) | |
143 item[0] = '='; | |
144 else if (item[1] == '"') | |
145 item[1] = 0; | |
32869 | 146 else |
33082 | 147 cutItem(item, item, '"', 1); |
32869 | 148 |
33082 | 149 if (item[0] & 0x80) { |
32869 | 150 for (i = 0; i < EXTRA_CHRS; i++) { |
151 if (!Fonts[id]->nonASCIIidx[i][0]) { | |
33082 | 152 strncpy(Fonts[id]->nonASCIIidx[i], item, UTF8LENGTH); |
32869 | 153 break; |
154 } | |
155 } | |
156 | |
157 if (i == EXTRA_CHRS) | |
158 continue; | |
159 | |
160 i += ASCII_CHRS; | |
161 } else | |
33082 | 162 i = item[0]; |
32869 | 163 |
33082 | 164 cutItem(param, buf, ',', 0); |
165 Fonts[id]->Fnt[i].x = atoi(buf); | |
32869 | 166 |
33082 | 167 cutItem(param, buf, ',', 1); |
168 Fonts[id]->Fnt[i].y = atoi(buf); | |
32869 | 169 |
33082 | 170 cutItem(param, buf, ',', 2); |
171 Fonts[id]->Fnt[i].sx = atoi(buf); | |
32869 | 172 |
33082 | 173 cutItem(param, buf, ',', 3); |
174 Fonts[id]->Fnt[i].sy = atoi(buf); | |
32869 | 175 |
33985 | 176 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[font] char: '%s' params: %d,%d %dx%d\n", item, Fonts[id]->Fnt[i].x, Fonts[id]->Fnt[i].y, Fonts[id]->Fnt[i].sx, Fonts[id]->Fnt[i].sy); |
33082 | 177 } else if (!strcmp(item, "image")) { |
178 av_strlcpy(buf, path, sizeof(buf)); | |
179 av_strlcat(buf, param, sizeof(buf)); | |
32869 | 180 |
33985 | 181 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[font] image file: %s\n", buf); |
32869 | 182 |
33969 | 183 if (skinImageRead(buf, &Fonts[id]->Bitmap) != 0) { |
32917
9949f3a123cf
Add new function bpFree() to free txSamples (bitmaps).
ib
parents:
32869
diff
changeset
|
184 bpFree(&Fonts[id]->Bitmap); |
33739 | 185 nfree(Fonts[id]); |
32869 | 186 fclose(f); |
187 return -4; | |
188 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
189 } |
23077 | 190 } |
191 | |
32869 | 192 fclose(f); |
33053 | 193 |
32869 | 194 return 0; |
23077 | 195 } |
196 | |
33973 | 197 /** |
198 * @brief Find the ID of a font by its name. | |
199 * | |
200 * @param name name of the font | |
201 * | |
202 * @return an identification >= 0 (ok) or -1 (not found) | |
203 */ | |
32869 | 204 int fntFindID(char *name) |
23077 | 205 { |
32869 | 206 int i; |
207 | |
208 for (i = 0; i < MAX_FONTS; i++) | |
209 if (Fonts[i]) | |
210 if (!strcmp(name, Fonts[i]->name)) | |
211 return i; | |
212 | |
213 return -1; | |
23077 | 214 } |
215 | |
33973 | 216 /** |
217 * @brief Get the #bmpFont::Fnt index of the character @a *str points to. | |
218 * | |
219 * Move pointer @a *str to the character according to @a direction | |
220 * afterwards. | |
221 * | |
222 * @param id font ID | |
223 * @param str pointer to the string | |
224 * @param uft8 flag indicating whether @a str contains UTF-8 characters | |
225 * @param direction +1 (forward) or -1 (backward) | |
226 * | |
227 * @return index >= 0 (ok) or -1 (not found) | |
228 */ | |
32869 | 229 static int fntGetCharIndex(int id, unsigned char **str, gboolean utf8, int direction) |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
230 { |
32869 | 231 unsigned char *p, uchar[6] = ""; // glib implements 31-bit UTF-8 |
232 int i, c = -1; | |
233 | |
234 if (**str & 0x80) { | |
235 if (utf8) { | |
236 p = *str; | |
237 *str = g_utf8_next_char(*str); | |
238 strncpy(uchar, p, *str - p); | |
239 | |
240 if (direction < 0) | |
241 *str = g_utf8_prev_char(p); | |
242 } else { | |
243 uchar[0] = **str; | |
244 *str += direction; | |
245 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
246 |
32869 | 247 for (i = 0; (i < EXTRA_CHRS) && Fonts[id]->nonASCIIidx[i][0]; i++) { |
248 if (strncmp(Fonts[id]->nonASCIIidx[i], uchar, UTF8LENGTH) == 0) | |
249 return i + ASCII_CHRS; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
250 |
32869 | 251 if (!utf8 && |
252 (Fonts[id]->nonASCIIidx[i][0] == (*uchar >> 6 | 0xc0) && | |
253 Fonts[id]->nonASCIIidx[i][1] == ((*uchar & 0x3f) | 0x80) && | |
254 Fonts[id]->nonASCIIidx[i][2] == 0)) | |
255 c = i + ASCII_CHRS; | |
256 } | |
257 } else { | |
258 c = **str; | |
259 | |
260 if (utf8 && (direction < 0)) | |
261 *str = g_utf8_prev_char(*str); | |
262 else | |
263 *str += direction; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
264 } |
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
265 |
32869 | 266 return c; |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
267 } |
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
268 |
33973 | 269 /** |
270 * @brief Get the rendering width of a text. | |
271 * | |
272 * @param id font ID | |
273 * @param str string to be examined | |
274 * | |
275 * @return width of the rendered string (in pixels) | |
276 */ | |
32869 | 277 int fntTextWidth(int id, char *str) |
23077 | 278 { |
32869 | 279 int size = 0, c; |
280 gboolean utf8; | |
281 unsigned char *p; | |
282 | |
283 utf8 = g_utf8_validate(str, -1, NULL); | |
284 p = str; | |
23077 | 285 |
32869 | 286 while (*p) { |
287 c = fntGetCharIndex(id, &p, utf8, 1); | |
288 | |
289 if (c == -1 || Fonts[id]->Fnt[c].sx == -1) | |
290 c = ' '; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
291 |
32869 | 292 if (Fonts[id]->Fnt[c].sx != -1) |
293 size += Fonts[id]->Fnt[c].sx; | |
294 } | |
295 | |
296 return size; | |
23077 | 297 } |
298 | |
33973 | 299 /** |
300 * @brief Get the rendering height of a text. | |
301 * | |
302 * @param id font ID | |
303 * @param str string to be examined | |
304 * | |
305 * @return height of the rendered string (in pixels) | |
306 */ | |
32869 | 307 static int fntTextHeight(int id, char *str) |
23077 | 308 { |
32869 | 309 int max = 0, c, h; |
310 gboolean utf8; | |
311 unsigned char *p; | |
23077 | 312 |
32869 | 313 utf8 = g_utf8_validate(str, -1, NULL); |
314 p = str; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
315 |
32869 | 316 while (*p) { |
317 c = fntGetCharIndex(id, &p, utf8, 1); | |
318 | |
319 if (c == -1 || Fonts[id]->Fnt[c].sx == -1) | |
320 c = ' '; | |
321 | |
322 h = Fonts[id]->Fnt[c].sy; | |
323 | |
324 if (h > max) | |
325 max = h; | |
326 } | |
327 | |
328 return max; | |
23077 | 329 } |
330 | |
33973 | 331 /** |
332 * @brief Render a text on an item. | |
333 * | |
334 * @param item item the text shall be placed on | |
335 * @param px x position for the text in case it is wider than the item width | |
336 * @param txt text to be rendered | |
337 * | |
338 * @return image containing the rendered text | |
339 */ | |
33971 | 340 guiImage *fntTextRender(wItem *item, int px, char *txt) |
23077 | 341 { |
32869 | 342 unsigned char *u; |
343 unsigned int i; | |
344 int c, dx, tw, th, fbw, iw, id, ofs; | |
345 int x, y, fh, fw, fyc, yc; | |
346 uint32_t *ibuf; | |
347 uint32_t *obuf; | |
348 gboolean utf8; | |
23077 | 349 |
32869 | 350 id = item->fontid; |
351 tw = fntTextWidth(id, txt); | |
23077 | 352 |
32869 | 353 if (!tw) |
354 return NULL; | |
23077 | 355 |
32869 | 356 iw = item->width; |
357 fbw = Fonts[id]->Bitmap.Width; | |
358 th = fntTextHeight(id, txt); | |
359 | |
360 if (item->height != th) | |
32917
9949f3a123cf
Add new function bpFree() to free txSamples (bitmaps).
ib
parents:
32869
diff
changeset
|
361 bpFree(&item->Bitmap); |
23077 | 362 |
32869 | 363 if (!item->Bitmap.Image) { |
364 item->Bitmap.Height = item->height = th; | |
365 item->Bitmap.Width = item->width = iw; | |
366 item->Bitmap.ImageSize = item->height * iw * 4; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
367 |
32869 | 368 if (!item->Bitmap.ImageSize) |
369 return NULL; | |
370 | |
33555 | 371 item->Bitmap.Bpp = 32; |
32869 | 372 item->Bitmap.Image = malloc(item->Bitmap.ImageSize); |
373 | |
374 if (!item->Bitmap.Image) | |
375 return NULL; | |
23077 | 376 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
377 |
32869 | 378 obuf = (uint32_t *)item->Bitmap.Image; |
379 ibuf = (uint32_t *)Fonts[id]->Bitmap.Image; | |
23077 | 380 |
32869 | 381 for (i = 0; i < item->Bitmap.ImageSize / 4; i++) |
33731
81f71d910333
Cosmetic: Change prefix for symbolic constants from GMP to GUI.
ib
parents:
33728
diff
changeset
|
382 obuf[i] = GUI_TRANSPARENT; |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
383 |
32869 | 384 if (tw <= iw) { |
385 switch (item->align) { | |
386 default: | |
387 case fntAlignLeft: | |
388 dx = 0; | |
389 break; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
390 |
32869 | 391 case fntAlignCenter: |
392 dx = (iw - tw) / 2; | |
393 break; | |
32792
31ce0bd110d5
Only replace non-existing font character by space if space itself exists.
ib
parents:
32791
diff
changeset
|
394 |
32869 | 395 case fntAlignRight: |
396 dx = iw - tw; | |
397 break; | |
398 } | |
399 } else | |
400 dx = px; | |
401 | |
402 ofs = dx; | |
403 | |
404 utf8 = g_utf8_validate(txt, -1, NULL); | |
405 u = txt; | |
406 | |
407 while (*u) { | |
408 c = fntGetCharIndex(id, &u, utf8, 1); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
409 |
32869 | 410 if (c != -1) |
411 fw = Fonts[id]->Fnt[c].sx; | |
412 | |
413 if (c == -1 || fw == -1) { | |
414 c = ' '; | |
415 fw = Fonts[id]->Fnt[c].sx; | |
416 } | |
417 | |
418 if (fw == -1) | |
419 continue; | |
420 | |
421 fh = Fonts[id]->Fnt[c].sy; | |
422 fyc = Fonts[id]->Fnt[c].y * fbw + Fonts[id]->Fnt[c].x; | |
423 yc = dx; | |
23077 | 424 |
32869 | 425 if (dx >= 0) { |
426 for (y = 0; y < fh; y++) { | |
427 for (x = 0; x < fw; x++) | |
428 if (dx + x >= 0 && dx + x < iw) | |
429 obuf[yc + x] = ibuf[fyc + x]; | |
430 | |
431 fyc += fbw; | |
432 yc += iw; | |
433 } | |
434 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
435 |
32869 | 436 dx += fw; |
437 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
438 |
32869 | 439 if (ofs > 0 && tw > item->width) { |
440 dx = ofs; | |
441 u = txt + strlen(txt); | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
442 |
32869 | 443 while (u > (unsigned char *)txt) { |
444 c = fntGetCharIndex(id, &u, utf8, -1); | |
23077 | 445 |
32869 | 446 if (c != -1) |
447 fw = Fonts[id]->Fnt[c].sx; | |
32792
31ce0bd110d5
Only replace non-existing font character by space if space itself exists.
ib
parents:
32791
diff
changeset
|
448 |
32869 | 449 if (c == -1 || fw == -1) { |
450 c = ' '; | |
451 fw = Fonts[id]->Fnt[c].sx; | |
452 } | |
453 | |
454 if (fw == -1) | |
455 continue; | |
456 | |
457 fh = Fonts[id]->Fnt[c].sy; | |
458 fyc = Fonts[id]->Fnt[c].y * fbw + Fonts[id]->Fnt[c].x; | |
459 | |
460 dx -= fw; | |
461 yc = dx; | |
23077 | 462 |
32869 | 463 if (dx >= 0) { |
464 for (y = 0; y < fh; y++) { | |
465 for (x = fw - 1; x >= 0; x--) | |
466 if (dx + x >= 0 && dx + x < iw) | |
467 obuf[yc + x] = ibuf[fyc + x]; | |
468 | |
469 fyc += fbw; | |
470 yc += iw; | |
471 } | |
472 } | |
473 } | |
23077 | 474 } |
475 | |
32869 | 476 return &item->Bitmap; |
23077 | 477 } |