Mercurial > mplayer.hg
annotate gui/skin/font.c @ 36182:8587ae275646
Rename HAVE_CMOV to HAVE_I686 for FFmpeg.
Keep the cmov name in configure since it is less
confusing, since cmov is what we test for and
also since for example VIA C3 sometimes is considered
i686 that does not implement the optional CMOV
instruction.
author | reimar |
---|---|
date | Fri, 17 May 2013 15:59:38 +0000 |
parents | c667e34fb941 |
children | 896b8c73943e |
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 |
36032 | 35 #include "mp_msg.h" |
32869 | 36 #include "libavutil/avstring.h" |
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 } |