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

Last change on this file since 272 was 272, checked in by Eugene Romanenko, 13 years ago

PDF plugin: fix wrong itaic style (closes #154)

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