summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Levin <al.le@rockbox.org>2009-03-08 16:23:14 +0000
committerAlexander Levin <al.le@rockbox.org>2009-03-08 16:23:14 +0000
commitbded5db2d91d1ec459bcee2e9deed8fca02fac66 (patch)
tree65924c00372319eb63f6eefa26c45d67b032e7eb
parent66cf3a3329f4708be0f89b0b44fd87c26abb256b (diff)
downloadrockbox-bded5db2d91d1ec459bcee2e9deed8fca02fac66.tar.gz
rockbox-bded5db2d91d1ec459bcee2e9deed8fca02fac66.zip
Introduced new options for convbdf that specify how the ascent/descent is allowed to grow to avoid glyph clipping.
The syntax is (for ascent, descent is similar): N[%][!]. E.g. -a3 allows ascent to become 3 pixels greater; -a3! forces ascent to become 3 px greater; -a20% allows ascent to grow 20% from what is specified in the font. By default, ascent/descent are not allowed to grow. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20239 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--tools/convbdf.c344
1 files changed, 287 insertions, 57 deletions
diff --git a/tools/convbdf.c b/tools/convbdf.c
index 8b6ef143a2..51ae5fb806 100644
--- a/tools/convbdf.c
+++ b/tools/convbdf.c
@@ -54,6 +54,9 @@ struct font {
54 54
55 /* unused by runtime system, read in by convbdf */ 55 /* unused by runtime system, read in by convbdf */
56 int nchars; /* number of different glyphs */ 56 int nchars; /* number of different glyphs */
57 int nchars_declared; /* number of glyphs as declared in the header */
58 int ascent_declared; /* ascent as declared in the header */
59 int descent_declared; /* descent as declared in the header */
57 unsigned int* offrot; /* offsets into rotated bitmap data */ 60 unsigned int* offrot; /* offsets into rotated bitmap data */
58 char* name; /* font name */ 61 char* name; /* font name */
59 char* facename; /* facename of font */ 62 char* facename; /* facename of font */
@@ -70,6 +73,13 @@ struct font {
70}; 73};
71/* END font.h*/ 74/* END font.h*/
72 75
76/* Description of how the ascent/descent is allowed to grow */
77struct stretch {
78 int value; /* The delta value (in pixels or percents) */
79 int percent; /* Is the value in percents (true) or pixels (false)? */
80 int force; /* MUST the value be set (true) or is it just a max (false) */
81};
82
73#define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) 83#define isprefix(buf,str) (!strncmp(buf, str, strlen(str)))
74#define strequal(s1,s2) (!strcmp(s1, s2)) 84#define strequal(s1,s2) (!strcmp(s1, s2))
75 85
@@ -78,14 +88,17 @@ struct font {
78 88
79/* Depending on the verbosity level some warnings are printed or not */ 89/* Depending on the verbosity level some warnings are printed or not */
80int verbosity_level = 0; 90int verbosity_level = 0;
91int trace = 0;
81 92
82/* Prints a warning of the specified verbosity level. It will only be 93/* Prints a warning of the specified verbosity level. It will only be
83 really printed if the level is >= the level set in the settings */ 94 really printed if the level is >= the level set in the settings */
84void print_warning(int level, const char *fmt, ...); 95void print_warning(int level, const char *fmt, ...);
85void print_error(const char *fmt, ...); 96void print_error(const char *fmt, ...);
86void print_info(const char *fmt, ...); 97void print_info(const char *fmt, ...);
87#define VL_CLIP 1 /* Verbosity level for clip related warnings */ 98void print_trace(const char *fmt, ...);
88#define VL_MIS 1 /* Verbosity level for other warnings */ 99#define VL_CLIP_FONT 1 /* Verbosity level for clip related warnings at font level */
100#define VL_CLIP_CHAR 2 /* Verbosity level for clip related warnings at char level */
101#define VL_MISC 1 /* Verbosity level for other warnings */
89 102
90int gen_c = 0; 103int gen_c = 0;
91int gen_h = 0; 104int gen_h = 0;
@@ -96,6 +109,10 @@ int limit_char = 65535;
96int oflag = 0; 109int oflag = 0;
97char outfile[256]; 110char outfile[256];
98 111
112struct stretch stretch_ascent = { 0, 0, 1 }; /* Don't allow ascent to grow by default */
113struct stretch stretch_descent = { 0, 0, 1 }; /* Don't allow descent to grow by default */
114
115
99void usage(void); 116void usage(void);
100void getopts(int *pac, char ***pav); 117void getopts(int *pac, char ***pav);
101int convbdf(char *path); 118int convbdf(char *path);
@@ -104,9 +121,20 @@ void free_font(struct font* pf);
104struct font* bdf_read_font(char *path); 121struct font* bdf_read_font(char *path);
105int bdf_read_header(FILE *fp, struct font* pf); 122int bdf_read_header(FILE *fp, struct font* pf);
106int bdf_read_bitmaps(FILE *fp, struct font* pf); 123int bdf_read_bitmaps(FILE *fp, struct font* pf);
124
125/*
126 Counts the glyphs and determines the max dimensions of glyphs
127 (fills the fields nchars, maxwidth, max_over_ascent, max_over_descent).
128 Returns 0 on failure or not-0 on success.
129*/
130int bdf_analyze_font(FILE *fp, struct font* pf);
131void bdf_correct_bbx(int *width, int *bbx); /* Corrects bbx and width if bbx<0 */
132
133/* Corrects the ascent and returns the new value (value to use) */
134int adjust_ascent(int ascent, int overflow, struct stretch *stretch);
135
107char * bdf_getline(FILE *fp, char *buf, int len); 136char * bdf_getline(FILE *fp, char *buf, int len);
108bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2); 137bitmap_t bdf_hexval(unsigned char *buf, int ndx1, int ndx2);
109void bitmap_buf_alloc(struct font* pf);
110 138
111int gen_c_source(struct font* pf, char *path); 139int gen_c_source(struct font* pf, char *path);
112int gen_h_header(struct font* pf, char *path); 140int gen_h_header(struct font* pf, char *path);
@@ -115,20 +143,53 @@ int gen_fnt_file(struct font* pf, char *path);
115void 143void
116usage(void) 144usage(void)
117{ 145{
118 char help[] = { 146 /* We use string array because some C compilers issue warnings about too long strings */
119 "Usage: convbdf [options] [input-files]\n" 147 char *help[] = {
120 " convbdf [options] [-o output-file] [single-input-file]\n" 148 "Usage: convbdf [options] [input-files]\n",
121 "Options:\n" 149 " convbdf [options] [-o output-file] [single-input-file]\n",
122 " -c Convert .bdf to .c source file\n" 150 "Options:\n",
123 " -h Convert .bdf to .h header file (to create sysfont.h)\n" 151 " -c Convert .bdf to .c source file\n",
124 " -f Convert .bdf to .fnt font file\n" 152 " -h Convert .bdf to .h header file (to create sysfont.h)\n",
125 " -s N Start output at character encodings >= N\n" 153 " -f Convert .bdf to .fnt font file\n",
126 " -l N Limit output to character encodings <= N\n" 154 " -s N Start output at character encodings >= N\n",
127 " -n Don't generate bitmaps as comments in .c file\n" 155 " -l N Limit output to character encodings <= N\n",
128 " -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n" 156 " -n Don't generate bitmaps as comments in .c file\n",
157 " -a N[%][!] Allow the ascent to grow N pixels/% to avoid glyph clipping\n",
158 " -d N[%][!] Allow the descent to grow N pixels/% to avoid glyph clipping\n",
159 " -v N Verbosity level: 0=quite quiet, 1=more verbose, 2=even more, etc.\n",
160 " -t Print internal tracing messages\n",
161 NULL /* Must be the last element in the array */
129 }; 162 };
130 163
131 print_info("%s", help); 164 char **p = help;
165 while (*p != NULL)
166 print_info("%s", *(p++));
167}
168
169
170void parse_ascent_opt(char *val, struct stretch *opt) {
171 char buf[256];
172 char *p;
173 strcpy(buf, val);
174
175 opt->force = 0;
176 opt->percent = 0;
177 p = buf + strlen(buf);
178 while (p > buf) {
179 p--;
180 if (*p == '%') {
181 opt->percent = 1;
182 *p = '\0';
183 }
184 else if (*p == '!') {
185 opt->force = 1;
186 *p = '\0';
187 }
188 else {
189 break;
190 }
191 }
192 opt->value = atoi(buf);
132} 193}
133 194
134/* parse command line options*/ 195/* parse command line options*/
@@ -199,6 +260,30 @@ void getopts(int *pac, char ***pav)
199 start_char = atoi(av[0]); 260 start_char = atoi(av[0]);
200 } 261 }
201 break; 262 break;
263 case 'a': /* ascent growth */
264 if (*p) {
265 parse_ascent_opt(p, &stretch_ascent);
266 while (*p && *p != ' ')
267 p++;
268 }
269 else {
270 av++; ac--;
271 if (ac > 0)
272 parse_ascent_opt(av[0], &stretch_ascent);
273 }
274 break;
275 case 'd': /* descent growth */
276 if (*p) {
277 parse_ascent_opt(p, &stretch_descent);
278 while (*p && *p != ' ')
279 p++;
280 }
281 else {
282 av++; ac--;
283 if (ac > 0)
284 parse_ascent_opt(av[0], &stretch_descent);
285 }
286 break;
202 case 'v': /* verbosity */ 287 case 'v': /* verbosity */
203 if (*p) { 288 if (*p) {
204 verbosity_level = atoi(p); 289 verbosity_level = atoi(p);
@@ -211,6 +296,9 @@ void getopts(int *pac, char ***pav)
211 verbosity_level = atoi(av[0]); 296 verbosity_level = atoi(av[0]);
212 } 297 }
213 break; 298 break;
299 case 't': /* tracing */
300 trace = 1;
301 break;
214 default: 302 default:
215 print_info("Unknown option ignored: %c\n", *(p-1)); 303 print_info("Unknown option ignored: %c\n", *(p-1));
216 } 304 }
@@ -230,6 +318,16 @@ void print_warning(int level, const char *fmt, ...) {
230 } 318 }
231} 319}
232 320
321void print_trace(const char *fmt, ...) {
322 if (trace) {
323 va_list ap;
324 va_start(ap, fmt);
325 fprintf(stderr, "TRACE: ");
326 vfprintf(stderr, fmt, ap);
327 va_end(ap);
328 }
329}
330
233void print_error(const char *fmt, ...) { 331void print_error(const char *fmt, ...) {
234 va_list ap; 332 va_list ap;
235 va_start(ap, fmt); 333 va_start(ap, fmt);
@@ -374,21 +472,64 @@ struct font* bdf_read_font(char *path)
374 print_error("Error reading font header\n"); 472 print_error("Error reading font header\n");
375 goto errout; 473 goto errout;
376 } 474 }
475 print_trace("Read font header, nchars_decl=%d\n", pf->nchars_declared);
476
477 if (!bdf_analyze_font(fp, pf)) {
478 print_error("Error analyzing the font\n");
479 goto errout;
480 }
481 print_trace("Analyzed font, nchars=%d, maxwidth=%d, asc_over=%d, desc_over=%d\n",
482 pf->nchars, pf->maxwidth, pf->max_over_ascent, pf->max_over_descent);
483
484 if (pf->nchars != pf->nchars_declared) {
485 print_warning(VL_MISC, "The declared number of chars (%d) "
486 "does not match the real number (%d)\n",
487 pf->nchars_declared, pf->nchars);
488 }
489
490 /* Correct ascent/descent if necessary */
491 pf->ascent = adjust_ascent(pf->ascent_declared, pf->max_over_ascent, &stretch_ascent);
492 if (pf->ascent != pf->ascent_declared) {
493 print_info("Font ascent has been changed from %d to %d\n",
494 pf->ascent_declared, pf->ascent);
495 }
496 pf->descent = adjust_ascent(pf->descent, pf->max_over_descent, &stretch_descent);
497 if (pf->descent != pf->descent_declared) {
498 print_info("Font descent has been changed from %d to %d\n",
499 pf->descent_declared, pf->descent);
500 }
501 pf->height = pf->ascent + pf->descent;
502 if (pf->height != pf->ascent_declared + pf->descent_declared) {
503 print_warning(VL_CLIP_FONT, "Generated font's height: %d\n", pf->height);
504 }
505
506 /* Alocate memory */
507 pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height;
508 pf->bits = (bitmap_t *)malloc(pf->bits_size * sizeof(bitmap_t));
509 pf->offset = (int *)malloc(pf->size * sizeof(int));
510 pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
511 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
512
513 if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
514 print_error("no memory for font load\n");
515 goto errout;
516 }
377 517
378 pf->max_over_ascent = pf->max_over_descent = 0;
379 pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0; 518 pf->num_clipped_ascent = pf->num_clipped_descent = pf->num_clipped = 0;
519 pf->max_over_ascent = pf->max_over_descent = 0;
380 520
381 if (!bdf_read_bitmaps(fp, pf)) { 521 if (!bdf_read_bitmaps(fp, pf)) {
382 print_error("Error reading font bitmaps\n"); 522 print_error("Error reading font bitmaps\n");
383 goto errout; 523 goto errout;
384 } 524 }
525 print_trace("Read bitmaps\n");
385 526
386 if (pf->num_clipped > 0) { 527 if (pf->num_clipped > 0) {
387 print_warning(VL_CLIP, "%d character(s) out of %d were clipped " 528 print_warning(VL_CLIP_FONT, "%d character(s) out of %d were clipped "
388 "(%d at ascent, %d at descent)\n", 529 "(%d at ascent, %d at descent)\n",
389 pf->num_clipped, pf->nchars, 530 pf->num_clipped, pf->nchars,
390 pf->num_clipped_ascent, pf->num_clipped_descent); 531 pf->num_clipped_ascent, pf->num_clipped_descent);
391 print_warning(VL_CLIP, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n", 532 print_warning(VL_CLIP_FONT, "max overflows: %d pixel(s) at ascent, %d pixel(s) at descent\n",
392 pf->max_over_ascent, pf->max_over_descent); 533 pf->max_over_ascent, pf->max_over_descent);
393 } 534 }
394 535
@@ -444,17 +585,19 @@ int bdf_read_header(FILE *fp, struct font* pf)
444 } 585 }
445 } 586 }
446 if (isprefix(buf, "FONT_DESCENT ")) { 587 if (isprefix(buf, "FONT_DESCENT ")) {
447 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) { 588 if (sscanf(buf, "FONT_DESCENT %d", &pf->descent_declared) != 1) {
448 print_error("bad 'FONT_DESCENT'\n"); 589 print_error("bad 'FONT_DESCENT'\n");
449 return 0; 590 return 0;
450 } 591 }
592 pf->descent = pf->descent_declared; /* For now */
451 continue; 593 continue;
452 } 594 }
453 if (isprefix(buf, "FONT_ASCENT ")) { 595 if (isprefix(buf, "FONT_ASCENT ")) {
454 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) { 596 if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent_declared) != 1) {
455 print_error("bad 'FONT_ASCENT'\n"); 597 print_error("bad 'FONT_ASCENT'\n");
456 return 0; 598 return 0;
457 } 599 }
600 pf->ascent = pf->ascent_declared; /* For now */
458 continue; 601 continue;
459 } 602 }
460 if (isprefix(buf, "FONTBOUNDINGBOX ")) { 603 if (isprefix(buf, "FONTBOUNDINGBOX ")) {
@@ -466,7 +609,7 @@ int bdf_read_header(FILE *fp, struct font* pf)
466 continue; 609 continue;
467 } 610 }
468 if (isprefix(buf, "CHARS ")) { 611 if (isprefix(buf, "CHARS ")) {
469 if (sscanf(buf, "CHARS %d", &pf->nchars) != 1) { 612 if (sscanf(buf, "CHARS %d", &pf->nchars_declared) != 1) {
470 print_error("bad 'CHARS'\n"); 613 print_error("bad 'CHARS'\n");
471 return 0; 614 return 0;
472 } 615 }
@@ -515,20 +658,6 @@ int bdf_read_header(FILE *fp, struct font* pf)
515 /* calc font size (offset/width entries) */ 658 /* calc font size (offset/width entries) */
516 pf->firstchar = firstchar; 659 pf->firstchar = firstchar;
517 pf->size = lastchar - firstchar + 1; 660 pf->size = lastchar - firstchar + 1;
518
519 /* use the font boundingbox to get initial maxwidth */
520 /*maxwidth = pf->fbbw - pf->fbbx;*/
521 pf->maxwidth = pf->fbbw;
522 bitmap_buf_alloc(pf); /* Allocate bitmaps */
523
524 pf->offset = (int *)malloc(pf->size * sizeof(int));
525 pf->offrot = (unsigned int *)malloc(pf->size * sizeof(unsigned int));
526 pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char));
527
528 if (!pf->bits || !pf->offset || !pf->offrot || !pf->width) {
529 print_error("no memory for font load\n");
530 return 0;
531 }
532 661
533 return 1; 662 return 1;
534} 663}
@@ -610,15 +739,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
610 pf->offrot[encoding-pf->firstchar] = ofr; 739 pf->offrot[encoding-pf->firstchar] = ofr;
611 740
612 /* calc char width */ 741 /* calc char width */
613 if (bbx < 0) { 742 bdf_correct_bbx(&width, &bbx);
614 /* Rockbox can't render overlapping glyphs */
615 width -= bbx;
616 bbx = 0;
617 }
618 if (width > pf->maxwidth) {
619 pf->maxwidth = width;
620 bitmap_buf_alloc(pf); /* Re-allocate bitmaps since the maxwidth has grown */
621 }
622 pf->width[encoding-pf->firstchar] = width; 743 pf->width[encoding-pf->firstchar] = width;
623 744
624 ch_bitmap = pf->bits + ofs; 745 ch_bitmap = pf->bits + ofs;
@@ -638,7 +759,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
638 pf->max_over_ascent = overflow_asc; 759 pf->max_over_ascent = overflow_asc;
639 } 760 }
640 bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */ 761 bbh = MAX(bbh - overflow_asc, 0); /* Clipped -> decrease the height */
641 print_warning(VL_CLIP, "character %d goes %d pixel(s)" 762 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
642 " beyond the font's ascent, it will be clipped\n", 763 " beyond the font's ascent, it will be clipped\n",
643 encoding, overflow_asc); 764 encoding, overflow_asc);
644 } 765 }
@@ -650,7 +771,7 @@ int bdf_read_bitmaps(FILE *fp, struct font* pf)
650 } 771 }
651 bby += overflow_desc; 772 bby += overflow_desc;
652 bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */ 773 bbh = MAX(bbh - overflow_desc, 0); /* Clipped -> decrease the height */
653 print_warning(VL_CLIP, "character %d goes %d pixel(s)" 774 print_warning(VL_CLIP_CHAR, "character %d goes %d pixel(s)"
654 " beyond the font's descent, it will be clipped\n", 775 " beyond the font's descent, it will be clipped\n",
655 encoding, overflow_desc); 776 encoding, overflow_desc);
656 } 777 }
@@ -796,17 +917,126 @@ char *bdf_getline(FILE *fp, char *buf, int len)
796 } 917 }
797 return buf; 918 return buf;
798} 919}
799 920
800/* 921void bdf_correct_bbx(int *width, int *bbx) {
801 Calculates the necessary size of the bit buffer to hold all the 922 if (*bbx < 0) {
802 bitmaps for the glyphs in the font. Shoud be called every time 923 /* Rockbox can't render overlapping glyphs */
803 the max width of the font grows. Font height, the max width and 924 *width -= *bbx;
804 the number of chars in the font must have been already set. 925 *bbx = 0;
805*/ 926 }
806void bitmap_buf_alloc(struct font* pf) 927}
807{ 928
808 pf->bits_size = pf->size * BITMAP_WORDS(pf->maxwidth) * pf->height; 929int bdf_analyze_font(FILE *fp, struct font* pf) {
809 pf->bits = (bitmap_t *)realloc(pf->bits, pf->bits_size * sizeof(bitmap_t)); 930 char buf[256];
931 int encoding;
932 int width, bbw, bbh, bbx, bby, overflow;
933 int read_enc = 0, read_width = 0, read_bbx = 0, read_endchar = 1;
934 int ignore_char = 0;
935
936 /* reset file pointer */
937 fseek(fp, 0L, SEEK_SET);
938
939 pf->maxwidth = 0;
940 pf->nchars = 0;
941 pf->max_over_ascent = pf->max_over_descent = 0;
942
943 for (;;) {
944
945 if (!bdf_getline(fp, buf, sizeof(buf))) {
946 print_error("EOF on file\n");
947 return 0;
948 }
949 if (isprefix(buf, "ENDFONT")) {
950 if (!read_endchar) {
951 print_error("No terminating ENDCHAR for character %d\n", encoding);
952 return 0;
953 }
954 break;
955 }
956 if (isprefix(buf, "STARTCHAR")) {
957 print_trace("Read STARTCHAR, nchars=%d, read_endchar=%d\n", pf->nchars, read_endchar);
958 if (!read_endchar) {
959 print_error("No terminating ENDCHAR for character %d\n", encoding);
960 return 0;
961 }
962 read_enc = read_width = read_bbx = read_endchar = 0;
963 continue;
964 }
965 if (isprefix(buf, "ENDCHAR")) {
966 if (!read_enc) {
967 print_error("ENCODING is not specified\n");
968 return 0;
969 }
970 ignore_char = (encoding < start_char || encoding > limit_char);
971 if (!ignore_char) {
972 if (!read_width || !read_bbx) {
973 print_error("WIDTH or BBX is not specified for character %d\n",
974 encoding);
975 }
976 bdf_correct_bbx(&width, &bbx);
977 if (width > pf->maxwidth) {
978 pf->maxwidth = width;
979 }
980 overflow = bby + bbh - pf->ascent;
981 if (overflow > pf->max_over_ascent) {
982 pf->max_over_ascent = overflow;
983 }
984 overflow = -bby - pf->descent;
985 if (overflow > pf->max_over_descent) {
986 pf->max_over_descent = overflow;
987 }
988 }
989 pf->nchars++;
990 read_endchar = 1;
991 continue;
992 }
993 if (isprefix(buf, "ENCODING ")) {
994 if (sscanf(buf, "ENCODING %d", &encoding) != 1) {
995 print_error("bad 'ENCODING': '%s'\n", buf);
996 return 0;
997 }
998 read_enc = 1;
999 continue;
1000 }
1001 if (isprefix(buf, "DWIDTH ")) {
1002 if (sscanf(buf, "DWIDTH %d", &width) != 1) {
1003 print_error("bad 'DWIDTH': '%s'\n", buf);
1004 return 0;
1005 }
1006 /* use font boundingbox width if DWIDTH <= 0 */
1007 if (width < 0) {
1008 print_error("Negative char width: %d\n", width);
1009 return 0;
1010 }
1011 read_width = 1;
1012 }
1013 if (isprefix(buf, "BBX ")) {
1014 if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) {
1015 print_error("bad 'BBX': '%s'\n", buf);
1016 return 0;
1017 }
1018 read_bbx = 1;
1019 continue;
1020 }
1021 }
1022 return 1;
1023}
1024
1025int adjust_ascent(int ascent, int overflow, struct stretch *stretch) {
1026 int result;
1027 int px = stretch->value;
1028 if (stretch->percent) {
1029 px = ascent * px / 100;
1030 }
1031
1032 if (stretch->force) {
1033 result = ascent + px;
1034 }
1035 else {
1036 result = ascent + MIN(overflow, px);
1037 }
1038 result = MAX(result, 0);
1039 return result;
810} 1040}
811 1041
812 1042