struct.c revision 3ef3f551
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->pxMetrics.height = UNDEF;
46    font->pxMetrics.maxX = UNDEF;
47    font->pxMetrics.minX = UNDEF;
48    font->pxMetrics.maxY = UNDEF;
49    font->pxMetrics.minY = UNDEF;
50    font->pxMetrics.xHeight = UNDEF;
51    font->pxMetrics.capHeight = UNDEF;
52    font->pxMetrics.maxAwidth = UNDEF;
53    font->pxMetrics.awidth = UNDEF;
54    font->pxMetrics.ascent = UNDEF;
55    font->pxMetrics.descent = UNDEF;
56    font->pxMetrics.underlinePosition = UNDEF;
57    font->pxMetrics.underlineThickness = UNDEF;
58    font->metrics.height = UNDEF;
59    font->metrics.maxX = UNDEF;
60    font->metrics.minX = UNDEF;
61    font->metrics.maxY = UNDEF;
62    font->metrics.minY = UNDEF;
63    font->metrics.xHeight = UNDEF;
64    font->metrics.capHeight = UNDEF;
65    font->metrics.maxAwidth = UNDEF;
66    font->metrics.awidth = UNDEF;
67    font->metrics.ascent = UNDEF;
68    font->metrics.descent = UNDEF;
69    font->metrics.underlinePosition = UNDEF;
70    font->metrics.underlineThickness = UNDEF;
71    font->foundry = makeName("UNKN");
72    font->strikes = NULL;
73    return font;
74}
75
76StrikePtr
77makeStrike(FontPtr font, int sizeX, int sizeY)
78{
79    StrikePtr strike, last_strike;
80
81    strike = font->strikes;
82    last_strike = NULL;
83    while(strike) {
84        if(strike->sizeX == sizeX && strike->sizeY == sizeY)
85            return strike;
86        last_strike = strike;
87        strike = strike->next;
88    }
89
90    strike = malloc(sizeof(StrikeRec));
91    if(strike == NULL)
92        return NULL;
93    strike->sizeX = sizeX;
94    strike->sizeY = sizeY;
95    strike->bitmaps =
96        calloc(FONT_CODES / FONT_SEGMENT_SIZE, sizeof(BitmapPtr*));
97    if(strike->bitmaps == NULL) {
98        free(strike);
99        return NULL;
100    }
101    strike->numSbits = 0;
102    strike->next = NULL;
103    strike->bitmapSizeTableLocation = 0xDEADFACE;
104    strike->indexSubTables = NULL;
105    if(last_strike)
106        last_strike->next = strike;
107    else
108        font->strikes = strike;
109    return strike;
110}
111
112BitmapPtr
113makeBitmap(StrikePtr strike, int code,
114           int advanceWidth, int horiBearingX, int horiBearingY,
115           int width, int height, int stride, unsigned char *raster, int crop)
116{
117    BitmapPtr bitmap;
118    int i, j, x, y;
119    int dx, dy, new_width, new_height;
120
121    bitmap = malloc(sizeof(BitmapRec));
122    if(bitmap == NULL)
123        return NULL;
124
125    bitmap->index = -1;
126    bitmap->width = 0;
127    bitmap->height = 0;
128    bitmap->stride = 0;
129    bitmap->raster = NULL;
130    bitmap->location = 0xDEADFACE;
131
132    i = code / FONT_SEGMENT_SIZE;
133    j = code % FONT_SEGMENT_SIZE;
134
135    if(strike->bitmaps[i] == NULL) {
136        strike->bitmaps[i] = calloc(FONT_SEGMENT_SIZE, sizeof(BitmapPtr));
137    }
138    if(strike->bitmaps[i] == NULL) {
139        free(bitmap);
140        return NULL;
141    }
142    if(strike->bitmaps[i][j] != NULL) {
143        if(verbose_flag)
144            fprintf(stderr, "Duplicate bitmap %d.\n", code);
145        free(bitmap);
146        return strike->bitmaps[i][j];
147    }
148
149    dx = 0;
150    dy = 0;
151    new_width = width;
152    new_height = height;
153
154    if(crop) {
155        int empty;
156        while(new_width > 0) {
157            empty = 1;
158            x = new_width - 1;
159            for(y = 0; y < new_height; y++) {
160                if(BITREF(raster, stride, x + dx, y + dy)) {
161                    empty = 0;
162                    break;
163                }
164            }
165            if(empty)
166                new_width--;
167            else
168                break;
169        }
170        while(new_height > 0) {
171            empty = 1;
172            y = new_height - 1;
173            for(x = 0; x < new_width; x++) {
174                if(BITREF(raster, stride, x + dx, y + dy)) {
175                    empty = 0;
176                    break;
177                }
178            }
179            if(empty)
180                new_height--;
181            else
182                break;
183        }
184        while(new_width > 0) {
185            empty = 1;
186            x = 0;
187            for(y = 0; y < new_height; y++) {
188                if(BITREF(raster, stride, x + dx, y + dy)) {
189                    empty = 0;
190                    break;
191                }
192            }
193            if(empty) {
194                dx++;
195                new_width--;
196            } else
197                break;
198        }
199        while(new_height > 0) {
200            empty = 1;
201            y = 0;
202            for(x = 0; x < new_width; x++) {
203                if(BITREF(raster, stride, x + dx, y + dy)) {
204                    empty = 0;
205                    break;
206                }
207            }
208            if(empty) {
209                dy++;
210                new_height--;
211            } else
212                break;
213        }
214    }
215
216
217    bitmap->advanceWidth = advanceWidth;
218    bitmap->horiBearingX = horiBearingX + dx;
219    bitmap->horiBearingY = horiBearingY - dy;
220    bitmap->width = new_width;
221    bitmap->height = new_height;
222    bitmap->stride = (new_width + 7) / 8;
223
224    bitmap->raster = malloc(bitmap->height * bitmap->stride);
225    if(bitmap->raster == NULL) {
226        free(bitmap);
227        return NULL;
228    }
229    memset(bitmap->raster, 0, bitmap->height * bitmap->stride);
230    for(y = 0; y < new_height; y++) {
231        for(x = 0; x < new_width; x++) {
232            if(BITREF(raster, stride, x + dx, y + dy))
233                bitmap->raster[y * bitmap->stride + x / 8] |=
234                    1 << (7 - (x % 8));
235        }
236    }
237    strike->bitmaps[i][j] = bitmap;
238    strike->numSbits++;
239
240    return bitmap;
241}
242
243IndexSubTablePtr
244makeIndexSubTables(StrikePtr strike, CmapPtr cmap)
245{
246    IndexSubTablePtr table, first, last;
247    BitmapPtr bitmap0, bitmap;
248    int index, n;
249
250    first = NULL;
251    last = NULL;
252
253    /* Assuming that we're writing bit-aligned data, small metrics
254       and short offsets, a constant metrics segment saves 5 bytes
255       per glyph in the EBDT table, and 2 bytes per glyph in the EBLC
256       table.  On the other hand, the overhead for a supplementary
257       type 2 indexSubTable is 8 bytes for the indexSubTableArray
258       entry and 20 bytes for the subtable itself.  It's worth
259       splitting at 5 glyphs.  There's no analogue of a type 2
260       indexSubTable with byte-aligned data, so we don't bother
261       splitting when byte-aligning. */
262    index = 0;
263    while(index < 0xFFFF) {
264        int constantMetrics = 1;
265        bitmap0 = strikeBitmapIndex(strike, cmap, index);
266        if(bitmap0 == NULL) {
267            index++;
268            continue;
269        }
270        n = 1;
271        while((bitmap = strikeBitmapIndex(strike, cmap, index + n)) != NULL) {
272            if(constantMetrics) {
273                if(!SAME_METRICS(bitmap0, bitmap)) {
274                    if(bit_aligned_flag && n >= 4)
275                        break;
276                    else
277                        constantMetrics = 0;
278                }
279            } else if(bit_aligned_flag) {
280                BitmapPtr b1 = strikeBitmapIndex(strike, cmap, index + n + 1);
281                BitmapPtr b2 = strikeBitmapIndex(strike, cmap, index + n + 2);
282                BitmapPtr b3 = strikeBitmapIndex(strike, cmap, index + n + 3);
283                BitmapPtr b4 = strikeBitmapIndex(strike, cmap, index + n + 4);
284                if(b1 && b2 && b3 && b4 &&
285                   SAME_METRICS(bitmap, b1) &&
286                   SAME_METRICS(bitmap, b2) &&
287                   SAME_METRICS(bitmap, b3) &&
288                   SAME_METRICS(bitmap, b4)) {
289                    break;
290                }
291            }
292            n++;
293        }
294        if(n <= 1)
295            constantMetrics = 0;
296
297        table = malloc(sizeof(IndexSubTableRec));
298        table->firstGlyphIndex = index;
299        table->lastGlyphIndex = index + n - 1;
300        table->constantMetrics = constantMetrics;
301        table->location = 0xDEADFACE;
302        table->lastLocation = 0xDEADFACE;
303        table->next = NULL;
304
305        if(first == NULL) {
306            first = table;
307            last = table;
308        } else {
309            last->next = table;
310            last = table;
311        }
312        index += n;
313    }
314    return first;
315}
316
317int
318fontIndex(FontPtr font, int code)
319{
320    StrikePtr strike;
321    BitmapPtr bitmap;
322
323    if(code == 0)
324        return 0;
325    strike = font->strikes;
326    while(strike) {
327        bitmap = STRIKE_BITMAP(strike, code);
328        if(bitmap)
329            return bitmap->index;
330        strike = strike->next;
331    }
332    return -1;
333}
334
335CmapPtr
336makeCmap(FontPtr font)
337{
338    CmapPtr cmap_head = NULL;
339    CmapPtr cmap_last = NULL;
340    CmapPtr cmap;
341    int code, i, index, maxindex = 0;
342
343    code = 0;
344    while(code < FONT_CODES) {
345        index = fontIndex(font, code);
346        if(index < 0) {
347            code++;
348            continue;
349        }
350        i = 1;
351        while(code + i < FONT_CODES &&
352              fontIndex(font, code + i) == index + i) {
353            i++;
354        }
355        cmap = malloc(sizeof(CmapRec));
356        if(cmap == NULL)
357            return NULL;
358        cmap->startCode = code;
359        cmap->endCode = code + i - 1;
360        cmap->index = index;
361        cmap->next = NULL;
362        cmap->maxindex = 0;
363        if(maxindex < index + i - 1)
364            maxindex = index + i - 1;
365        if(cmap_head == NULL)
366            cmap_head = cmap;
367        else
368            cmap_last->next = cmap;
369        cmap_last = cmap;
370
371        code += i;
372    }
373    cmap_head->maxindex = maxindex;
374    cmap_head->inverse = calloc(maxindex + 1, sizeof(int));
375    cmap = cmap_head;
376    while(cmap) {
377        for(i = cmap->index;
378            i <= cmap->endCode - cmap->startCode + cmap->index; i++) {
379            cmap_head->inverse[i] =
380                i - cmap->index + cmap->startCode;
381        }
382        cmap = cmap->next;
383    }
384
385    return cmap_head;
386}
387
388int
389findIndex(CmapPtr cmap_head, int code)
390{
391    CmapPtr cmap;
392    cmap = cmap_head;
393    while(cmap) {
394        if(cmap->endCode > code)
395            return -1;
396        if(cmap->startCode <= code)
397            return cmap->index + code - cmap->startCode;
398        cmap = cmap->next;
399    }
400    return -1;
401}
402
403int
404findCode(CmapPtr cmap_head, int index)
405{
406    if(index < 0 || index > cmap_head->maxindex)
407        return -1;
408    return cmap_head->inverse[index];
409
410}
411
412int
413maxIndex(CmapPtr cmap_head)
414{
415    return cmap_head->maxindex;
416}
417
418BitmapPtr
419strikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index)
420{
421    int code = findCode(cmap, index);
422    if(code < 0)
423        return NULL;
424
425    return STRIKE_BITMAP(strike, code);
426}
427
428int
429strikeMaxWidth(StrikePtr strike)
430{
431    BitmapPtr bitmap;
432    int i;
433    int width_max = 0;
434
435    for(i = 0; i < FONT_CODES; i++) {
436        bitmap = STRIKE_BITMAP(strike, i);
437        if(!bitmap)
438            continue;
439        if(bitmap->advanceWidth > width_max)
440            width_max = bitmap->advanceWidth;
441    }
442
443    return width_max;
444}
445
446int
447glyphMetrics(FontPtr font, int code,
448             int *width_return,
449             int *x_min_return, int *y_min_return,
450             int *x_max_return, int *y_max_return)
451{
452    StrikePtr strike;
453    BitmapPtr bitmap;
454
455    strike = font->strikes;
456    while(strike) {
457        bitmap = STRIKE_BITMAP(strike, code);
458        if(bitmap) {
459            if(width_return)
460                *width_return =
461                    (((float)bitmap->advanceWidth) / strike->sizeX) *
462                    TWO_SIXTEENTH;
463            if(x_min_return)
464                *x_min_return =
465                    ((float)bitmap->horiBearingX / strike->sizeX) *
466                    TWO_SIXTEENTH;
467            if(y_min_return)
468                *y_min_return =
469                    (((float)bitmap->horiBearingY - bitmap->height)
470                     / strike->sizeY) * TWO_SIXTEENTH;
471            if(x_max_return)
472                *x_max_return =
473                    (((float)bitmap->horiBearingX + bitmap->width)
474                     / strike->sizeX) * TWO_SIXTEENTH;
475            if(y_max_return)
476                *y_max_return =
477                    (((float)bitmap->horiBearingY) / strike->sizeY) *
478                    TWO_SIXTEENTH;
479            return 1;
480        }
481        strike = strike->next;
482    }
483
484    return -1;
485}
486