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