source: trunk/poppler/fc-emulate-os2/fontconfig/fontconfig.cpp @ 71

Last change on this file since 71 was 71, checked in by Eugene Romanenko, 15 years ago

fontconfig replacement fixes, removed wrong text in file headers

File size: 12.7 KB
Line 
1/*
2 * Copyright (c) 2006, Eugene Romanenko, netlabs.org
3 *
4 *----------------------------------------------------------------------
5 * This file is part of poppler plugin for Lucide (lupoppler).
6 *
7 *  lupoppler is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 *
12 *  lupoppler is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU General Public License for more details.
16 *----------------------------------------------------------------------
17 */
18
19// This file is fontconfig replacement which emulates functions
20// used by poppler.
21
22#define INCL_DOS
23#define INCL_WIN
24#include <os2.h>
25
26#include <map>
27#include <string>
28using namespace std;
29
30#include <stdio.h>
31#include <dos.h>
32#include <string.h>
33
34#include "fontconfig.h"
35
36#include <ft2build.h>
37#include FT_FREETYPE_H
38
39
40static char *newstrdup( const char *s )
41{
42    if ( s == NULL ) {
43        return NULL;
44    }
45    char *temp = new char[ strlen( s ) + 1 ];
46    strcpy( temp, s );
47    return temp;
48}
49
50static string rtrim( const char *p )
51{
52    size_t len = strlen( p );
53    char *temp = new char[ len + 1 ];
54    strcpy( temp, p );
55
56    for ( int i = len - 1; i >= 0; i-- )
57    {
58        if ( isspace( temp[ i ] ) ) {
59            temp[ i ] = 0;
60        }
61        else {
62            break;
63        }
64    }
65    string r = temp;
66    delete temp;
67    return r;
68}
69
70// er_tokens - utility class
71class er_tokens
72{
73    private:
74        char   separator;
75        size_t len;
76        char   *str;
77        char   *tmp;
78        size_t curoffs;
79    public:
80        er_tokens( const char *s, char sep );
81        ~er_tokens();
82        char *nexttoken();
83};
84
85er_tokens::er_tokens( const char *s, char sep )
86{
87    separator = sep;
88    len = strlen( s );
89    str = new char[ len + 1 ];
90    strcpy( str , s );
91    tmp = new char[ len + 1 ];
92    curoffs = 0;
93}
94
95er_tokens::~er_tokens()
96{
97    delete str;
98    delete tmp;
99}
100
101char *er_tokens::nexttoken()
102{
103    if ( curoffs >= len ) {
104        return NULL;
105    }
106
107    memset( tmp, 0, len + 1 );
108
109    if ( str[ curoffs ] == separator ) {
110        curoffs++;
111    }
112    else
113    {
114        char *t1 = str + curoffs;
115        char *t2 = tmp;
116
117        while ( ( *t1 != separator ) && ( *t1 != 0 ) ) {
118            *t2++ = *t1++;
119            curoffs++;
120        }
121        curoffs++;
122    }
123
124    return tmp;
125}
126
127struct FcfRecord
128{
129    char filename[ _MAX_PATH ];
130    char family[ 64 ];
131    char style[ 64 ];
132    long size;
133    long modified;
134};
135
136static map<string,string>    *fontmap = NULL;   // font name / font filename
137static map<string,FcfRecord> *fcfmap = NULL;    // font filename / FcfRecord
138static bool fcfChanged = false;
139static FT_Library ftlib;
140
141
142struct _FcPattern
143{
144    char *family;
145    int slant;
146    int weight;
147    int width;
148    int spacing;
149    char *lang;
150
151    char *filename;
152};
153
154
155FcConfig *FcConfigGetCurrent()
156{
157    return NULL;
158}
159
160FcBool FcConfigSubstitute( FcConfig *config, FcPattern *p, FcMatchKind kind )
161{
162    return FcTrue;
163}
164
165
166void FcDefaultSubstitute( FcPattern *pattern )
167{
168}
169
170void FcFontSetDestroy( FcFontSet *s )
171{
172    for ( int i = 0; i < s->nfont; i++ ) {
173        FcPatternDestroy( s->fonts[i] );
174    }
175    delete s->fonts;
176    delete s;
177}
178
179static void ftLoad( char *fn )
180{
181    int l = strlen( fn );
182    if ( l < 5 ) {
183        return;
184    }
185
186    if ( ( stricmp( fn + ( l - 4 ), ".OFM" ) != 0 ) &&
187         ( stricmp( fn + ( l - 4 ), ".PFB" ) != 0 ) &&
188         ( stricmp( fn + ( l - 4 ), ".PFA" ) != 0 ) &&
189         ( stricmp( fn + ( l - 4 ), ".TTF" ) != 0 ) &&
190         ( stricmp( fn + ( l - 4 ), ".TTC" ) != 0 ) )
191    {
192        return;
193    }
194
195    if ( stricmp( fn + ( l - 4 ), ".OFM" ) == 0 ) {
196        fn[ l - 3 ] = 'P';
197        fn[ l - 1 ] = 'B';
198    }
199
200    string familyName = "";
201    string styleName = "";
202
203    bool needread = false;
204    struct stat st = {0};
205    stat( fn, &st );
206
207    if ( fcfmap->find( fn ) == fcfmap->end() ) {
208        needread = true;
209    }
210    else {
211        FcfRecord r = (*fcfmap)[ fn ];
212        if ( ( r.size == st.st_size ) && ( r.modified == st.st_mtime ) ) {
213            familyName = rtrim( r.family );
214            styleName = rtrim( r.style );
215        }
216        else {
217            needread = true;
218        }
219    }
220
221    if ( needread )
222    {
223        //printf( "read: %s\n", fn );
224        fcfChanged = true;
225
226        FT_Face ftface;
227        if ( FT_New_Face( ftlib, fn, 0, &ftface ) ) {
228            return;
229        }
230
231        familyName = rtrim( ftface->family_name );
232        styleName = rtrim( ftface->style_name );
233
234        FT_Done_Face( ftface );
235    }
236
237    string key = familyName;
238    if ( stricmp( styleName.c_str(), "regular" ) != 0 ) {
239        key += ' ';
240        key += styleName;
241    }
242
243    char *tmpkey = newstrdup( key.c_str() );
244    strlwr( tmpkey );
245    key = tmpkey;
246    delete tmpkey;
247
248    (*fontmap)[ key ] = fn;
249    //printf( "%s: %s\n", fn, key.c_str() );
250
251    FcfRecord fcfr = {0};
252    strcpy( fcfr.filename, fn );
253    strncpy( fcfr.family, familyName.c_str(), sizeof( fcfr.family ) - 1 );
254    strncpy( fcfr.style, styleName.c_str(), sizeof( fcfr.style ) - 1 );
255    fcfr.size = st.st_size;
256    fcfr.modified = st.st_mtime;
257
258    (*fcfmap)[ fn ] = fcfr;
259}
260
261
262static string getFcfName()
263{
264    char fullpath[ _MAX_PATH ];
265    char drive[ _MAX_DRIVE ];
266    char dir[ _MAX_DIR ];
267    char fname[ _MAX_FNAME ];
268    _splitpath( __argv[0], drive, dir, fname, NULL );
269    strlwr( fname );
270    _makepath( fullpath, drive, dir, fname, ".fcf" );
271    return fullpath;
272}
273
274/*static void loadDir( string path )
275{
276    string pathnam = path + "\\*";
277
278    struct find_t ffblk;
279    unsigned done = _dos_findfirst( pathnam.c_str(), _A_RDONLY | _A_NORMAL, &ffblk );
280    while ( done == 0 )
281    {
282        string fname = path + '\\' + ffblk.name;
283        char *fn = newstrdup( fname.c_str() );
284        ftLoad( fn );
285        delete fn;
286        done = _dos_findnext( &ffblk );
287    }
288    _dos_findclose( &ffblk );
289} */
290
291static void saveFcf( const char *fn )
292{
293    FILE *f = NULL;
294
295    if ( ( f = fopen( fn, "w" ) ) == NULL ) {
296        return;
297    }
298
299    fputs( "# Font configuration file.\n" \
300           "# Auto-generated file, do not edit!\n", f );
301
302    map<string,FcfRecord>::const_iterator iter;
303    for ( iter = fcfmap->begin(); iter != fcfmap->end(); iter++ )
304    {
305        FcfRecord r = (*iter).second;
306        fprintf( f, "|%s|%s|%s|%ld|%ld|\n", r.filename, r.family, r.style,
307                 r.size, r.modified );
308    }
309    fclose( f );
310}
311
312#define READ_BUF    4096
313static void readFcf( const char *fn )
314{
315    if ( access( fn, 0 ) != 0 ) {
316        return;
317    }
318
319    FILE *f = NULL;
320
321    if ( ( f = fopen( fn, "r" ) ) == NULL ) {
322        return;
323    }
324
325    char *buf = new char[ READ_BUF ];
326
327    while( fgets( buf, READ_BUF, f ) != NULL )
328    {
329        if ( buf[0] == '|' )
330        {
331            FcfRecord r = {0};
332
333            er_tokens tkn( buf + 1, '|' );
334            strncpy( r.filename, tkn.nexttoken(), sizeof( r.filename ) - 1 );
335            strncpy( r.family, tkn.nexttoken(), sizeof( r.family ) - 1 );
336            strncpy( r.style, tkn.nexttoken(), sizeof( r.style ) - 1 );
337            r.size = atol( tkn.nexttoken() );
338            r.modified = atol( tkn.nexttoken() );
339
340            (*fcfmap)[ r.filename ] = r;
341        }
342    }
343
344    fclose( f );
345}
346
347#define FLIST_SIZE  (1024*64)
348
349
350FcBool FcInit()
351{
352    if ( fontmap != NULL ) {
353        return FcTrue;
354    }
355
356    if ( FT_Init_FreeType( &ftlib ) ) {
357        return FcFalse;
358    }
359
360    fcfChanged = false;
361
362    string fcfname = getFcfName();
363
364    fontmap = new map<string,string>;
365    fcfmap  = new map<string,FcfRecord>;
366
367    readFcf( fcfname.c_str() );
368
369    // enum installed fonts
370    ULONG uldrv = 0;
371    DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &uldrv, sizeof( ULONG ) );
372    char drv = (char)( uldrv + '@' );
373
374    const char *pmfonts = "PM_Fonts";
375    char *fnames = new char[ FLIST_SIZE ];
376    memset( fnames, 0, FLIST_SIZE );
377    PrfQueryProfileString( HINI_USER, pmfonts, NULL, NULL, fnames, FLIST_SIZE );
378
379    char *fn1 = new char[ CCHMAXPATH ];
380    char *fn2 = new char[ CCHMAXPATH ];
381    int noffset = 0;
382    while ( fnames[ noffset ] != 0 )
383    {
384        const char *fname = fnames + noffset;
385
386        PrfQueryProfileString( HINI_USER, pmfonts, fname, "", fn1, CCHMAXPATH );
387
388        if ( fn1[ 0 ] == '\\' ) {
389            fn2[ 0 ] = drv;
390            fn2[ 1 ] = ':';
391            fn2[ 2 ] = 0;
392            strcat( fn2, fn1 );
393        }
394        else {
395            strcpy( fn2, fn1 );
396        }
397
398        ftLoad( fn2 );
399
400        noffset += ( strlen( fname ) + 1 );
401    }
402    delete fn1;
403    delete fn2;
404    delete fnames;
405
406    // TODO: load some fonts dir?
407    //loadDir( "Fonts" );
408
409    if ( fcfChanged ) {
410        saveFcf( fcfname.c_str() );
411    }
412
413    return FcTrue;
414}
415
416
417//
418// Assume fonts "Times New Roman", "Helvetica" and "Courier" always
419// present on any system (see GPI Guide and Reference, section
420// "Fonts" -> "About Fonts" -> "PM-Supplied Fonts").
421//
422#define DEFAULT_SERIF_FONT          "times new roman"
423#define DEFAULT_SANSSERIF_FONT      "helvetica"
424#define DEFAULT_MONOSPACED_FONT     "courier"
425
426static string buildFontKey( FcPattern *p, bool useDefaultFonts )
427{
428    string key = p->family;
429
430    if ( useDefaultFonts )
431    {
432        if ( p->spacing == FC_MONO ) {
433            key = DEFAULT_MONOSPACED_FONT;
434        }
435        else
436        {
437            if ( ( strstr( p->family, "swiss" ) != NULL ) ||
438                 ( strstr( p->family, "sans" ) != NULL ) )
439            {
440                key = DEFAULT_SANSSERIF_FONT;
441            }
442            else {
443                key = DEFAULT_SERIF_FONT;
444            }
445        }
446    }
447
448    if ( p->weight > FC_WEIGHT_NORMAL ) {
449        key += ' ';
450        key += "bold";
451    }
452
453    if ( p->slant != FC_SLANT_ROMAN ) {
454        key += ' ';
455        key += "italic";
456    }
457
458    return key;
459}
460
461FcFontSet *FcFontSort( FcConfig *config, FcPattern *p, FcBool trim,
462                       FcCharSet **csp, FcResult *result )
463{
464    FcPattern *pat = new FcPattern;
465    pat->family   = newstrdup( p->family );
466    pat->slant    = p->slant;
467    pat->weight   = p->weight;
468    pat->width    = p->width;
469    pat->spacing  = p->spacing;
470    pat->lang     = newstrdup( p->lang );
471    pat->filename = NULL;
472
473    string key = buildFontKey( pat, false );
474
475    if ( fontmap->find( key ) == fontmap->end() ) {
476        key = buildFontKey( pat, true );
477        pat->filename = newstrdup( (*fontmap)[ key ].c_str() );
478    }
479    else {
480        pat->filename = newstrdup( (*fontmap)[ key ].c_str() );
481    }
482
483    //printf( "MATCHED STYLE: %s, FILENAME: %s\n", key.c_str(), pat->filename );
484
485    FcFontSet *fs = new FcFontSet;
486    fs->nfont = 1;
487    fs->sfont = 1;
488    fs->fonts = new FcPattern *[ 1 ];
489    fs->fonts[ 0 ] = pat;
490
491    return fs;
492}
493
494void FcFontSetSortDestroy( FcFontSet *fs )
495{
496}
497
498void FcPatternDestroy( FcPattern *p )
499{
500    delete p->family;
501    delete p->lang;
502    delete p->filename;
503}
504
505FcResult FcPatternGetInteger( const FcPattern *p, const char *object, int n, int *i )
506{
507    return FcResultMatch;
508}
509
510FcResult FcPatternGetString( const FcPattern *p, const char *object, int n, FcChar8 **s )
511{
512    if ( strcmp( object, FC_FILE ) == 0 )
513    {
514        *s = p->filename;
515        return FcResultMatch;
516    }
517    return FcResultNoMatch;
518}
519
520FcPattern *FcPatternBuild( void *,
521                    const char *fcFamily, FcType tFamily, const char *family,
522                    const char *fcSlant, FcType tSlant, int slant,
523                    const char *fcWeight, FcType tWeight, int weight,
524                    const char *fcWidth, FcType tWidth, int width,
525                    const char *fcSpacing, FcType tSpacing, int spacing,
526                    const char *fcLang, FcType tLang, const char *lang, void * )
527{
528    //printf( "FAMILY: %s, SLANT: %d, WEIGHT: %d, WIDTH: %d, SPACING: %d, LANG: %s\n",
529    //        family, slant, weight, width, spacing, lang );
530
531    FcPattern *p = new FcPattern;
532    p->family   = newstrdup( family );
533    strlwr( p->family );
534    p->slant    = slant;
535    p->weight   = weight;
536    p->width    = width;
537    p->spacing  = spacing;
538    p->lang     = newstrdup( lang );
539    p->filename = NULL;
540
541    return p;
542}
543
Note: See TracBrowser for help on using the repository browser.