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

Last change on this file since 478 was 478, checked in by Silvan Scherrer, 10 years ago

shit forgot to disable debug

File size: 15.9 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#if defined(__EMX__)
25#define OS2EMX_PLAIN_CHAR
26#endif
27#include <os2.h>
28
29#include <map>
30#include <string>
31using namespace std;
32
33#include <stdio.h>
34#include <string.h>
35
36#if defined( __WATCOMC__ )
37#include <dos.h>
38#else
39#include <io.h>
40#include <sys/stat.h>
41#endif
42
43#include "fontconfig.h"
44
45#include <ft2build.h>
46#include FT_FREETYPE_H
47
48
49static char *newstrdup( const char *s )
50{
51    if ( s == NULL ) {
52        return NULL;
53    }
54    char *temp = new char[ strlen( s ) + 1 ];
55    strcpy( temp, s );
56    return temp;
57}
58
59static string rtrim( const char *p )
60{
61    size_t len = strlen( p );
62    char *temp = new char[ len + 1 ];
63    strcpy( temp, p );
64
65    for ( int i = len - 1; i >= 0; i-- )
66    {
67        if ( isspace( temp[ i ] ) ) {
68            temp[ i ] = 0;
69        }
70        else {
71            break;
72        }
73    }
74    string r = temp;
75    delete temp;
76    return r;
77}
78
79// er_tokens - utility class
80class er_tokens
81{
82    private:
83        char   separator;
84        size_t len;
85        char   *str;
86        char   *tmp;
87        size_t curoffs;
88    public:
89        er_tokens( const char *s, char sep );
90        ~er_tokens();
91        char *nexttoken();
92};
93
94er_tokens::er_tokens( const char *s, char sep )
95{
96    separator = sep;
97    len = strlen( s );
98    str = new char[ len + 1 ];
99    strcpy( str , s );
100    tmp = new char[ len + 1 ];
101    curoffs = 0;
102}
103
104er_tokens::~er_tokens()
105{
106    delete str;
107    delete tmp;
108}
109
110char *er_tokens::nexttoken()
111{
112    if ( curoffs >= len ) {
113        return NULL;
114    }
115
116    memset( tmp, 0, len + 1 );
117
118    if ( str[ curoffs ] == separator ) {
119        curoffs++;
120    }
121    else
122    {
123        char *t1 = str + curoffs;
124        char *t2 = tmp;
125
126        while ( ( *t1 != separator ) && ( *t1 != 0 ) ) {
127            *t2++ = *t1++;
128            curoffs++;
129        }
130        curoffs++;
131    }
132
133    return tmp;
134}
135
136struct FcfRecord
137{
138    char filename[ _MAX_PATH ];
139    char family[ 64 ];
140    char style[ 64 ];
141    long size;
142    long modified;
143};
144
145static map<string,string>    *fontmap = NULL;   // font name / font filename
146static map<string,FcfRecord> *fcfmap = NULL;    // font filename / FcfRecord
147static bool fcfChanged = false;
148static FT_Library ftlib;
149
150
151struct _FcPattern
152{
153    char *family;
154    int slant;
155    int weight;
156    int width;
157    int spacing;
158    char *lang;
159
160    char *filename;
161};
162
163
164FcConfig *FcConfigGetCurrent()
165{
166    // STUB
167    return NULL;
168}
169
170FcBool FcConfigSubstitute( FcConfig *config, FcPattern *p, FcMatchKind kind )
171{
172    // STUB
173    return FcTrue;
174}
175
176
177void FcDefaultSubstitute( FcPattern *pattern )
178{
179    // STUB
180}
181
182void FcFontSetDestroy( FcFontSet *s )
183{
184    for ( int i = 0; i < s->nfont; i++ ) {
185        FcPatternDestroy( s->fonts[i] );
186    }
187    delete s->fonts;
188    delete s;
189}
190
191static void ftLoad( char *fn )
192{
193    //printf( "Loading font %s\n", fn );
194    int l = strlen( fn );
195    if ( l < 5 ) {
196        return;
197    }
198
199    if ( ( stricmp( fn + ( l - 4 ), ".OFM" ) != 0 ) &&
200         ( stricmp( fn + ( l - 4 ), ".PFB" ) != 0 ) &&
201         ( stricmp( fn + ( l - 4 ), ".PFA" ) != 0 ) &&
202         ( stricmp( fn + ( l - 4 ), ".TTF" ) != 0 ) &&
203         ( stricmp( fn + ( l - 4 ), ".TTC" ) != 0 ) )
204    {
205        return;
206    }
207
208    if ( stricmp( fn + ( l - 4 ), ".OFM" ) == 0 ) {
209        fn[ l - 3 ] = 'P';
210        fn[ l - 1 ] = 'B';
211    }
212
213    string familyName = "";
214    string styleName = "";
215
216    bool needread = false;
217    struct stat st = {0};
218    stat( fn, &st );
219
220    if ( fcfmap->find( fn ) == fcfmap->end() ) {
221        needread = true;
222    }
223    else {
224        FcfRecord r = (*fcfmap)[ fn ];
225        if ( ( r.size == st.st_size ) && ( r.modified == st.st_mtime ) ) {
226            familyName = rtrim( r.family );
227            styleName = rtrim( r.style );
228        }
229        else {
230            needread = true;
231        }
232    }
233
234    if ( needread )
235    {
236        //printf( "read: %s\n", fn );
237        fcfChanged = true;
238
239        FT_Face ftface;
240        if ( FT_New_Face( ftlib, fn, 0, &ftface ) ) {
241            return;
242        }
243        //printf( "readed, family_name: %s   style_name: %s\n", ftface->family_name, ftface->style_name );
244
245        if ( ( ftface->family_name == NULL ) || ( ftface->style_name == NULL ) ) {
246            printf( "Broken font file: %s\n", fn );
247            FT_Done_Face( ftface );
248            return;
249        }
250
251        familyName = rtrim( ftface->family_name );
252        styleName = rtrim( ftface->style_name );
253
254        FT_Done_Face( ftface );
255    }
256
257    string key = familyName;
258    if ( stricmp( styleName.c_str(), "regular" ) != 0 &&
259         stricmp( styleName.c_str(), "book" ) != 0 ) {
260        key += ' ';
261        key += styleName;
262    }
263
264    char *tmpkey = newstrdup( key.c_str() );
265    strlwr( tmpkey );
266    key = tmpkey;
267    delete tmpkey;
268
269    (*fontmap)[ key ] = fn;
270    //printf( "%s: %s\n", fn, key.c_str() );
271
272    FcfRecord fcfr = {0};
273    strcpy( fcfr.filename, fn );
274    strncpy( fcfr.family, familyName.c_str(), sizeof( fcfr.family ) - 1 );
275    strncpy( fcfr.style, styleName.c_str(), sizeof( fcfr.style ) - 1 );
276    fcfr.size = st.st_size;
277    fcfr.modified = st.st_mtime;
278
279    (*fcfmap)[ fn ] = fcfr;
280    //printf( "Done loading font %s\n", fn );
281}
282
283
284static string getFcfName()
285{
286    char fullpath[ _MAX_PATH ];
287    char drive[ _MAX_DRIVE ];
288    char dir[ _MAX_DIR ];
289    char fname[ _MAX_FNAME ];
290#if defined( __WATCOMC__ )
291    _splitpath( __argv[0], drive, dir, fname, NULL );
292#else
293    _execname( fullpath, sizeof(fullpath) );
294    _splitpath( fullpath, drive, dir, fname, NULL );
295#endif
296    strlwr( fname );
297    _makepath( fullpath, drive, dir, fname, ".fcf" );
298    return fullpath;
299}
300
301/*static void loadDir( string path )
302{
303    string pathnam = path + "\\*";
304
305    struct find_t ffblk;
306    unsigned done = _dos_findfirst( pathnam.c_str(), _A_RDONLY | _A_NORMAL, &ffblk );
307    while ( done == 0 )
308    {
309        string fname = path + '\\' + ffblk.name;
310        char *fn = newstrdup( fname.c_str() );
311        ftLoad( fn );
312        delete fn;
313        done = _dos_findnext( &ffblk );
314    }
315    _dos_findclose( &ffblk );
316} */
317
318static void saveFcf( const char *fn )
319{
320    FILE *f = NULL;
321
322    if ( ( f = fopen( fn, "w" ) ) == NULL ) {
323        return;
324    }
325
326    fputs( "# Font configuration file.\n" \
327           "# Auto-generated file, do not edit!\n", f );
328
329    map<string,FcfRecord>::const_iterator iter;
330    for ( iter = fcfmap->begin(); iter != fcfmap->end(); iter++ )
331    {
332        FcfRecord r = (*iter).second;
333        fprintf( f, "|%s|%s|%s|%ld|%ld|\n", r.filename, r.family, r.style,
334                 r.size, r.modified );
335    }
336    fclose( f );
337}
338
339#define READ_BUF    4096
340static void readFcf( const char *fn )
341{
342    if ( access( fn, 0 ) != 0 ) {
343        return;
344    }
345
346    FILE *f = NULL;
347
348    if ( ( f = fopen( fn, "r" ) ) == NULL ) {
349        return;
350    }
351
352    char *buf = new char[ READ_BUF ];
353
354    while( fgets( buf, READ_BUF, f ) != NULL )
355    {
356        if ( buf[0] == '|' )
357        {
358            FcfRecord r = {0};
359
360            er_tokens tkn( buf + 1, '|' );
361            strncpy( r.filename, tkn.nexttoken(), sizeof( r.filename ) - 1 );
362            strncpy( r.family, tkn.nexttoken(), sizeof( r.family ) - 1 );
363            strncpy( r.style, tkn.nexttoken(), sizeof( r.style ) - 1 );
364            r.size = atol( tkn.nexttoken() );
365            r.modified = atol( tkn.nexttoken() );
366
367            (*fcfmap)[ r.filename ] = r;
368        }
369    }
370
371    fclose( f );
372}
373
374#define FLIST_SIZE  (1024*64)
375
376
377FcBool FcInit()
378{
379    if ( fontmap != NULL ) {
380        return FcTrue;
381    }
382
383    if ( FT_Init_FreeType( &ftlib ) ) {
384        return FcFalse;
385    }
386
387    fcfChanged = false;
388
389    string fcfname = getFcfName();
390
391    fontmap = new map<string,string>;
392    fcfmap  = new map<string,FcfRecord>;
393
394    readFcf( fcfname.c_str() );
395
396    // enum installed fonts
397    ULONG uldrv = 0;
398    DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &uldrv, sizeof( ULONG ) );
399    char drv = (char)( uldrv + '@' );
400
401    const char *pmfonts = "PM_Fonts";
402    char *fnames = new char[ FLIST_SIZE ];
403    memset( fnames, 0, FLIST_SIZE );
404    PrfQueryProfileString( HINI_USER, pmfonts, NULL, NULL, fnames, FLIST_SIZE );
405
406    char *fn1 = new char[ CCHMAXPATH ];
407    char *fn2 = new char[ CCHMAXPATH ];
408    int noffset = 0;
409    while ( fnames[ noffset ] != 0 )
410    {
411        const char *fname = fnames + noffset;
412
413        PrfQueryProfileString( HINI_USER, pmfonts, fname, "", fn1, CCHMAXPATH );
414
415        if ( fn1[ 0 ] == '\\' ) {
416            fn2[ 0 ] = drv;
417            fn2[ 1 ] = ':';
418            fn2[ 2 ] = 0;
419            strcat( fn2, fn1 );
420        }
421        else {
422            strcpy( fn2, fn1 );
423        }
424
425        ftLoad( fn2 );
426
427        noffset += ( strlen( fname ) + 1 );
428    }
429    delete fn1;
430    delete fn2;
431    delete fnames;
432
433    // TODO: load some fonts dir?
434    //loadDir( "Fonts" );
435
436    if ( fcfChanged ) {
437        saveFcf( fcfname.c_str() );
438    }
439
440    return FcTrue;
441}
442
443
444//
445// Assume fonts "Times New Roman", "Helvetica" and "Courier" always
446// present on any system (see GPI Guide and Reference, section
447// "Fonts" -> "About Fonts" -> "PM-Supplied Fonts").
448//
449#define DEFAULT_SERIF_FONT          "times new roman"
450#define DEFAULT_SERIF_FONTJA       "times new roman wt j"
451#define DEFAULT_SANSSERIF_FONT      "helvetica"
452#define DEFAULT_MONOSPACED_FONT     "courier"
453#define DEFAULT_SYMBOL_FONT         "symbol set"
454
455static bool isSansserif( const char *family )
456{
457    return ( ( strstr( family, "swiss" ) != NULL ) ||
458             ( strstr( family, "sans" ) != NULL ) ||
459             ( strcmp( family, "arial" ) == 0 ) ||
460             ( strcmp( family, "tahoma" ) == 0 ) ||
461             ( strcmp( family, "verdana" ) == 0 ) );
462}
463
464static string buildFontKey( FcPattern *p )
465{
466    string key = p->family;
467
468    // From http://en.wikipedia.org/wiki/Portable_Document_Format:
469    //
470    // There are fourteen typefaces that have a special significance to PDF
471    // documents:
472    //
473    //  * Times (v3) (in regular, italic, bold, and bold italic)
474    //  * Courier (in regular, oblique, bold and bold oblique)
475    //  * Helvetica (v3) (in regular, oblique, bold and bold oblique)
476    //  * Symbol
477    //  * Zapf Dingbats
478    //
479    // These fonts, sometimes referred to as the "base fourteen fonts" should
480    // always be present (actually present or a close substitute) and so need
481    // not be embedded in a PDF.[46]  PDF viewers must know about the metrics
482    // of these fonts. Other fonts may be substituted if they are not embedded
483    // in a PDF.
484    //
485    // The following code is based on this information and guarantees that we
486    // always return a valid font for those (except Zapf Dingbats for which we
487    // don't have a pre-installed OS/2 font).
488
489    bool ignoreStyle = false;
490
491    if ( fontmap->find( key ) == fontmap->end() ) {
492        // not found: try substitutions
493        if (!stricmp(p->lang, "ja"))
494        {
495            key = DEFAULT_SERIF_FONTJA;
496        } else {
497
498        if ( p->spacing == FC_MONO ) {
499            key = DEFAULT_MONOSPACED_FONT;
500        } else {
501            if ( isSansserif( p->family ) ) {
502                key = DEFAULT_SANSSERIF_FONT;
503            } else {
504                if ( key == "symbol" ) {
505                    ignoreStyle = true;
506                    key = "opensymbol";
507                    if ( fontmap->find( key ) == fontmap->end() )
508                        key = DEFAULT_SYMBOL_FONT;
509                } else if ( key == "zapfdingbats" || key == "zapf dingbats" ) {
510                    ignoreStyle = true;
511                    key = "dejavu sans";
512                    // last resort, quite meaningless but we must provide something
513                    if ( fontmap->find( key ) == fontmap->end() )
514                        key = DEFAULT_SYMBOL_FONT;
515                } else {
516                        key = DEFAULT_SERIF_FONT;
517                }
518            }
519        }
520       }
521    }
522
523    if ( !ignoreStyle ) {
524        if ( p->weight > FC_WEIGHT_NORMAL ) {
525            key += ' ';
526            key += "bold";
527        }
528        if ( (p->slant == FC_SLANT_ITALIC) || (p->slant == FC_SLANT_OBLIQUE) ) {
529            key += ' ';
530            key += "italic";
531        }
532    }
533
534    return key;
535}
536
537FcFontSet *FcFontSort( FcConfig *config, FcPattern *p, FcBool trim,
538                       FcCharSet **csp, FcResult *result )
539{
540    // we need to make sure the fonfconfig is initialised.
541    if (!FcInit())
542       {
543          return NULL;
544       }
545
546    FcPattern *pat = new FcPattern;
547    pat->family   = newstrdup( p->family );
548    pat->slant    = p->slant;
549    pat->weight   = p->weight;
550    pat->width    = p->width;
551    pat->spacing  = p->spacing;
552    pat->lang     = newstrdup( p->lang );
553    pat->filename = NULL;
554
555    string key = buildFontKey( pat );
556    pat->filename = newstrdup( (*fontmap)[ key ].c_str() );
557
558//    printf( "fontfamily: %s --> MATCHED STYLE: %s, FILENAME: %s\n", pat->family, key.c_str(), pat->filename );
559//    printf("SLANT: %d, WEIGHT:%d, WIDTH:%d, SPACING:%d, LANG:%s\n", pat->slant, pat->weight, pat->width, pat->spacing, pat->lang);
560
561    FcFontSet *fs = new FcFontSet;
562    fs->nfont = 1;
563    fs->sfont = 1;
564    fs->fonts = new FcPattern *[ 1 ];
565    fs->fonts[ 0 ] = pat;
566
567    return fs;
568}
569
570void FcFontSetSortDestroy( FcFontSet *fs )
571{
572    // STUB
573}
574
575void FcPatternDestroy( FcPattern *p )
576{
577    delete p->family;
578    delete p->lang;
579    delete p->filename;
580}
581
582FcResult FcPatternGetInteger( const FcPattern *p, const char *object, int n, int *i )
583{
584    // STUB
585    *i = 0;
586    return FcResultMatch;
587}
588
589FcResult FcPatternGetString( const FcPattern *p, const char *object, int n, FcChar8 **s )
590{
591    if ( strcmp( object, FC_FILE ) == 0 )
592    {
593        *s = p->filename;
594        return FcResultMatch;
595    }
596    return FcResultNoMatch;
597}
598
599FcPattern *FcPatternBuild( void *,
600                    const char *fcFamily, FcType tFamily, const char *family,
601                    const char *fcLang, FcType tLang, const char *lang, void * )
602{
603//    printf( "FAMILY: %s, LANG: %s\n", family, lang );
604
605    FcPattern *p = new FcPattern;
606    p->family   = newstrdup( family );
607    strlwr( p->family );
608    p->slant    = -1;
609    p->weight   = -1;
610    p->width    = -1;
611    p->spacing  = -1;
612    p->lang     = newstrdup( lang );
613    p->filename = NULL;
614
615    return p;
616}
617
618void FcPatternAddInteger(FcPattern *p, const char *fcType, int value)
619{
620// handle all possible int values
621   if (!strcmp(fcType, FC_SLANT)) {
622      p->slant = value;
623   }
624
625   if (!strcmp(fcType, FC_WEIGHT)) {
626      p->weight = value;
627   }
628
629   if (!strcmp(fcType, FC_WIDTH)) {
630      p->width = value;
631   }
632
633   if (!strcmp(fcType, FC_SPACING)) {
634      p->spacing = value;
635   }
636
637//   printf("FAMILY: %s, SLANT: %d, WEIGHT:%d, WIDTH:%d, SPACING:%d\n", p->family, p->slant, p->weight, p->width, p->spacing);
638
639   return;
640}
641
Note: See TracBrowser for help on using the repository browser.