struct.c revision 51b1aeb1
143f32c10Smrg/*
243f32c10SmrgCopyright (c) 2002-2003 by Juliusz Chroboczek
343f32c10Smrg
443f32c10SmrgPermission is hereby granted, free of charge, to any person obtaining a copy
543f32c10Smrgof this software and associated documentation files (the "Software"), to deal
643f32c10Smrgin the Software without restriction, including without limitation the rights
743f32c10Smrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
843f32c10Smrgcopies of the Software, and to permit persons to whom the Software is
943f32c10Smrgfurnished to do so, subject to the following conditions:
1043f32c10Smrg
1143f32c10SmrgThe above copyright notice and this permission notice shall be included in
1243f32c10Smrgall copies or substantial portions of the Software.
1343f32c10Smrg
1443f32c10SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1543f32c10SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1643f32c10SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1743f32c10SmrgAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1843f32c10SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1943f32c10SmrgOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2043f32c10SmrgTHE SOFTWARE.
2143f32c10Smrg*/
2243f32c10Smrg/* $XFree86: xc/programs/fonttosfnt/struct.c,v 1.3 2003/10/24 20:38:11 tsi Exp $ */
2343f32c10Smrg
2443f32c10Smrg#include <stdlib.h>
2543f32c10Smrg#include <stdio.h>
2643f32c10Smrg#include <ft2build.h>
2743f32c10Smrg#include FT_FREETYPE_H
2843f32c10Smrg#include "fonttosfnt.h"
2943f32c10Smrg
3043f32c10SmrgFontPtr
3151b1aeb1SmrgmakeFont(void)
3243f32c10Smrg{
3343f32c10Smrg    FontPtr font;
3443f32c10Smrg
3543f32c10Smrg    font = malloc(sizeof(FontRec));
3643f32c10Smrg    if(font == NULL)
3743f32c10Smrg        return NULL;
3843f32c10Smrg
3943f32c10Smrg    font->numNames = 0;
4043f32c10Smrg    font->names = NULL;
4143f32c10Smrg    font->flags = 0;
4243f32c10Smrg    font->weight = 500;
4343f32c10Smrg    font->width = 5;
4443f32c10Smrg    font->italicAngle = 0;
4543f32c10Smrg    font->underlinePosition = - TWO_SIXTEENTH;
4643f32c10Smrg    font->underlineThickness = TWO_SIXTEENTH;
4743f32c10Smrg    font->foundry = makeName("UNKN");
4843f32c10Smrg    font->strikes = NULL;
4943f32c10Smrg    return font;
5043f32c10Smrg}
5143f32c10Smrg
5243f32c10SmrgStrikePtr
5343f32c10SmrgmakeStrike(FontPtr font, int sizeX, int sizeY)
5443f32c10Smrg{
5543f32c10Smrg    StrikePtr strike, last_strike;
5643f32c10Smrg
5743f32c10Smrg    strike = font->strikes;
5843f32c10Smrg    last_strike = NULL;
5943f32c10Smrg    while(strike) {
6043f32c10Smrg        if(strike->sizeX == sizeX && strike->sizeY == sizeY)
6143f32c10Smrg            return strike;
6243f32c10Smrg        last_strike = strike;
6343f32c10Smrg        strike = strike->next;
6443f32c10Smrg    }
6543f32c10Smrg
6643f32c10Smrg    strike = malloc(sizeof(StrikeRec));
6743f32c10Smrg    if(strike == NULL)
6843f32c10Smrg        return NULL;
6943f32c10Smrg    strike->sizeX = sizeX;
7043f32c10Smrg    strike->sizeY = sizeY;
7143f32c10Smrg    strike->bitmaps =
7243f32c10Smrg        calloc(FONT_CODES / FONT_SEGMENT_SIZE, sizeof(BitmapPtr*));
7343f32c10Smrg    if(strike->bitmaps == NULL) {
7443f32c10Smrg        free(strike);
7543f32c10Smrg        return NULL;
7643f32c10Smrg    }
7743f32c10Smrg    strike->numSbits = 0;
7843f32c10Smrg    strike->next = NULL;
7943f32c10Smrg    strike->bitmapSizeTableLocation = 0xDEADFACE;
8043f32c10Smrg    strike->indexSubTables = NULL;
8143f32c10Smrg    if(last_strike)
8243f32c10Smrg        last_strike->next = strike;
8343f32c10Smrg    else
8443f32c10Smrg        font->strikes = strike;
8543f32c10Smrg    return strike;
8643f32c10Smrg}
8743f32c10Smrg
8843f32c10SmrgBitmapPtr
8943f32c10SmrgmakeBitmap(StrikePtr strike, int code,
9043f32c10Smrg           int advanceWidth, int horiBearingX, int horiBearingY,
9143f32c10Smrg           int width, int height, int stride, unsigned char *raster, int crop)
9243f32c10Smrg{
9343f32c10Smrg    BitmapPtr bitmap;
9443f32c10Smrg    int i, j, x, y;
9543f32c10Smrg    int dx, dy, new_width, new_height;
9643f32c10Smrg
9743f32c10Smrg    bitmap = malloc(sizeof(BitmapRec));
9843f32c10Smrg    if(bitmap == NULL)
9943f32c10Smrg        return NULL;
10043f32c10Smrg
10143f32c10Smrg    bitmap->index = -1;
10243f32c10Smrg    bitmap->width = 0;
10343f32c10Smrg    bitmap->height = 0;
10443f32c10Smrg    bitmap->stride = 0;
10543f32c10Smrg    bitmap->raster = NULL;
10643f32c10Smrg    bitmap->location = 0xDEADFACE;
10743f32c10Smrg
10843f32c10Smrg    i = code / FONT_SEGMENT_SIZE;
10943f32c10Smrg    j = code % FONT_SEGMENT_SIZE;
11043f32c10Smrg
11143f32c10Smrg    if(strike->bitmaps[i] == NULL) {
11243f32c10Smrg        strike->bitmaps[i] = calloc(FONT_SEGMENT_SIZE, sizeof(BitmapPtr));
11343f32c10Smrg    }
11443f32c10Smrg    if(strike->bitmaps[i] == NULL) {
11543f32c10Smrg        free(bitmap);
11643f32c10Smrg        return NULL;
11743f32c10Smrg    }
11843f32c10Smrg    if(strike->bitmaps[i][j] != NULL) {
11943f32c10Smrg        if(verbose_flag)
12043f32c10Smrg            fprintf(stderr, "Duplicate bitmap %d.\n", code);
12143f32c10Smrg        free(bitmap);
12243f32c10Smrg        return strike->bitmaps[i][j];
12343f32c10Smrg    }
12443f32c10Smrg
12543f32c10Smrg    dx = 0;
12643f32c10Smrg    dy = 0;
12743f32c10Smrg    new_width = width;
12843f32c10Smrg    new_height = height;
12943f32c10Smrg
13043f32c10Smrg    if(crop) {
13143f32c10Smrg        int empty;
13243f32c10Smrg        while(new_width > 0) {
13343f32c10Smrg            empty = 1;
13443f32c10Smrg            x = new_width - 1;
13543f32c10Smrg            for(y = 0; y < new_height; y++) {
13643f32c10Smrg                if(BITREF(raster, stride, x + dx, y + dy)) {
13743f32c10Smrg                    empty = 0;
13843f32c10Smrg                    break;
13943f32c10Smrg                }
14043f32c10Smrg            }
14143f32c10Smrg            if(empty)
14243f32c10Smrg                new_width--;
14343f32c10Smrg            else
14443f32c10Smrg                break;
14543f32c10Smrg        }
14643f32c10Smrg        while(new_height > 0) {
14743f32c10Smrg            empty = 1;
14843f32c10Smrg            y = new_height - 1;
14943f32c10Smrg            for(x = 0; x < new_width; x++) {
15043f32c10Smrg                if(BITREF(raster, stride, x + dx, y + dy)) {
15143f32c10Smrg                    empty = 0;
15243f32c10Smrg                    break;
15343f32c10Smrg                }
15443f32c10Smrg            }
15543f32c10Smrg            if(empty)
15643f32c10Smrg                new_height--;
15743f32c10Smrg            else
15843f32c10Smrg                break;
15943f32c10Smrg        }
16043f32c10Smrg        while(new_width > 0) {
16143f32c10Smrg            empty = 1;
16243f32c10Smrg            x = 0;
16343f32c10Smrg            for(y = 0; y < new_height; y++) {
16443f32c10Smrg                if(BITREF(raster, stride, x + dx, y + dy)) {
16543f32c10Smrg                    empty = 0;
16643f32c10Smrg                    break;
16743f32c10Smrg                }
16843f32c10Smrg            }
16943f32c10Smrg            if(empty) {
17043f32c10Smrg                dx++;
17143f32c10Smrg                new_width--;
17243f32c10Smrg            } else
17343f32c10Smrg                break;
17443f32c10Smrg        }
17543f32c10Smrg        while(new_height > 0) {
17643f32c10Smrg            empty = 1;
17743f32c10Smrg            y = 0;
17843f32c10Smrg            for(x = 0; x < new_width; x++) {
17943f32c10Smrg                if(BITREF(raster, stride, x + dx, y + dy)) {
18043f32c10Smrg                    empty = 0;
18143f32c10Smrg                    break;
18243f32c10Smrg                }
18343f32c10Smrg            }
18443f32c10Smrg            if(empty) {
18543f32c10Smrg                dy++;
18643f32c10Smrg                new_height--;
18743f32c10Smrg            } else
18843f32c10Smrg                break;
18943f32c10Smrg        }
19043f32c10Smrg    }
19143f32c10Smrg
19243f32c10Smrg
19343f32c10Smrg    bitmap->advanceWidth = advanceWidth;
19443f32c10Smrg    bitmap->horiBearingX = horiBearingX + dx;
19543f32c10Smrg    bitmap->horiBearingY = horiBearingY - dy;
19643f32c10Smrg    bitmap->width = new_width;
19743f32c10Smrg    bitmap->height = new_height;
19843f32c10Smrg    bitmap->stride = (new_width + 7) / 8;
19943f32c10Smrg
20043f32c10Smrg    bitmap->raster = malloc(bitmap->height * bitmap->stride);
20143f32c10Smrg    if(bitmap->raster == NULL) {
20243f32c10Smrg        free(bitmap);
20343f32c10Smrg        return NULL;
20443f32c10Smrg    }
20543f32c10Smrg    memset(bitmap->raster, 0, bitmap->height * bitmap->stride);
20643f32c10Smrg    for(y = 0; y < new_height; y++) {
20743f32c10Smrg        for(x = 0; x < new_width; x++) {
20843f32c10Smrg            if(BITREF(raster, stride, x + dx, y + dy))
20943f32c10Smrg                bitmap->raster[y * bitmap->stride + x / 8] |=
21043f32c10Smrg                    1 << (7 - (x % 8));
21143f32c10Smrg        }
21243f32c10Smrg    }
21343f32c10Smrg    strike->bitmaps[i][j] = bitmap;
21443f32c10Smrg    strike->numSbits++;
21543f32c10Smrg
21643f32c10Smrg    return bitmap;
21743f32c10Smrg}
21843f32c10Smrg
21943f32c10SmrgIndexSubTablePtr
22043f32c10SmrgmakeIndexSubTables(StrikePtr strike, CmapPtr cmap)
22143f32c10Smrg{
22243f32c10Smrg    IndexSubTablePtr table, first, last;
22343f32c10Smrg    BitmapPtr bitmap0, bitmap;
22443f32c10Smrg    int index, n;
22543f32c10Smrg
22643f32c10Smrg    first = NULL;
22743f32c10Smrg    last = NULL;
22843f32c10Smrg
22943f32c10Smrg    /* Assuming that we're writing bit-aligned data, small metrics
23043f32c10Smrg       and short offsets, a constant metrics segment saves 5 bytes
23143f32c10Smrg       per glyph in the EBDT table, and 2 bytes per glyph in the EBLC
23243f32c10Smrg       table.  On the other hand, the overhead for a supplementary
23343f32c10Smrg       type 2 indexSubTable is 8 bytes for the indexSubTableArray
23443f32c10Smrg       entry and 20 bytes for the subtable itself.  It's worth
23543f32c10Smrg       splitting at 5 glyphs.  There's no analogue of a type 2
23643f32c10Smrg       indexSubTable with byte-aligned data, so we don't bother
23743f32c10Smrg       splitting when byte-aligning. */
23843f32c10Smrg    index = 0;
23943f32c10Smrg    while(index < 0xFFFF) {
24043f32c10Smrg        int constantMetrics = 1;
24143f32c10Smrg        bitmap0 = strikeBitmapIndex(strike, cmap, index);
24243f32c10Smrg        if(bitmap0 == NULL) {
24343f32c10Smrg            index++;
24443f32c10Smrg            continue;
24543f32c10Smrg        }
24643f32c10Smrg        n = 1;
24743f32c10Smrg        while((bitmap = strikeBitmapIndex(strike, cmap, index + n)) != NULL) {
24843f32c10Smrg            if(constantMetrics) {
24943f32c10Smrg                if(!SAME_METRICS(bitmap0, bitmap)) {
25043f32c10Smrg                    if(bit_aligned_flag && n >= 4)
25143f32c10Smrg                        break;
25243f32c10Smrg                    else
25343f32c10Smrg                        constantMetrics = 0;
25443f32c10Smrg                }
25543f32c10Smrg            } else if(bit_aligned_flag) {
25643f32c10Smrg                BitmapPtr b1 = strikeBitmapIndex(strike, cmap, index + n + 1);
25743f32c10Smrg                BitmapPtr b2 = strikeBitmapIndex(strike, cmap, index + n + 2);
25843f32c10Smrg                BitmapPtr b3 = strikeBitmapIndex(strike, cmap, index + n + 3);
25943f32c10Smrg                BitmapPtr b4 = strikeBitmapIndex(strike, cmap, index + n + 4);
26043f32c10Smrg                if(b1 && b2 && b3 && b4 &&
26143f32c10Smrg                   SAME_METRICS(bitmap, b1) &&
26243f32c10Smrg                   SAME_METRICS(bitmap, b2) &&
26343f32c10Smrg                   SAME_METRICS(bitmap, b3) &&
26443f32c10Smrg                   SAME_METRICS(bitmap, b4)) {
26543f32c10Smrg                    break;
26643f32c10Smrg                }
26743f32c10Smrg            }
26843f32c10Smrg            n++;
26943f32c10Smrg        }
27043f32c10Smrg        if(n <= 1)
27143f32c10Smrg            constantMetrics = 0;
27243f32c10Smrg
27343f32c10Smrg        table = malloc(sizeof(IndexSubTableRec));
27443f32c10Smrg        table->firstGlyphIndex = index;
27543f32c10Smrg        table->lastGlyphIndex = index + n - 1;
27643f32c10Smrg        table->constantMetrics = constantMetrics;
27743f32c10Smrg        table->location = 0xDEADFACE;
27843f32c10Smrg        table->lastLocation = 0xDEADFACE;
27943f32c10Smrg        table->next = NULL;
28043f32c10Smrg
28143f32c10Smrg        if(first == NULL) {
28243f32c10Smrg            first = table;
28343f32c10Smrg            last = table;
28443f32c10Smrg        } else {
28543f32c10Smrg            last->next = table;
28643f32c10Smrg            last = table;
28743f32c10Smrg        }
28843f32c10Smrg        index += n;
28943f32c10Smrg    }
29043f32c10Smrg    return first;
29143f32c10Smrg}
29243f32c10Smrg
29343f32c10Smrgint
29443f32c10SmrgfontIndex(FontPtr font, int code)
29543f32c10Smrg{
29643f32c10Smrg    StrikePtr strike;
29743f32c10Smrg    BitmapPtr bitmap;
29843f32c10Smrg
29943f32c10Smrg    if(code == 0)
30043f32c10Smrg        return 0;
30143f32c10Smrg    strike = font->strikes;
30243f32c10Smrg    while(strike) {
30343f32c10Smrg        bitmap = STRIKE_BITMAP(strike, code);
30443f32c10Smrg        if(bitmap)
30543f32c10Smrg            return bitmap->index;
30643f32c10Smrg        strike = strike->next;
30743f32c10Smrg    }
30843f32c10Smrg    return -1;
30943f32c10Smrg}
31043f32c10Smrg
31143f32c10SmrgCmapPtr
31243f32c10SmrgmakeCmap(FontPtr font)
31343f32c10Smrg{
31443f32c10Smrg    CmapPtr cmap_head = NULL;
31543f32c10Smrg    CmapPtr cmap_last = NULL;
31643f32c10Smrg    CmapPtr cmap;
31743f32c10Smrg    int code, i, index, maxindex = 0;
31843f32c10Smrg
31943f32c10Smrg    code = 0;
32043f32c10Smrg    while(code < FONT_CODES) {
32143f32c10Smrg        index = fontIndex(font, code);
32243f32c10Smrg        if(index < 0) {
32343f32c10Smrg            code++;
32443f32c10Smrg            continue;
32543f32c10Smrg        }
32643f32c10Smrg        i = 1;
32743f32c10Smrg        while(code + i < FONT_CODES &&
32843f32c10Smrg              fontIndex(font, code + i) == index + i) {
32943f32c10Smrg            i++;
33043f32c10Smrg        }
33143f32c10Smrg        cmap = malloc(sizeof(CmapRec));
33243f32c10Smrg        if(cmap == NULL)
33343f32c10Smrg            return NULL;
33443f32c10Smrg        cmap->startCode = code;
33543f32c10Smrg        cmap->endCode = code + i - 1;
33643f32c10Smrg        cmap->index = index;
33743f32c10Smrg        cmap->next = NULL;
33843f32c10Smrg        cmap->maxindex = 0;
33943f32c10Smrg        if(maxindex < index + i - 1)
34043f32c10Smrg            maxindex = index + i - 1;
34143f32c10Smrg        if(cmap_head == NULL)
34243f32c10Smrg            cmap_head = cmap;
34343f32c10Smrg        else
34443f32c10Smrg            cmap_last->next = cmap;
34543f32c10Smrg        cmap_last = cmap;
34643f32c10Smrg
34743f32c10Smrg        code += i;
34843f32c10Smrg    }
34943f32c10Smrg    cmap_head->maxindex = maxindex;
35043f32c10Smrg    cmap_head->inverse = calloc(maxindex + 1, sizeof(int));
35143f32c10Smrg    cmap = cmap_head;
35243f32c10Smrg    while(cmap) {
35343f32c10Smrg        for(i = cmap->index;
35443f32c10Smrg            i <= cmap->endCode - cmap->startCode + cmap->index; i++) {
35543f32c10Smrg            cmap_head->inverse[i] =
35643f32c10Smrg                i - cmap->index + cmap->startCode;
35743f32c10Smrg        }
35843f32c10Smrg        cmap = cmap->next;
35943f32c10Smrg    }
36043f32c10Smrg
36143f32c10Smrg    return cmap_head;
36243f32c10Smrg}
36343f32c10Smrg
36443f32c10Smrgint
36543f32c10SmrgfindIndex(CmapPtr cmap_head, int code)
36643f32c10Smrg{
36743f32c10Smrg    CmapPtr cmap;
36843f32c10Smrg    cmap = cmap_head;
36943f32c10Smrg    while(cmap) {
37043f32c10Smrg        if(cmap->endCode > code)
37143f32c10Smrg            return -1;
37243f32c10Smrg        if(cmap->startCode <= code)
37343f32c10Smrg            return cmap->index + code - cmap->startCode;
37443f32c10Smrg        cmap = cmap->next;
37543f32c10Smrg    }
37643f32c10Smrg    return -1;
37743f32c10Smrg}
37843f32c10Smrg
37943f32c10Smrgint
38043f32c10SmrgfindCode(CmapPtr cmap_head, int index)
38143f32c10Smrg{
38243f32c10Smrg    if(index < 0 || index > cmap_head->maxindex)
38343f32c10Smrg        return -1;
38443f32c10Smrg    return cmap_head->inverse[index];
38543f32c10Smrg
38643f32c10Smrg}
38743f32c10Smrg
38843f32c10Smrgint
38943f32c10SmrgmaxIndex(CmapPtr cmap_head)
39043f32c10Smrg{
39143f32c10Smrg    return cmap_head->maxindex;
39243f32c10Smrg}
39343f32c10Smrg
39443f32c10SmrgBitmapPtr
39543f32c10SmrgstrikeBitmapIndex(StrikePtr strike, CmapPtr cmap, int index)
39643f32c10Smrg{
39743f32c10Smrg    int code = findCode(cmap, index);
39843f32c10Smrg    if(code < 0)
39943f32c10Smrg        return NULL;
40043f32c10Smrg
40143f32c10Smrg    return STRIKE_BITMAP(strike, code);
40243f32c10Smrg}
40343f32c10Smrg
40443f32c10Smrgvoid
40543f32c10SmrgstrikeMetrics(StrikePtr strike,
40643f32c10Smrg              int *width_max_return,
40743f32c10Smrg              int *x_min_return, int *y_min_return,
40843f32c10Smrg              int *x_max_return, int *y_max_return)
40943f32c10Smrg{
41043f32c10Smrg    BitmapPtr bitmap;
41143f32c10Smrg    int i;
41243f32c10Smrg    int width_max = 0;
41343f32c10Smrg    int x_min = 10000;
41443f32c10Smrg    int y_min = 10000;
41543f32c10Smrg    int x_max = -10000;
41643f32c10Smrg    int y_max = -10000;
41743f32c10Smrg
41843f32c10Smrg    for(i = 0; i < FONT_CODES; i++) {
41943f32c10Smrg        bitmap = STRIKE_BITMAP(strike, i);
42043f32c10Smrg        if(!bitmap)
42143f32c10Smrg            continue;
42243f32c10Smrg        if(bitmap->advanceWidth > width_max)
42343f32c10Smrg            width_max = bitmap->advanceWidth;
42443f32c10Smrg        if(bitmap->horiBearingX < x_min)
42543f32c10Smrg            x_min = bitmap->horiBearingX;
42643f32c10Smrg        if(bitmap->horiBearingY > y_max)
42743f32c10Smrg            y_max = bitmap->horiBearingY;
42843f32c10Smrg        if(bitmap->horiBearingX + bitmap->width > x_max)
42943f32c10Smrg            x_max = bitmap->horiBearingX + bitmap->width;
43043f32c10Smrg        if(bitmap->horiBearingY - bitmap->height < y_min)
43143f32c10Smrg            y_min = bitmap->horiBearingY - bitmap->height;
43243f32c10Smrg    }
43343f32c10Smrg
43443f32c10Smrg    if(width_max_return) *width_max_return = width_max;
43543f32c10Smrg    if(x_min_return) *x_min_return = x_min;
43643f32c10Smrg    if(y_min_return) *y_min_return = y_min;
43743f32c10Smrg    if(x_max_return) *x_max_return = x_max;
43843f32c10Smrg    if(y_max_return) *y_max_return = y_max;
43943f32c10Smrg}
44043f32c10Smrg
44143f32c10Smrgint
44243f32c10SmrgglyphMetrics(FontPtr font, int code,
44343f32c10Smrg             int *width_return,
44443f32c10Smrg             int *x_min_return, int *y_min_return,
44543f32c10Smrg             int *x_max_return, int *y_max_return)
44643f32c10Smrg{
44743f32c10Smrg    StrikePtr strike;
44843f32c10Smrg    BitmapPtr bitmap;
44943f32c10Smrg
45043f32c10Smrg    strike = font->strikes;
45143f32c10Smrg    while(strike) {
45243f32c10Smrg        bitmap = STRIKE_BITMAP(strike, code);
45343f32c10Smrg        if(bitmap) {
45443f32c10Smrg            if(width_return)
45543f32c10Smrg                *width_return =
45643f32c10Smrg                    (((float)bitmap->advanceWidth + 0.5) / strike->sizeX) *
45743f32c10Smrg                    TWO_SIXTEENTH;
45843f32c10Smrg            if(x_min_return)
45943f32c10Smrg                *x_min_return =
46043f32c10Smrg                    ((float)bitmap->horiBearingX / strike->sizeX) *
46143f32c10Smrg                    TWO_SIXTEENTH;
46243f32c10Smrg            if(y_min_return)
46343f32c10Smrg                *y_min_return =
46443f32c10Smrg                    (((float)bitmap->horiBearingY - bitmap->height)
46543f32c10Smrg                     / strike->sizeY) * TWO_SIXTEENTH;
46643f32c10Smrg            /* For the following two, 0.9 instead of 0.5 might make
46743f32c10Smrg               more sense.  However, using different rounding rules
46843f32c10Smrg               for x_max and awidth causes problems for detecting
46943f32c10Smrg               charcell fonts. */
47043f32c10Smrg            if(x_max_return)
47143f32c10Smrg                *x_max_return =
47243f32c10Smrg                    (((float)bitmap->horiBearingX + bitmap->width + 0.5)
47343f32c10Smrg                     / strike->sizeX) * TWO_SIXTEENTH;
47443f32c10Smrg            if(y_max_return)
47543f32c10Smrg                *y_max_return =
47643f32c10Smrg                    (((float)bitmap->horiBearingY + 0.5) / strike->sizeY) *
47743f32c10Smrg                    TWO_SIXTEENTH;
47843f32c10Smrg            return 1;
47943f32c10Smrg        }
48043f32c10Smrg        strike = strike->next;
48143f32c10Smrg    }
48243f32c10Smrg
48343f32c10Smrg    return -1;
48443f32c10Smrg}
48543f32c10Smrg
48643f32c10Smrgvoid
48743f32c10SmrgfontMetrics(FontPtr font,
48843f32c10Smrg            int *max_awidth_return,
48943f32c10Smrg            int *min_x_return, int *min_y_return,
49043f32c10Smrg            int *max_x_return, int *max_y_return)
49143f32c10Smrg{
49243f32c10Smrg    int i, rc;
49343f32c10Smrg    int max_awidth = 0;
494cec190c7Sjoerg    int min_x = 10000 * 65536, min_y = 10000 * 65536;
495cec190c7Sjoerg    int max_x = -10000 * 65536, max_y = -10000 * 65536;
49643f32c10Smrg    for(i = 0; i < FONT_CODES; i++) {
49743f32c10Smrg        int awidth, x0, y0, x1, y1;
49843f32c10Smrg        rc = glyphMetrics(font, i, &awidth, &x0, &y0, &x1, &y1);
49943f32c10Smrg        if(rc < 0)
50043f32c10Smrg            continue;
50143f32c10Smrg        if(awidth > max_awidth)
50243f32c10Smrg            max_awidth = awidth;
50343f32c10Smrg        if(x0 < min_x) min_x = x0;
50443f32c10Smrg        if(y0 < min_y) min_y = y0;
50543f32c10Smrg        if(x1 > max_x) max_x = x1;
50643f32c10Smrg        if(y1 > max_y) max_y = y1;
50743f32c10Smrg    }
50843f32c10Smrg    if(max_awidth_return) *max_awidth_return = max_awidth;
50943f32c10Smrg    if(min_x_return) *min_x_return = min_x;
51043f32c10Smrg    if(min_y_return) *min_y_return = min_y;
51143f32c10Smrg    if(max_x_return) *max_x_return = max_x;
51243f32c10Smrg    if(max_y_return) *max_y_return = max_y;
51343f32c10Smrg}
51443f32c10Smrg
515