struct.c revision 51b1aeb1
1/* 2Copyright (c) 2002-2003 by Juliusz Chroboczek 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21*/ 22/* $XFree86: xc/programs/fonttosfnt/struct.c,v 1.3 2003/10/24 20:38:11 tsi Exp $ */ 23 24#include <stdlib.h> 25#include <stdio.h> 26#include <ft2build.h> 27#include FT_FREETYPE_H 28#include "fonttosfnt.h" 29 30FontPtr 31makeFont(void) 32{ 33 FontPtr font; 34 35 font = malloc(sizeof(FontRec)); 36 if(font == NULL) 37 return NULL; 38 39 font->numNames = 0; 40 font->names = NULL; 41 font->flags = 0; 42 font->weight = 500; 43 font->width = 5; 44 font->italicAngle = 0; 45 font->underlinePosition = - TWO_SIXTEENTH; 46 font->underlineThickness = TWO_SIXTEENTH; 47 font->foundry = makeName("UNKN"); 48 font->strikes = NULL; 49 return font; 50} 51 52StrikePtr 53makeStrike(FontPtr font, int sizeX, int sizeY) 54{ 55 StrikePtr strike, last_strike; 56 57 strike = font->strikes; 58 last_strike = NULL; 59 while(strike) { 60 if(strike->sizeX == sizeX && strike->sizeY == sizeY) 61 return strike; 62 last_strike = strike; 63 strike = strike->next; 64 } 65 66 strike = malloc(sizeof(StrikeRec)); 67 if(strike == NULL) 68 return NULL; 69 strike->sizeX = sizeX; 70 strike->sizeY = sizeY; 71 strike->bitmaps = 72 calloc(FONT_CODES / FONT_SEGMENT_SIZE, sizeof(BitmapPtr*)); 73 if(strike->bitmaps == NULL) { 74 free(strike); 75 return NULL; 76 } 77 strike->numSbits = 0; 78 strike->next = NULL; 79 strike->bitmapSizeTableLocation = 0xDEADFACE; 80 strike->indexSubTables = NULL; 81 if(last_strike) 82 last_strike->next = strike; 83 else 84 font->strikes = strike; 85 return strike; 86} 87 88BitmapPtr 89makeBitmap(StrikePtr strike, int code, 90 int advanceWidth, int horiBearingX, int horiBearingY, 91 int width, int height, int stride, unsigned char *raster, int crop) 92{ 93 BitmapPtr bitmap; 94 int i, j, x, y; 95 int dx, dy, new_width, new_height; 96 97 bitmap = malloc(sizeof(BitmapRec)); 98 if(bitmap == NULL) 99 return NULL; 100 101 bitmap->index = -1; 102 bitmap->width = 0; 103 bitmap->height = 0; 104 bitmap->stride = 0; 105 bitmap->raster = NULL; 106 bitmap->location = 0xDEADFACE; 107 108 i = code / FONT_SEGMENT_SIZE; 109 j = code % FONT_SEGMENT_SIZE; 110 111 if(strike->bitmaps[i] == NULL) { 112 strike->bitmaps[i] = calloc(FONT_SEGMENT_SIZE, sizeof(BitmapPtr)); 113 } 114 if(strike->bitmaps[i] == NULL) { 115 free(bitmap); 116 return NULL; 117 } 118 if(strike->bitmaps[i][j] != NULL) { 119 if(verbose_flag) 120 fprintf(stderr, "Duplicate bitmap %d.\n", code); 121 free(bitmap); 122 return strike->bitmaps[i][j]; 123 } 124 125 dx = 0; 126 dy = 0; 127 new_width = width; 128 new_height = height; 129 130 if(crop) { 131 int empty; 132 while(new_width > 0) { 133 empty = 1; 134 x = new_width - 1; 135 for(y = 0; y < new_height; y++) { 136 if(BITREF(raster, stride, x + dx, y + dy)) { 137 empty = 0; 138 break; 139 } 140 } 141 if(empty) 142 new_width--; 143 else 144 break; 145 } 146 while(new_height > 0) { 147 empty = 1; 148 y = new_height - 1; 149 for(x = 0; x < new_width; x++) { 150 if(BITREF(raster, stride, x + dx, y + dy)) { 151 empty = 0; 152 break; 153 } 154 } 155 if(empty) 156 new_height--; 157 else 158 break; 159 } 160 while(new_width > 0) { 161 empty = 1; 162 x = 0; 163 for(y = 0; y < new_height; y++) { 164 if(BITREF(raster, stride, x + dx, y + dy)) { 165 empty = 0; 166 break; 167 } 168 } 169 if(empty) { 170 dx++; 171 new_width--; 172 } else 173 break; 174 } 175 while(new_height > 0) { 176 empty = 1; 177 y = 0; 178 for(x = 0; x < new_width; x++) { 179 if(BITREF(raster, stride, x + dx, y + dy)) { 180 empty = 0; 181 break; 182 } 183 } 184 if(empty) { 185 dy++; 186 new_height--; 187 } else 188 break; 189 } 190 } 191 192 193 bitmap->advanceWidth = advanceWidth; 194 bitmap->horiBearingX = horiBearingX + dx; 195 bitmap->horiBearingY = horiBearingY - dy; 196 bitmap->width = new_width; 197 bitmap->height = new_height; 198 bitmap->stride = (new_width + 7) / 8; 199 200 bitmap->raster = malloc(bitmap->height * bitmap->stride); 201 if(bitmap->raster == NULL) { 202 free(bitmap); 203 return NULL; 204 } 205 memset(bitmap->raster, 0, bitmap->height * bitmap->stride); 206 for(y = 0; y < new_height; y++) { 207 for(x = 0; x < new_width; x++) { 208 if(BITREF(raster, stride, x + dx, y + dy)) 209 bitmap->raster[y * bitmap->stride + x / 8] |= 210 1 << (7 - (x % 8)); 211 } 212 } 213 strike->bitmaps[i][j] = bitmap; 214 strike->numSbits++; 215 216 return bitmap; 217} 218 219IndexSubTablePtr 220makeIndexSubTables(StrikePtr strike, CmapPtr cmap) 221{ 222 IndexSubTablePtr table, first, last; 223 BitmapPtr bitmap0, bitmap; 224 int index, n; 225 226 first = NULL; 227 last = NULL; 228 229 /* Assuming that we're writing bit-aligned data, small metrics 230 and short offsets, a constant metrics segment saves 5 bytes 231 per glyph in the EBDT table, and 2 bytes per glyph in the EBLC 232 table. On the other hand, the overhead for a supplementary 233 type 2 indexSubTable is 8 bytes for the indexSubTableArray 234 entry and 20 bytes for the subtable itself. It's worth 235 splitting at 5 glyphs. There's no analogue of a type 2 236 indexSubTable with byte-aligned data, so we don't bother 237 splitting when byte-aligning. */ 238 index = 0; 239 while(index < 0xFFFF) { 240 int constantMetrics = 1; 241 bitmap0 = strikeBitmapIndex(strike, cmap, index); 242 if(bitmap0 == NULL) { 243 index++; 244 continue; 245 } 246 n = 1; 247 while((bitmap = strikeBitmapIndex(strike, cmap, index + n)) != NULL) { 248 if(constantMetrics) { 249 if(!SAME_METRICS(bitmap0, bitmap)) { 250 if(bit_aligned_flag && n >= 4) 251 break; 252 else 253 constantMetrics = 0; 254 } 255 } else if(bit_aligned_flag) { 256 BitmapPtr b1 = strikeBitmapIndex(strike, cmap, index + n + 1); 257 BitmapPtr b2 = strikeBitmapIndex(strike, cmap, index + n + 2); 258 BitmapPtr b3 = strikeBitmapIndex(strike, cmap, index + n + 3); 259 BitmapPtr b4 = strikeBitmapIndex(strike, cmap, index + n + 4); 260 if(b1 && b2 && b3 && b4 && 261 SAME_METRICS(bitmap, b1) && 262 SAME_METRICS(bitmap, b2) && 263 SAME_METRICS(bitmap, b3) && 264 SAME_METRICS(bitmap, b4)) { 265 break; 266 } 267 } 268 n++; 269 } 270 if(n <= 1) 271 constantMetrics = 0; 272 273 table = malloc(sizeof(IndexSubTableRec)); 274 table->firstGlyphIndex = index; 275 table->lastGlyphIndex = index + n - 1; 276 table->constantMetrics = constantMetrics; 277 table->location = 0xDEADFACE; 278 table->lastLocation = 0xDEADFACE; 279 table->next = NULL; 280 281 if(first == NULL) { 282 first = table; 283 last = table; 284 } else { 285 last->next = table; 286 last = table; 287 } 288 index += n; 289 } 290 return first; 291} 292 293int 294fontIndex(FontPtr font, int code) 295{ 296 StrikePtr strike; 297 BitmapPtr bitmap; 298 299 if(code == 0) 300 return 0; 301 strike = font->strikes; 302 while(strike) { 303 bitmap = STRIKE_BITMAP(strike, code); 304 if(bitmap) 305 return bitmap->index; 306 strike = strike->next; 307 } 308 return -1; 309} 310 311CmapPtr 312makeCmap(FontPtr font) 313{ 314 CmapPtr cmap_head = NULL; 315 CmapPtr cmap_last = NULL; 316 CmapPtr cmap; 317 int code, i, index, maxindex = 0; 318 319 code = 0; 320 while(code < FONT_CODES) { 321 index = fontIndex(font, code); 322 if(index < 0) { 323 code++; 324 continue; 325 } 326 i = 1; 327 while(code + i < FONT_CODES && 328 fontIndex(font, code + i) == index + i) { 329 i++; 330 } 331 cmap = malloc(sizeof(CmapRec)); 332 if(cmap == NULL) 333 return NULL; 334 cmap->startCode = code; 335 cmap->endCode = code + i - 1; 336 cmap->index = index; 337 cmap->next = NULL; 338 cmap->maxindex = 0; 339 if(maxindex < index + i - 1) 340 maxindex = index + i - 1; 341 if(cmap_head == NULL) 342 cmap_head = cmap; 343 else 344 cmap_last->next = cmap; 345 cmap_last = cmap; 346 347 code += i; 348 } 349 cmap_head->maxindex = maxindex; 350 cmap_head->inverse = calloc(maxindex + 1, sizeof(int)); 351 cmap = cmap_head; 352 while(cmap) { 353 for(i = cmap->index; 354 i <= cmap->endCode - cmap->startCode + cmap->index; i++) { 355 cmap_head->inverse[i] = 356 i - cmap->index + cmap->startCode; 357 } 358 cmap = cmap->next; 359 } 360 361 return cmap_head; 362} 363 364int 365findIndex(CmapPtr cmap_head, int code) 366{ 367 CmapPtr cmap; 368 cmap = cmap_head; 369 while(cmap) { 370 if(cmap->endCode > code) 371 return -1; 372 if(cmap->startCode <= code) 373 return cmap->index + code - cmap->startCode; 374 cmap = cmap->next; 375 } 376 return -1; 377} 378 379int 380findCode(CmapPtr cmap_head, int index) 381{ 382 if(index < 0 || index > cmap_head->maxindex) 383 return -1; 384 return cmap_head->inverse[index]; 385 386} 387 388int 389maxIndex(CmapPtr cmap_head) 390{ 391 return cmap_head->maxindex; 392} 393 394BitmapPtr 395strikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index) 396{ 397 int code = findCode(cmap, index); 398 if(code < 0) 399 return NULL; 400 401 return STRIKE_BITMAP(strike, code); 402} 403 404void 405strikeMetrics(StrikePtr strike, 406 int *width_max_return, 407 int *x_min_return, int *y_min_return, 408 int *x_max_return, int *y_max_return) 409{ 410 BitmapPtr bitmap; 411 int i; 412 int width_max = 0; 413 int x_min = 10000; 414 int y_min = 10000; 415 int x_max = -10000; 416 int y_max = -10000; 417 418 for(i = 0; i < FONT_CODES; i++) { 419 bitmap = STRIKE_BITMAP(strike, i); 420 if(!bitmap) 421 continue; 422 if(bitmap->advanceWidth > width_max) 423 width_max = bitmap->advanceWidth; 424 if(bitmap->horiBearingX < x_min) 425 x_min = bitmap->horiBearingX; 426 if(bitmap->horiBearingY > y_max) 427 y_max = bitmap->horiBearingY; 428 if(bitmap->horiBearingX + bitmap->width > x_max) 429 x_max = bitmap->horiBearingX + bitmap->width; 430 if(bitmap->horiBearingY - bitmap->height < y_min) 431 y_min = bitmap->horiBearingY - bitmap->height; 432 } 433 434 if(width_max_return) *width_max_return = width_max; 435 if(x_min_return) *x_min_return = x_min; 436 if(y_min_return) *y_min_return = y_min; 437 if(x_max_return) *x_max_return = x_max; 438 if(y_max_return) *y_max_return = y_max; 439} 440 441int 442glyphMetrics(FontPtr font, int code, 443 int *width_return, 444 int *x_min_return, int *y_min_return, 445 int *x_max_return, int *y_max_return) 446{ 447 StrikePtr strike; 448 BitmapPtr bitmap; 449 450 strike = font->strikes; 451 while(strike) { 452 bitmap = STRIKE_BITMAP(strike, code); 453 if(bitmap) { 454 if(width_return) 455 *width_return = 456 (((float)bitmap->advanceWidth + 0.5) / strike->sizeX) * 457 TWO_SIXTEENTH; 458 if(x_min_return) 459 *x_min_return = 460 ((float)bitmap->horiBearingX / strike->sizeX) * 461 TWO_SIXTEENTH; 462 if(y_min_return) 463 *y_min_return = 464 (((float)bitmap->horiBearingY - bitmap->height) 465 / strike->sizeY) * TWO_SIXTEENTH; 466 /* For the following two, 0.9 instead of 0.5 might make 467 more sense. However, using different rounding rules 468 for x_max and awidth causes problems for detecting 469 charcell fonts. */ 470 if(x_max_return) 471 *x_max_return = 472 (((float)bitmap->horiBearingX + bitmap->width + 0.5) 473 / strike->sizeX) * TWO_SIXTEENTH; 474 if(y_max_return) 475 *y_max_return = 476 (((float)bitmap->horiBearingY + 0.5) / strike->sizeY) * 477 TWO_SIXTEENTH; 478 return 1; 479 } 480 strike = strike->next; 481 } 482 483 return -1; 484} 485 486void 487fontMetrics(FontPtr font, 488 int *max_awidth_return, 489 int *min_x_return, int *min_y_return, 490 int *max_x_return, int *max_y_return) 491{ 492 int i, rc; 493 int max_awidth = 0; 494 int min_x = 10000 * 65536, min_y = 10000 * 65536; 495 int max_x = -10000 * 65536, max_y = -10000 * 65536; 496 for(i = 0; i < FONT_CODES; i++) { 497 int awidth, x0, y0, x1, y1; 498 rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1); 499 if(rc < 0) 500 continue; 501 if(awidth > max_awidth) 502 max_awidth = awidth; 503 if(x0 < min_x) min_x = x0; 504 if(y0 < min_y) min_y = y0; 505 if(x1 > max_x) max_x = x1; 506 if(y1 > max_y) max_y = y1; 507 } 508 if(max_awidth_return) *max_awidth_return = max_awidth; 509 if(min_x_return) *min_x_return = min_x; 510 if(min_y_return) *min_y_return = min_y; 511 if(max_x_return) *max_x_return = max_x; 512 if(max_y_return) *max_y_return = max_y; 513} 514 515