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

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

more comments, new method isFixedImage(), fixed keyboard selection of printer in printer dialog

File size: 13.1 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    // STUB
158    return NULL;
159}
160
161FcBool FcConfigSubstitute( FcConfig *config, FcPattern *p, FcMatchKind kind )
162{
163    // STUB
164    return FcTrue;
165}
166
167
168void FcDefaultSubstitute( FcPattern *pattern )
169{
170    // STUB
171}
172
173void FcFontSetDestroy( FcFontSet *s )
174{
175    for ( int i = 0; i < s->nfont; i++ ) {
176        FcPatternDestroy( s->fonts[i] );
177    }
178    delete s->fonts;
179    delete s;
180}
181
182static void ftLoad( char *fn )
183{
184    int l = strlen( fn );
185    if ( l < 5 ) {
186        return;
187    }
188
189    if ( ( stricmp( fn + ( l - 4 ), ".OFM" ) != 0 ) &&
190         ( stricmp( fn + ( l - 4 ), ".PFB" ) != 0 ) &&
191         ( stricmp( fn + ( l - 4 ), ".PFA" ) != 0 ) &&
192         ( stricmp( fn + ( l - 4 ), ".TTF" ) != 0 ) &&
193         ( stricmp( fn + ( l - 4 ), ".TTC" ) != 0 ) )
194    {
195        return;
196    }
197
198    if ( stricmp( fn + ( l - 4 ), ".OFM" ) == 0 ) {
199        fn[ l - 3 ] = 'P';
200        fn[ l - 1 ] = 'B';
201    }
202
203    string familyName = "";
204    string styleName = "";
205
206    bool needread = false;
207    struct stat st = {0};
208    stat( fn, &st );
209
210    if ( fcfmap->find( fn ) == fcfmap->end() ) {
211        needread = true;
212    }
213    else {
214        FcfRecord r = (*fcfmap)[ fn ];
215        if ( ( r.size == st.st_size ) && ( r.modified == st.st_mtime ) ) {
216            familyName = rtrim( r.family );
217            styleName = rtrim( r.style );
218        }
219        else {
220            needread = true;
221        }
222    }
223
224    if ( needread )
225    {
226        //printf( "read: %s\n", fn );
227        fcfChanged = true;
228
229        FT_Face ftface;
230        if ( FT_New_Face( ftlib, fn, 0, &ftface ) ) {
231            return;
232        }
233
234        familyName = rtrim( ftface->family_name );
235        styleName = rtrim( ftface->style_name );
236
237        FT_Done_Face( ftface );
238    }
239
240    string key = familyName;
241    if ( stricmp( styleName.c_str(), "regular" ) != 0 ) {
242        key += ' ';
243        key += styleName;
244    }
245
246    char *tmpkey = newstrdup( key.c_str() );
247    strlwr( tmpkey );
248    key = tmpkey;
249    delete tmpkey;
250
251    (*fontmap)[ key ] = fn;
252    //printf( "%s: %s\n", fn, key.c_str() );
253
254    FcfRecord fcfr = {0};
255    strcpy( fcfr.filename, fn );
256    strncpy( fcfr.family, familyName.c_str(), sizeof( fcfr.family ) - 1 );
257    strncpy( fcfr.style, styleName.c_str(), sizeof( fcfr.style ) - 1 );
258    fcfr.size = st.st_size;
259    fcfr.modified = st.st_mtime;
260
261    (*fcfmap)[ fn ] = fcfr;
262}
263
264
265static string getFcfName()
266{
267    char fullpath[ _MAX_PATH ];
268    char drive[ _MAX_DRIVE ];
269    char dir[ _MAX_DIR ];
270    char fname[ _MAX_FNAME ];
271    _splitpath( __argv[0], drive, dir, fname, NULL );
272    strlwr( fname );
273    _makepath( fullpath, drive, dir, fname, ".fcf" );
274    return fullpath;
275}
276
277/*static void loadDir( string path )
278{
279    string pathnam = path + "\\*";
280
281    struct find_t ffblk;
282    unsigned done = _dos_findfirst( pathnam.c_str(), _A_RDONLY | _A_NORMAL, &ffblk );
283    while ( done == 0 )
284    {
285        string fname = path + '\\' + ffblk.name;
286        char *fn = newstrdup( fname.c_str() );
287        ftLoad( fn );
288        delete fn;
289        done = _dos_findnext( &ffblk );
290    }
291    _dos_findclose( &ffblk );
292} */
293
294static void saveFcf( const char *fn )
295{
296    FILE *f = NULL;
297
298    if ( ( f = fopen( fn, "w" ) ) == NULL ) {
299        return;
300    }
301
302    fputs( "# Font configuration file.\n" \
303           "# Auto-generated file, do not edit!\n", f );
304
305    map<string,FcfRecord>::const_iterator iter;
306    for ( iter = fcfmap->begin(); iter != fcfmap->end(); iter++ )
307    {
308        FcfRecord r = (*iter).second;
309        fprintf( f, "|%s|%s|%s|%ld|%ld|\n", r.filename, r.family, r.style,
310                 r.size, r.modified );
311    }
312    fclose( f );
313}
314
315#define READ_BUF    4096
316static void readFcf( const char *fn )
317{
318    if ( access( fn, 0 ) != 0 ) {
319        return;
320    }
321
322    FILE *f = NULL;
323
324    if ( ( f = fopen( fn, "r" ) ) == NULL ) {
325        return;
326    }
327
328    char *buf = new char[ READ_BUF ];
329
330    while( fgets( buf, READ_BUF, f ) != NULL )
331    {
332        if ( buf[0] == '|' )
333        {
334            FcfRecord r = {0};
335
336            er_tokens tkn( buf + 1, '|' );
337            strncpy( r.filename, tkn.nexttoken(), sizeof( r.filename ) - 1 );
338            strncpy( r.family, tkn.nexttoken(), sizeof( r.family ) - 1 );
339            strncpy( r.style, tkn.nexttoken(), sizeof( r.style ) - 1 );
340            r.size = atol( tkn.nexttoken() );
341            r.modified = atol( tkn.nexttoken() );
342
343            (*fcfmap)[ r.filename ] = r;
344        }
345    }
346
347    fclose( f );
348}
349
350#define FLIST_SIZE  (1024*64)
351
352
353FcBool FcInit()
354{
355    if ( fontmap != NULL ) {
356        return FcTrue;
357    }
358
359    if ( FT_Init_FreeType( &ftlib ) ) {
360        return FcFalse;
361    }
362
363    fcfChanged = false;
364
365    string fcfname = getFcfName();
366
367    fontmap = new map<string,string>;
368    fcfmap  = new map<string,FcfRecord>;
369
370    readFcf( fcfname.c_str() );
371
372    // enum installed fonts
373    ULONG uldrv = 0;
374    DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &uldrv, sizeof( ULONG ) );
375    char drv = (char)( uldrv + '@' );
376
377    const char *pmfonts = "PM_Fonts";
378    char *fnames = new char[ FLIST_SIZE ];
379    memset( fnames, 0, FLIST_SIZE );
380    PrfQueryProfileString( HINI_USER, pmfonts, NULL, NULL, fnames, FLIST_SIZE );
381
382    char *fn1 = new char[ CCHMAXPATH ];
383    char *fn2 = new char[ CCHMAXPATH ];
384    int noffset = 0;
385    while ( fnames[ noffset ] != 0 )
386    {
387        const char *fname = fnames + noffset;
388
389        PrfQueryProfileString( HINI_USER, pmfonts, fname, "", fn1, CCHMAXPATH );
390
391        if ( fn1[ 0 ] == '\\' ) {
392            fn2[ 0 ] = drv;
393            fn2[ 1 ] = ':';
394            fn2[ 2 ] = 0;
395            strcat( fn2, fn1 );
396        }
397        else {
398            strcpy( fn2, fn1 );
399        }
400
401        ftLoad( fn2 );
402
403        noffset += ( strlen( fname ) + 1 );
404    }
405    delete fn1;
406    delete fn2;
407    delete fnames;
408
409    // TODO: load some fonts dir?
410    //loadDir( "Fonts" );
411
412    if ( fcfChanged ) {
413        saveFcf( fcfname.c_str() );
414    }
415
416    return FcTrue;
417}
418
419
420//
421// Assume fonts "Times New Roman", "Helvetica" and "Courier" always
422// present on any system (see GPI Guide and Reference, section
423// "Fonts" -> "About Fonts" -> "PM-Supplied Fonts").
424//
425#define DEFAULT_SERIF_FONT          "times new roman"
426#define DEFAULT_SANSSERIF_FONT      "helvetica"
427#define DEFAULT_MONOSPACED_FONT     "courier"
428
429static bool isSansserif( const char *family )
430{
431    return ( ( strstr( family, "swiss" ) != NULL ) ||
432             ( strstr( family, "sans" ) != NULL ) ||
433             ( strcmp( family, "arial" ) == 0 ) ||
434             ( strcmp( family, "tahoma" ) == 0 ) ||
435             ( strcmp( family, "verdana" ) == 0 ) );
436}
437
438static string buildFontKey( FcPattern *p, bool useDefaultFonts )
439{
440    string key = p->family;
441
442    if ( useDefaultFonts )
443    {
444        if ( p->spacing == FC_MONO ) {
445            key = DEFAULT_MONOSPACED_FONT;
446        }
447        else
448        {
449            if ( isSansserif( p->family ) ) {
450                key = DEFAULT_SANSSERIF_FONT;
451            }
452            else {
453                key = DEFAULT_SERIF_FONT;
454            }
455        }
456    }
457    else
458    {
459        // use 'Symbol Set' (SYMB.PFB) instead of 'Symbol'
460        if ( strcmp( p->family, "symbol" ) == 0 ) {
461            key = "symbol set";
462        }
463    }
464
465    if ( p->weight > FC_WEIGHT_NORMAL ) {
466        key += ' ';
467        key += "bold";
468    }
469
470    if ( p->slant != FC_SLANT_ROMAN ) {
471        key += ' ';
472        key += "italic";
473    }
474
475    return key;
476}
477
478FcFontSet *FcFontSort( FcConfig *config, FcPattern *p, FcBool trim,
479                       FcCharSet **csp, FcResult *result )
480{
481    FcPattern *pat = new FcPattern;
482    pat->family   = newstrdup( p->family );
483    pat->slant    = p->slant;
484    pat->weight   = p->weight;
485    pat->width    = p->width;
486    pat->spacing  = p->spacing;
487    pat->lang     = newstrdup( p->lang );
488    pat->filename = NULL;
489
490    string key = buildFontKey( pat, false );
491
492    if ( fontmap->find( key ) == fontmap->end() ) {
493        key = buildFontKey( pat, true );
494        pat->filename = newstrdup( (*fontmap)[ key ].c_str() );
495    }
496    else {
497        pat->filename = newstrdup( (*fontmap)[ key ].c_str() );
498    }
499
500//printf( "MATCHED STYLE: %s, FILENAME: %s\n", key.c_str(), pat->filename );
501
502    FcFontSet *fs = new FcFontSet;
503    fs->nfont = 1;
504    fs->sfont = 1;
505    fs->fonts = new FcPattern *[ 1 ];
506    fs->fonts[ 0 ] = pat;
507
508    return fs;
509}
510
511void FcFontSetSortDestroy( FcFontSet *fs )
512{
513    // STUB
514}
515
516void FcPatternDestroy( FcPattern *p )
517{
518    delete p->family;
519    delete p->lang;
520    delete p->filename;
521}
522
523FcResult FcPatternGetInteger( const FcPattern *p, const char *object, int n, int *i )
524{
525    // STUB
526    *i = 0;
527    return FcResultMatch;
528}
529
530FcResult FcPatternGetString( const FcPattern *p, const char *object, int n, FcChar8 **s )
531{
532    if ( strcmp( object, FC_FILE ) == 0 )
533    {
534        *s = p->filename;
535        return FcResultMatch;
536    }
537    return FcResultNoMatch;
538}
539
540FcPattern *FcPatternBuild( void *,
541                    const char *fcFamily, FcType tFamily, const char *family,
542                    const char *fcSlant, FcType tSlant, int slant,
543                    const char *fcWeight, FcType tWeight, int weight,
544                    const char *fcWidth, FcType tWidth, int width,
545                    const char *fcSpacing, FcType tSpacing, int spacing,
546                    const char *fcLang, FcType tLang, const char *lang, void * )
547{
548//printf( "FAMILY: %s, SLANT: %d, WEIGHT: %d, WIDTH: %d, SPACING: %d, LANG: %s\n",
549//            family, slant, weight, width, spacing, lang );
550
551    FcPattern *p = new FcPattern;
552    p->family   = newstrdup( family );
553    strlwr( p->family );
554    p->slant    = slant;
555    p->weight   = weight;
556    p->width    = width;
557    p->spacing  = spacing;
558    p->lang     = newstrdup( lang );
559    p->filename = NULL;
560
561    return p;
562}
563
Note: See TracBrowser for help on using the repository browser.