Mercurial > mplayer.hg
annotate gui/skin/font.c @ 36016:7ee29db149cd
Cosmetic: Rearrange code.
author | ib |
---|---|
date | Sun, 31 Mar 2013 12:10:42 +0000 |
parents | fcc519c99311 |
children | c667e34fb941 |
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 | |
36013 | 24 #include <glib.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" | |
35530 | 30 #include "skin.h" |
33046 | 31 #include "gui/util/cut.h" |
33739 | 32 #include "gui/util/mem.h" |
33048 | 33 #include "gui/util/string.h" |
32869 | 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 { |
34578 | 107 FILE *file; |
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)); | |
34578 | 121 file = fopen(buf, "rt"); |
32839
2dd39155f320
Cosmetic: Make conditions more readable by having assignments outside.
ib
parents:
32838
diff
changeset
|
122 |
34578 | 123 if (!file) { |
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 |
34578 | 128 while (fgetstr(buf, sizeof(buf), file)) { |
33082 | 129 strswap(buf, '\t', ' '); |
130 trim(buf); | |
131 decomment(buf); | |
32869 | 132 |
33082 | 133 if (!*buf) |
32869 | 134 continue; |
135 | |
33082 | 136 n = (strncmp(buf, "\"=", 2) == 0 ? 1 : 0); |
137 cutItem(buf, item, '=', n); | |
138 cutItem(buf, param, '=', n + 1); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
139 |
33082 | 140 if (item[0] == '"') { |
141 if (!item[1]) | |
142 item[0] = '='; | |
143 else if (item[1] == '"') | |
144 item[1] = 0; | |
32869 | 145 else |
33082 | 146 cutItem(item, item, '"', 1); |
32869 | 147 |
33082 | 148 if (item[0] & 0x80) { |
32869 | 149 for (i = 0; i < EXTRA_CHRS; i++) { |
150 if (!Fonts[id]->nonASCIIidx[i][0]) { | |
33082 | 151 strncpy(Fonts[id]->nonASCIIidx[i], item, UTF8LENGTH); |
32869 | 152 break; |
153 } | |
154 } | |
155 | |
156 if (i == EXTRA_CHRS) | |
157 continue; | |
158 | |
159 i += ASCII_CHRS; | |
160 } else | |
33082 | 161 i = item[0]; |
32869 | 162 |
33082 | 163 cutItem(param, buf, ',', 0); |
164 Fonts[id]->Fnt[i].x = atoi(buf); | |
32869 | 165 |
33082 | 166 cutItem(param, buf, ',', 1); |
167 Fonts[id]->Fnt[i].y = atoi(buf); | |
32869 | 168 |
33082 | 169 cutItem(param, buf, ',', 2); |
170 Fonts[id]->Fnt[i].sx = atoi(buf); | |
32869 | 171 |
33082 | 172 cutItem(param, buf, ',', 3); |
173 Fonts[id]->Fnt[i].sy = atoi(buf); | |
32869 | 174 |
33985 | 175 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 | 176 } else if (!strcmp(item, "image")) { |
177 av_strlcpy(buf, path, sizeof(buf)); | |
178 av_strlcat(buf, param, sizeof(buf)); | |
32869 | 179 |
33985 | 180 mp_msg(MSGT_GPLAYER, MSGL_DBG2, "[font] image file: %s\n", buf); |
32869 | 181 |
33969 | 182 if (skinImageRead(buf, &Fonts[id]->Bitmap) != 0) { |
32917
9949f3a123cf
Add new function bpFree() to free txSamples (bitmaps).
ib
parents:
32869
diff
changeset
|
183 bpFree(&Fonts[id]->Bitmap); |
33739 | 184 nfree(Fonts[id]); |
34578 | 185 fclose(file); |
32869 | 186 return -4; |
187 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
188 } |
23077 | 189 } |
190 | |
34578 | 191 fclose(file); |
33053 | 192 |
32869 | 193 return 0; |
23077 | 194 } |
195 | |
33973 | 196 /** |
197 * @brief Find the ID of a font by its name. | |
198 * | |
199 * @param name name of the font | |
200 * | |
201 * @return an identification >= 0 (ok) or -1 (not found) | |
202 */ | |
32869 | 203 int fntFindID(char *name) |
23077 | 204 { |
32869 | 205 int i; |
206 | |
207 for (i = 0; i < MAX_FONTS; i++) | |
208 if (Fonts[i]) | |
209 if (!strcmp(name, Fonts[i]->name)) | |
210 return i; | |
211 | |
212 return -1; | |
23077 | 213 } |
214 | |
33973 | 215 /** |
216 * @brief Get the #bmpFont::Fnt index of the character @a *str points to. | |
217 * | |
218 * Move pointer @a *str to the character according to @a direction | |
219 * afterwards. | |
220 * | |
221 * @param id font ID | |
222 * @param str pointer to the string | |
223 * @param uft8 flag indicating whether @a str contains UTF-8 characters | |
224 * @param direction +1 (forward) or -1 (backward) | |
225 * | |
226 * @return index >= 0 (ok) or -1 (not found) | |
227 */ | |
32869 | 228 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
|
229 { |
32869 | 230 unsigned char *p, uchar[6] = ""; // glib implements 31-bit UTF-8 |
231 int i, c = -1; | |
232 | |
233 if (**str & 0x80) { | |
234 if (utf8) { | |
235 p = *str; | |
236 *str = g_utf8_next_char(*str); | |
237 strncpy(uchar, p, *str - p); | |
238 | |
239 if (direction < 0) | |
240 *str = g_utf8_prev_char(p); | |
241 } else { | |
242 uchar[0] = **str; | |
243 *str += direction; | |
244 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
245 |
32869 | 246 for (i = 0; (i < EXTRA_CHRS) && Fonts[id]->nonASCIIidx[i][0]; i++) { |
247 if (strncmp(Fonts[id]->nonASCIIidx[i], uchar, UTF8LENGTH) == 0) | |
248 return i + ASCII_CHRS; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
249 |
32869 | 250 if (!utf8 && |
251 (Fonts[id]->nonASCIIidx[i][0] == (*uchar >> 6 | 0xc0) && | |
252 Fonts[id]->nonASCIIidx[i][1] == ((*uchar & 0x3f) | 0x80) && | |
253 Fonts[id]->nonASCIIidx[i][2] == 0)) | |
254 c = i + ASCII_CHRS; | |
255 } | |
256 } else { | |
257 c = **str; | |
258 | |
259 if (utf8 && (direction < 0)) | |
260 *str = g_utf8_prev_char(*str); | |
261 else | |
262 *str += direction; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
263 } |
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
264 |
32869 | 265 return c; |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
266 } |
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
267 |
33973 | 268 /** |
269 * @brief Get the rendering width of a text. | |
270 * | |
271 * @param id font ID | |
272 * @param str string to be examined | |
273 * | |
274 * @return width of the rendered string (in pixels) | |
275 */ | |
32869 | 276 int fntTextWidth(int id, char *str) |
23077 | 277 { |
32869 | 278 int size = 0, c; |
279 gboolean utf8; | |
280 unsigned char *p; | |
281 | |
282 utf8 = g_utf8_validate(str, -1, NULL); | |
283 p = str; | |
23077 | 284 |
32869 | 285 while (*p) { |
286 c = fntGetCharIndex(id, &p, utf8, 1); | |
287 | |
288 if (c == -1 || Fonts[id]->Fnt[c].sx == -1) | |
289 c = ' '; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
290 |
32869 | 291 if (Fonts[id]->Fnt[c].sx != -1) |
292 size += Fonts[id]->Fnt[c].sx; | |
293 } | |
294 | |
295 return size; | |
23077 | 296 } |
297 | |
33973 | 298 /** |
299 * @brief Get the rendering height of a text. | |
300 * | |
301 * @param id font ID | |
302 * @param str string to be examined | |
303 * | |
304 * @return height of the rendered string (in pixels) | |
305 */ | |
32869 | 306 static int fntTextHeight(int id, char *str) |
23077 | 307 { |
32869 | 308 int max = 0, c, h; |
309 gboolean utf8; | |
310 unsigned char *p; | |
23077 | 311 |
32869 | 312 utf8 = g_utf8_validate(str, -1, NULL); |
313 p = str; | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
314 |
32869 | 315 while (*p) { |
316 c = fntGetCharIndex(id, &p, utf8, 1); | |
317 | |
318 if (c == -1 || Fonts[id]->Fnt[c].sx == -1) | |
319 c = ' '; | |
320 | |
321 h = Fonts[id]->Fnt[c].sy; | |
322 | |
323 if (h > max) | |
324 max = h; | |
325 } | |
326 | |
327 return max; | |
23077 | 328 } |
329 | |
33973 | 330 /** |
331 * @brief Render a text on an item. | |
332 * | |
333 * @param item item the text shall be placed on | |
334 * @param px x position for the text in case it is wider than the item width | |
335 * @param txt text to be rendered | |
336 * | |
337 * @return image containing the rendered text | |
338 */ | |
35688 | 339 guiImage *fntTextRender(guiItem *item, int px, char *txt) |
23077 | 340 { |
32869 | 341 unsigned char *u; |
342 unsigned int i; | |
343 int c, dx, tw, th, fbw, iw, id, ofs; | |
344 int x, y, fh, fw, fyc, yc; | |
345 uint32_t *ibuf; | |
346 uint32_t *obuf; | |
347 gboolean utf8; | |
23077 | 348 |
32869 | 349 id = item->fontid; |
350 tw = fntTextWidth(id, txt); | |
23077 | 351 |
32869 | 352 if (!tw) |
353 return NULL; | |
23077 | 354 |
32869 | 355 iw = item->width; |
356 fbw = Fonts[id]->Bitmap.Width; | |
357 th = fntTextHeight(id, txt); | |
358 | |
359 if (item->height != th) | |
32917
9949f3a123cf
Add new function bpFree() to free txSamples (bitmaps).
ib
parents:
32869
diff
changeset
|
360 bpFree(&item->Bitmap); |
23077 | 361 |
32869 | 362 if (!item->Bitmap.Image) { |
363 item->Bitmap.Height = item->height = th; | |
364 item->Bitmap.Width = item->width = iw; | |
365 item->Bitmap.ImageSize = item->height * iw * 4; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
366 |
32869 | 367 if (!item->Bitmap.ImageSize) |
368 return NULL; | |
369 | |
33555 | 370 item->Bitmap.Bpp = 32; |
32869 | 371 item->Bitmap.Image = malloc(item->Bitmap.ImageSize); |
372 | |
373 if (!item->Bitmap.Image) | |
374 return NULL; | |
23077 | 375 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
376 |
32869 | 377 obuf = (uint32_t *)item->Bitmap.Image; |
378 ibuf = (uint32_t *)Fonts[id]->Bitmap.Image; | |
23077 | 379 |
32869 | 380 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
|
381 obuf[i] = GUI_TRANSPARENT; |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
382 |
32869 | 383 if (tw <= iw) { |
384 switch (item->align) { | |
385 default: | |
386 case fntAlignLeft: | |
387 dx = 0; | |
388 break; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
389 |
32869 | 390 case fntAlignCenter: |
391 dx = (iw - tw) / 2; | |
392 break; | |
32792
31ce0bd110d5
Only replace non-existing font character by space if space itself exists.
ib
parents:
32791
diff
changeset
|
393 |
32869 | 394 case fntAlignRight: |
395 dx = iw - tw; | |
396 break; | |
397 } | |
398 } else | |
399 dx = px; | |
400 | |
401 ofs = dx; | |
402 | |
403 utf8 = g_utf8_validate(txt, -1, NULL); | |
404 u = txt; | |
405 | |
406 while (*u) { | |
407 c = fntGetCharIndex(id, &u, utf8, 1); | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
408 |
32869 | 409 if (c != -1) |
410 fw = Fonts[id]->Fnt[c].sx; | |
411 | |
412 if (c == -1 || fw == -1) { | |
413 c = ' '; | |
414 fw = Fonts[id]->Fnt[c].sx; | |
415 } | |
416 | |
417 if (fw == -1) | |
418 continue; | |
419 | |
420 fh = Fonts[id]->Fnt[c].sy; | |
421 fyc = Fonts[id]->Fnt[c].y * fbw + Fonts[id]->Fnt[c].x; | |
422 yc = dx; | |
23077 | 423 |
32869 | 424 if (dx >= 0) { |
425 for (y = 0; y < fh; y++) { | |
426 for (x = 0; x < fw; x++) | |
427 if (dx + x >= 0 && dx + x < iw) | |
428 obuf[yc + x] = ibuf[fyc + x]; | |
429 | |
430 fyc += fbw; | |
431 yc += iw; | |
432 } | |
433 } | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
434 |
32869 | 435 dx += fw; |
436 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
26458
diff
changeset
|
437 |
32869 | 438 if (ofs > 0 && tw > item->width) { |
439 dx = ofs; | |
440 u = txt + strlen(txt); | |
32734
cc58a1e919d9
Allow character in the font description file to be in UTF-8.
ib
parents:
32712
diff
changeset
|
441 |
32869 | 442 while (u > (unsigned char *)txt) { |
443 c = fntGetCharIndex(id, &u, utf8, -1); | |
23077 | 444 |
32869 | 445 if (c != -1) |
446 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
|
447 |
32869 | 448 if (c == -1 || fw == -1) { |
449 c = ' '; | |
450 fw = Fonts[id]->Fnt[c].sx; | |
451 } | |
452 | |
453 if (fw == -1) | |
454 continue; | |
455 | |
456 fh = Fonts[id]->Fnt[c].sy; | |
457 fyc = Fonts[id]->Fnt[c].y * fbw + Fonts[id]->Fnt[c].x; | |
458 | |
459 dx -= fw; | |
460 yc = dx; | |
23077 | 461 |
32869 | 462 if (dx >= 0) { |
463 for (y = 0; y < fh; y++) { | |
464 for (x = fw - 1; x >= 0; x--) | |
465 if (dx + x >= 0 && dx + x < iw) | |
466 obuf[yc + x] = ibuf[fyc + x]; | |
467 | |
468 fyc += fbw; | |
469 yc += iw; | |
470 } | |
471 } | |
472 } | |
23077 | 473 } |
474 | |
32869 | 475 return &item->Bitmap; |
23077 | 476 } |