Code

warning cleanup
[inkscape.git] / src / libnrtype / FontFactory.cpp
1 /*
2  *  FontFactory.cpp
3  *  testICU
4  *
5  *   Authors:
6  *     fred
7  *     bulia byak <buliabyak@users.sf.net>
8  *
9  */
11 #include "FontFactory.h"
12 #include <libnrtype/font-instance.h>
14 #include <glibmm.h>
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
21 #include <glib/gmem.h>
22 #include <glibmm/i18n.h> // _()
24 /* Freetype2 */
25 # include <pango/pangoft2.h>
28 // need to avoid using the size field
29 size_t font_descr_hash::operator()( PangoFontDescription *const &x) const {
30     int h = 0;
31     h *= 1128467;
32     char const *theF = pango_font_description_get_family(x);
33     h += (theF)?g_str_hash(theF):0;
34     h *= 1128467;
35     h += (int)pango_font_description_get_style(x);
36     h *= 1128467;
37     h += (int)pango_font_description_get_variant(x);
38     h *= 1128467;
39     h += (int)pango_font_description_get_weight(x);
40     h *= 1128467;
41     h += (int)pango_font_description_get_stretch(x);
42     return h;
43 }
44 bool  font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDescription *const &b) {
45     //if ( pango_font_description_equal(a,b) ) return true;
46     char const *fa = pango_font_description_get_family(a);
47     char const *fb = pango_font_description_get_family(b);
48     if ( ( fa && fb == NULL ) || ( fb && fa == NULL ) ) return false;
49     if ( fa && fb && strcmp(fa,fb) != 0 ) return false;
50     if ( pango_font_description_get_style(a) != pango_font_description_get_style(b) ) return false;
51     if ( pango_font_description_get_variant(a) != pango_font_description_get_variant(b) ) return false;
52     if ( pango_font_description_get_weight(a) != pango_font_description_get_weight(b) ) return false;
53     if ( pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b) ) return false;
54     return true;
55 }
57 /////////////////// helper functions
59 /**
60  * A wrapper for strcasestr that also provides an implementation for Win32.
61  */
62 static bool
63 ink_strstr(char const *haystack, char const *pneedle)
64 {
65     // windows has no strcasestr implementation, so here is ours...
66     // stolen from nmap
67     /* FIXME: This is broken for e.g. ink_strstr("aab", "ab").  Report to nmap.
68      *
69      * Also, suggest use of g_ascii_todown instead of buffer stuff, and g_ascii_tolower instead
70      * of tolower.  Given that haystack is a font name (i.e. fairly short), it should be ok to
71      * do g_ascii_strdown on both haystack and pneedle, and do normal strstr.
72      *
73      * Rather than fixing in inkscape, consider getting rid of this routine, instead using
74      * strdown and plain strstr at caller.  We have control over the needle values, so we can
75      * modify the callers rather than calling strdown there.
76      */
77     char buf[512];
78     register char const *p;
79     char *needle, *q, *foundto;
80     if (!*pneedle) return true;
81     if (!haystack) return false;
82         
83     needle = buf;
84     p = pneedle; q = needle;
85     while ((*q++ = tolower(*p++)))
86         ;
87     p = haystack - 1; foundto = needle;
88     while (*++p) {
89         if (tolower(*p) == *foundto) {
90             if (!*++foundto) {
91                 /* Yeah, we found it */
92                 return true;
93             }
94         } else foundto = needle;
95     }
96     return false;
97 }
99 /**
100  * Regular fonts are 'Regular', 'Roman', 'Normal', or 'Plain'
101  */
102 // FIXME: make this UTF8, add non-English style names
103 static bool
104 is_regular(char const *s)
106     if (ink_strstr(s, "Regular")) return true;
107     if (ink_strstr(s, "Roman")) return true;
108     if (ink_strstr(s, "Normal")) return true;
109     if (ink_strstr(s, "Plain")) return true;
110     return false;
113 /**
114  * Non-bold fonts are 'Medium' or 'Book'
115  */
116 static bool
117 is_nonbold(char const *s)
119     if (ink_strstr(s, "Medium")) return true;
120     if (ink_strstr(s, "Book")) return true;
121     return false;
124 /**
125  * Italic fonts are 'Italic', 'Oblique', or 'Slanted'
126  */
127 static bool
128 is_italic(char const *s)
130     if (ink_strstr(s, "Italic")) return true;
131     if (ink_strstr(s, "Oblique")) return true;
132     if (ink_strstr(s, "Slanted")) return true;
133     return false;
136 /**
137  * Bold fonts are 'Bold'
138  */
139 static bool
140 is_bold(char const *s)
142     if (ink_strstr(s, "Bold")) return true;
143     return false;
146 /**
147  * Caps fonts are 'Caps'
148  */
149 static bool
150 is_caps(char const *s)
152     if (ink_strstr(s, "Caps")) return true;
153     return false;
156 #if 0 /* FIXME: These are all unused.  Please delete them or use them (presumably in
157 * style_name_compare). */
158 /**
159  * Monospaced fonts are 'Mono'
160  */
161 static bool
162 is_mono(char const *s)
164     if (ink_strstr(s, "Mono")) return true;
165     return false;
168 /**
169  * Rounded fonts are 'Round'
170  */
171 static bool
172 is_round(char const *s)
174     if (ink_strstr(s, "Round")) return true;
175     return false;
178 /**
179  * Outline fonts are 'Outline'
180  */
181 static bool
182 is_outline(char const *s)
184     if (ink_strstr(s, "Outline")) return true;
185     return false;
188 /**
189  * Swash fonts are 'Swash'
190  */
191 static bool
192 is_swash(char const *s)
194     if (ink_strstr(s, "Swash")) return true;
195     return false;
197 #endif
199 /**
200  * Determines if two style names match.  This allows us to match
201  * based on the type of style rather than simply doing string matching,
202  * because for instance 'Plain' and 'Normal' mean the same thing.
203  * 
204  * Q:  Shouldn't this include the other tests such as is_outline, etc.?
205  * Q:  Is there a problem with strcasecmp on Win32?  Should it use stricmp?
206  */
207 int
208 style_name_compare(char const *aa, char const *bb)
210     char const *a = (char const *) aa;
211     char const *b = (char const *) bb;
212         
213     if (is_regular(a) && !is_regular(b)) return -1;
214     if (is_regular(b) && !is_regular(a)) return 1;
215         
216     if (is_bold(a) && !is_bold(b)) return 1;
217     if (is_bold(b) && !is_bold(a)) return -1;
218         
219     if (is_italic(a) && !is_italic(b)) return 1;
220     if (is_italic(b) && !is_italic(a)) return -1;
221         
222     if (is_nonbold(a) && !is_nonbold(b)) return 1;
223     if (is_nonbold(b) && !is_nonbold(a)) return -1;
224         
225     if (is_caps(a) && !is_caps(b)) return 1;
226     if (is_caps(b) && !is_caps(a)) return -1;
227         
228     return strcasecmp(a, b);
231 /*
232  defined but not used:
234 static int
235 style_record_compare(void const *aa, void const *bb)
237     NRStyleRecord const *a = (NRStyleRecord const *) aa;
238     NRStyleRecord const *b = (NRStyleRecord const *) bb;
239         
240     return (style_name_compare(a->name, b->name));
243 static void font_factory_name_list_destructor(NRNameList *list) 
245     for (unsigned int i = 0; i < list->length; i++) 
246         g_free(list->names[i]);
247     if ( list->names ) g_free(list->names);
250 static void font_factory_style_list_destructor(NRStyleList *list) 
252     for (unsigned int i = 0; i < list->length; i++) {
253         g_free((void *) (list->records)[i].name);
254         g_free((void *) (list->records)[i].descr);
255     }
256     if ( list->records ) g_free(list->records);
258 */
260 /**
261  * On Win32 performs a stricmp(a,b), otherwise does a strcasecmp(a,b)
262  */
263 int
264 family_name_compare(char const *a, char const *b)
266 #ifndef WIN32
267     return strcasecmp((*((char const **) a)), (*((char const **) b)));
268 #else
269     return stricmp((*((char const **) a)), (*((char const **) b)));
270 #endif
273 void noop(...) {}
274 //#define PANGO_DEBUG g_print
275 #define PANGO_DEBUG noop
279 ///////////////////// FontFactory
280 #ifndef USE_PANGO_WIN32
281 // the substitute function to tell fontconfig to enforce outline fonts
282 void FactorySubstituteFunc(FcPattern *pattern,gpointer /*data*/)
284     FcPatternAddBool(pattern, "FC_OUTLINE",FcTrue);
285     //char *fam = NULL;
286     //FcPatternGetString(pattern, "FC_FAMILY",0, &fam);
287     //printf("subst_f on %s\n",fam);
289 #endif
292 font_factory *font_factory::lUsine = NULL;
294 font_factory *font_factory::Default(void)
296     if ( lUsine == NULL ) lUsine = new font_factory;
297     return lUsine;
300 font_factory::font_factory(void)
302     fontSize = 512;
303     nbEnt = 0;
304     maxEnt = 32;
305     ents = (font_entry*)g_malloc(maxEnt*sizeof(font_entry));
307 #ifdef USE_PANGO_WIN32
308     hScreenDC = pango_win32_get_dc();
309     fontServer = pango_win32_font_map_for_display();
310     fontContext = pango_win32_get_context();
311     pangoFontCache = pango_win32_font_map_get_font_cache(fontServer);
312 #else
313     fontServer = pango_ft2_font_map_new();
314     pango_ft2_font_map_set_resolution((PangoFT2FontMap*)fontServer, 72, 72);
315     fontContext = pango_ft2_font_map_create_context((PangoFT2FontMap*)fontServer);
316     pango_ft2_font_map_set_default_substitute((PangoFT2FontMap*)fontServer,FactorySubstituteFunc,this,NULL);
317 #endif
320 font_factory::~font_factory(void)
322     for (int i = 0;i < nbEnt;i++) ents[i].f->Unref();
323     if ( ents ) g_free(ents);
325     g_object_unref(fontServer);
326 #ifdef USE_PANGO_WIN32
327     pango_win32_shutdown_display();
328 #else
329     //pango_ft2_shutdown_display();
330 #endif
331     //g_object_unref(fontContext);
332     
333     // Delete the pango font pointers in the string to instance map
334     PangoStringToDescrMap::iterator it = fontInstanceMap.begin();
335     while (it != fontInstanceMap.end()) {
336         pango_font_description_free((*it).second);
337         it++;
338     }
342 Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *font)
344     Glib::ustring pangoString;
345     
346     g_assert(font);
347     
348     if (font) {
349         // Once the format for the font specification is decided, it must be
350         // kept.. if it is absolutely necessary to change it, the attribute
351         // it is written to needs to have a new version so the legacy files
352         // can be read.
353         
354         PangoFontDescription *copy = pango_font_description_copy(font);
355         
356         pango_font_description_unset_fields (copy, PANGO_FONT_MASK_SIZE);
357         pangoString = Glib::ustring(pango_font_description_to_string(copy));
358         
359         pango_font_description_free(copy);
360         
361     }
362     
363     return pangoString;
366 Glib::ustring font_factory::ConstructFontSpecification(font_instance *font)
368     Glib::ustring pangoString;
369     
370     g_assert(font);
371     
372     if (font) {
373         pangoString = ConstructFontSpecification(font->descr);
374     }
375     
376     return pangoString;
379 Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr)
381     Glib::ustring family;
382     
383     g_assert(fontDescr);
384     
385     if (fontDescr) {
386         // For now, keep it as family name taken from pango
387         family = pango_font_description_get_family(fontDescr);
388     }
389     
390     return family;
393 Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDescr)
395     Glib::ustring style;
396     
397     g_assert(fontDescr);
398     
399     if (fontDescr) {
400         PangoFontDescription *fontDescrCopy = pango_font_description_copy(fontDescr);
401         
402         pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY);
403         pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE);
404         
405         // For now, keep it as style name taken from pango
406         style = pango_font_description_to_string(fontDescrCopy);
407         
408         pango_font_description_free(fontDescrCopy);
409     }
410     
411     return style; 
414 Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily)
416     Glib::ustring newFontSpec;
417     
418     // Although we are using the string from pango_font_description_to_string for the
419     // font specification, we definitely cannot just set the new family in the
420     // PangoFontDescription structure and ask for a new string.  This is because
421     // what constitutes a "family" in our own UI may be different from how Pango
422     // sees it.
423     
424     // Find the PangoFontDescription associated to this fontSpec
425     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
426     
427     if (it != fontInstanceMap.end()) {
428         PangoFontDescription *descr = pango_font_description_copy((*it).second);
429         
430         // Grab the UI Family string from the descr
431         Glib::ustring uiFamily = GetUIFamilyString(descr);
432         
433         // Replace the UI Family name with the new family name
434         std::size_t found = fontSpec.find(uiFamily);
435         if (found != Glib::ustring::npos) {
436             newFontSpec = fontSpec;
437             newFontSpec.erase(found, uiFamily.size());
438             newFontSpec.insert(found, newFamily);
439             
440             // If the new font specification does not exist in the reference maps,
441             // search for the next best match for the faces in that style 
442             it = fontInstanceMap.find(newFontSpec);
443             if (it == fontInstanceMap.end()) {
444                 
445                 PangoFontDescription *newFontDescr = pango_font_description_from_string(newFontSpec.c_str());
446                 
447                 PangoFontDescription *bestMatchForNewDescr = NULL;
448                 Glib::ustring bestMatchFontDescription;
449                 
450                 bool setFirstFamilyMatch = false;
451                 for (it = fontInstanceMap.begin(); it != fontInstanceMap.end(); it++) {
452                     
453                     Glib::ustring currentFontSpec = (*it).first;
454                     
455                     // Save some time by only looking at the right family
456                     if (currentFontSpec.find(newFamily) != Glib::ustring::npos) {
457                         if (!setFirstFamilyMatch) {
458                                 // This ensures that the closest match is at least within the correct
459                                 // family rather than the first font in the list
460                             bestMatchForNewDescr = pango_font_description_copy((*it).second);
461                             bestMatchFontDescription = currentFontSpec;
462                             setFirstFamilyMatch = true;
463                         } else {
464                             // Get the font description that corresponds, and
465                             // then see if we've found a better match
466                             PangoFontDescription *possibleMatch = pango_font_description_copy((*it).second);
467                             
468                             if (pango_font_description_better_match(
469                                     newFontDescr, bestMatchForNewDescr, possibleMatch)) {
470                                 
471                                 pango_font_description_free(bestMatchForNewDescr);
472                                 bestMatchForNewDescr = possibleMatch;
473                                 bestMatchFontDescription = currentFontSpec;
474                             } else {
475                                 pango_font_description_free(possibleMatch);
476                             }
477                         }
478                     }
479                 }
480                 
481                 newFontSpec = bestMatchFontDescription;
482                 
483                 pango_font_description_free(newFontDescr);
484                 pango_font_description_free(bestMatchForNewDescr);
485             }
486         }
487         
488         pango_font_description_free(descr);
489     }
490     
491     return newFontSpec;
494 Glib::ustring font_factory::FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn)
496     Glib::ustring newFontSpec;
497     
498     // Find the PangoFontDesecription that goes with this font specification string
499     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
500     
501     if (it != fontInstanceMap.end()) {
502         // If we did find one, make a copy and set/unset the italic as needed
503         PangoFontDescription *descr = pango_font_description_copy((*it).second);
504         
505         PangoStyle style;
506         if (turnOn) {
507             style = PANGO_STYLE_ITALIC;
508         } else {
509             style = PANGO_STYLE_NORMAL;
510         }
511         pango_font_description_set_style(descr, style);
512         
513         newFontSpec = ConstructFontSpecification(descr);
514         if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
515             // If the new font does not have an italic face, don't
516             // allow italics to be set!
517             newFontSpec = fontSpec;
518         }
519         
520         pango_font_description_free(descr);
521     }
522     
523     return newFontSpec;    
526 Glib::ustring font_factory::FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn)
528     Glib::ustring newFontSpec;
529     
530     // Find the PangoFontDesecription that goes with this font specification string
531     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
532     
533     if (it != fontInstanceMap.end()) {
534         // If we did find one, make a copy and set/unset the bold as needed
535         PangoFontDescription *descr = pango_font_description_copy((*it).second);
536         
537         PangoWeight weight;
538         if (turnOn) {
539             weight = PANGO_WEIGHT_BOLD;
540         } else {
541             weight = PANGO_WEIGHT_NORMAL;
542         }
543         pango_font_description_set_weight(descr, weight);
544         
545         newFontSpec = ConstructFontSpecification(descr);
546         if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
547             // If the new font does not have a bold face, don't
548             // allow bold to be set!
549             newFontSpec = fontSpec;
550         }
551         
552         pango_font_description_free(descr);
553     }
554     
555     return newFontSpec;  
558 /////
560 static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2)
562     return (style_name_compare(style1.c_str(), style2.c_str()) < 0);
565 void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
567     g_assert(map);
568     
569     if (map) {
570         
571         // Gather the family names as listed by Pango
572         PangoFontFamily**  families = NULL;
573         int numFamilies = 0;
574         pango_font_map_list_families(fontServer, &families, &numFamilies);
575            
576         for (int currentFamily=0; currentFamily < numFamilies; currentFamily++) {
577             
578             // Gather the styles for this family
579             PangoFontFace** faces = NULL;
580             int numFaces = 0;
581             pango_font_family_list_faces(families[currentFamily], &faces, &numFaces);
582             
583             for (int currentFace=0; currentFace < numFaces; currentFace++) {
584                 
585                 // If the face has a name, describe it, and then use the 
586                 // description to get the UI family and face strings
587                 
588                 if (pango_font_face_get_face_name(faces[currentFace]) == NULL) {
589                     continue;
590                 }
591                 
592                 PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]);
593                 if (faceDescr) {
594                     Glib::ustring familyUIName = GetUIFamilyString(faceDescr);
595                     Glib::ustring styleUIName = GetUIStyleString(faceDescr);
596                     
597                     if (!familyUIName.empty() && !styleUIName.empty()) {
598                         // Find the right place to put the style information, adding
599                         // a map entry for the family name if it doesn't yet exist
600                         
601                         FamilyToStylesMap::iterator iter = map->find(familyUIName);
602                         
603                         if (iter == map->end()) {
604                             map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>()));
605                         }
606                         
607                         // Insert into the style list and save the info in the reference maps
608                         // only if the style does not yet exist
609                         
610                         bool exists = false;
611                         std::list<Glib::ustring> &styleList = (*map)[familyUIName];
612                         
613                         for (std::list<Glib::ustring>::iterator it=styleList.begin();
614                                  it != styleList.end();
615                                  it++) {
616                             if (*it == styleUIName) {
617                                 exists = true;
618                                 break;
619                             }
620                         }
621                         
622                         if (!exists) {
623                             styleList.push_back(styleUIName);
624                             
625                             // Add the string info needed in the reference maps
626                             fontStringMap.insert(
627                                     std::make_pair(
628                                             Glib::ustring(familyUIName) + Glib::ustring(styleUIName),
629                                             ConstructFontSpecification(faceDescr)));
630                             fontInstanceMap.insert(
631                                     std::make_pair(ConstructFontSpecification(faceDescr), faceDescr));
632                         } else {
633                             pango_font_description_free(faceDescr);
634                         }
635                     } else {
636                         pango_font_description_free(faceDescr);
637                     }
638                 }
639             }
640         }
641        
642         // Sort the style lists
643         for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); iter++) {
644             (*iter).second.sort(StyleNameCompareInternal);
645         }
646     }
649 font_instance* font_factory::FaceFromStyle(SPStyle const *style)
651     font_instance *font = NULL;
652     
653     g_assert(style);
654     
655     if (style) {
656         //  First try to use the font specification if it is set
657         if (style->text->font_specification.set
658             && style->text->font_specification.value
659             && *style->text->font_specification.value) {
660             
661             font = FaceFromFontSpecification(style->text->font_specification.value);
662         }
663         
664         // If that failed, try using the CSS information in the style
665         if (!font) {
666             font = Face(style->text->font_family.value, font_style_to_pos(*style));
667         }
668     }
669     
670     return font;
673 font_instance *font_factory::FaceFromDescr(char const *family, char const *style)
675     PangoFontDescription *temp_descr = pango_font_description_from_string(style);
676     pango_font_description_set_family(temp_descr,family);
677     font_instance *res = Face(temp_descr);
678     pango_font_description_free(temp_descr);
679     return res;
682 font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle)
684     font_instance *fontInstance = NULL;
685     
686     g_assert(uiFamily && uiStyle);
687     if (uiFamily && uiStyle) {
688         Glib::ustring uiString = Glib::ustring(uiFamily) + Glib::ustring(uiStyle);
689         
690         UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString);
691         
692         if (uiToPangoIter != fontStringMap.end ()) {
693             PangoStringToDescrMap::iterator pangoToDescrIter = fontInstanceMap.find((*uiToPangoIter).second);
694             if (pangoToDescrIter != fontInstanceMap.end()) {
695                 // We found the pango description - now we can make a font_instance
696                 PangoFontDescription *tempDescr = pango_font_description_copy((*pangoToDescrIter).second);
697                 fontInstance = Face(tempDescr);
698                 pango_font_description_free(tempDescr);
699             }
700         }
701     }
702     
703     return fontInstance;
706 font_instance* font_factory::FaceFromPangoString(char const *pangoString)
708     font_instance *fontInstance = NULL;
709         
710     g_assert(pangoString);
711     
712     if (pangoString) {
713         PangoFontDescription *descr = NULL;
714          
715         // First attempt to find the font specification in the reference map
716         PangoStringToDescrMap::iterator it = fontInstanceMap.find(Glib::ustring(pangoString));
717         if (it != fontInstanceMap.end()) {
718             descr = pango_font_description_copy((*it).second);
719         }
720          
721         // Or create a font description from the string - this may fail or
722         // produce unexpected results if the string does not have a good format
723         if (!descr) {
724             descr = pango_font_description_from_string(pangoString);
725         }
726         
727         if (descr && (pango_font_description_get_family(descr) != NULL)) {
728             fontInstance = Face(descr);
729         }
730         
731         if (descr) {
732             pango_font_description_free(descr);
733         }
734     }
735      
736     return fontInstance;
739 font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecification)
741     font_instance *font = NULL;
742     
743     g_assert(fontSpecification);
744     
745     if (fontSpecification) {
746         // How the string is used to reconstruct a font depends on how it
747         // was constructed in ConstructFontSpecification.  As it stands,
748         // the font specification is a pango-created string
749         font = FaceFromPangoString(fontSpecification);
750     }
751     
752     return font;
757 font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
759 #ifdef USE_PANGO_WIN32
760     // damn Pango fudges the size, so we need to unfudge. See source of pango_win32_font_map_init()
761     pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE*72/GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY))); // mandatory huge size (hinting workaround)
762 #else
763     pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE)); // mandatory huge size (hinting workaround)
764 #endif
765         
766     font_instance *res = NULL;
767         
768     if ( loadedFaces.find(descr) == loadedFaces.end() ) {
769         // not yet loaded
770         PangoFont *nFace = NULL;
772         // workaround for bug #1025565.
773         // fonts without families blow up Pango.
774         if (pango_font_description_get_family(descr) != NULL) {
775             nFace = pango_font_map_load_font(fontServer,fontContext,descr);
776         }
777         else {
778             g_warning(_("Ignoring font without family that will crash Pango"));
779         }
781         if ( nFace ) {
782             // duplicate FcPattern, the hard way
783             res = new font_instance();
784             // store the descr of the font we asked for, since this is the key where we intend to put the font_instance at
785             // in the hash_map.  the descr of the returned pangofont may differ from what was asked, so we don't know (at this 
786             // point) whether loadedFaces[that_descr] is free or not (and overwriting an entry will bring deallocation problems)
787             res->descr = pango_font_description_copy(descr);
788             res->daddy = this;
789             res->InstallFace(nFace);
790             if ( res->pFont == NULL ) {
791                 // failed to install face -> bitmap font
792                 // printf("face failed\n");
793                 res->daddy = NULL;
794                 delete res;
795                 res = NULL;
796                 if ( canFail ) {
797                     char *tc = pango_font_description_to_string(descr);
798                     PANGO_DEBUG("falling back from %s to Sans because InstallFace failed\n",tc);
799                     g_free(tc);
800                     pango_font_description_set_family(descr,"Sans");
801                     res = Face(descr,false);
802                 }
803             } else {
804                 loadedFaces[res->descr]=res;
805                 res->Ref();
806                 AddInCache(res);
807             }
808         } else {
809             // no match
810             if ( canFail ) {
811                 PANGO_DEBUG("falling back to Sans\n");
812                 descr = pango_font_description_new();
813                 pango_font_description_set_family(descr,"Sans");
814                 res = Face(descr,false);
815                 pango_font_description_free(descr);
816             }
817         }
818     } else {
819         // already here
820         res = loadedFaces[descr];
821         res->Ref();
822         AddInCache(res);
823     }
824     res->InitTheFace();
825     return res;
828 font_instance *font_factory::Face(char const *family, int variant, int style, int weight, int stretch, int /*size*/, int /*spacing*/)
830     PangoFontDescription *temp_descr = pango_font_description_new();
831     pango_font_description_set_family(temp_descr,family);
832     pango_font_description_set_weight(temp_descr,(PangoWeight)weight);
833     pango_font_description_set_stretch(temp_descr,(PangoStretch)stretch);
834     pango_font_description_set_style(temp_descr,(PangoStyle)style);
835     pango_font_description_set_variant(temp_descr,(PangoVariant)variant);
836     font_instance *res = Face(temp_descr);
837     pango_font_description_free(temp_descr);
838     return res;
841 font_instance *font_factory::Face(char const *family, NRTypePosDef apos)
843     PangoFontDescription *temp_descr = pango_font_description_new();
844         
845     pango_font_description_set_family(temp_descr, family);
846         
847     if ( apos.variant == NR_POS_VARIANT_SMALLCAPS ) {
848         pango_font_description_set_variant(temp_descr, PANGO_VARIANT_SMALL_CAPS);
849     } else {
850         pango_font_description_set_variant(temp_descr, PANGO_VARIANT_NORMAL);
851     }
852         
853     if ( apos.italic ) {
854         pango_font_description_set_style(temp_descr, PANGO_STYLE_ITALIC);
855     } else if ( apos.oblique ) {
856         pango_font_description_set_style(temp_descr, PANGO_STYLE_OBLIQUE);
857     } else {
858         pango_font_description_set_style(temp_descr, PANGO_STYLE_NORMAL);
859     }
860         
861     if ( apos.weight <= NR_POS_WEIGHT_ULTRA_LIGHT ) {
862         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRALIGHT);
863     } else if ( apos.weight <= NR_POS_WEIGHT_LIGHT ) {
864         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_LIGHT);
865     } else if ( apos.weight <= NR_POS_WEIGHT_NORMAL ) {
866         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_NORMAL);
867     } else if ( apos.weight <= NR_POS_WEIGHT_BOLD ) {
868         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_BOLD);
869     } else if ( apos.weight <= NR_POS_WEIGHT_ULTRA_BOLD ) {
870         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRABOLD);
871     } else {
872         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_HEAVY);
873     }
874         
875     if ( apos.stretch <= NR_POS_STRETCH_ULTRA_CONDENSED ) {
876         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_CONDENSED);
877     } else if ( apos.stretch <= NR_POS_STRETCH_CONDENSED ) {
878         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_CONDENSED);
879     } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_CONDENSED ) {
880         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_CONDENSED);
881     } else if ( apos.stretch <= NR_POS_WEIGHT_NORMAL ) {
882         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_NORMAL);
883     } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_EXPANDED ) {
884         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_EXPANDED);
885     } else if ( apos.stretch <= NR_POS_STRETCH_EXPANDED ) {
886         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXPANDED);
887     } else {
888         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_EXPANDED);
889     }
890         
891     font_instance *res = Face(temp_descr);
892     pango_font_description_free(temp_descr);
893     return res;
896 void font_factory::UnrefFace(font_instance *who)
898     if ( who == NULL ) return;
899     if ( loadedFaces.find(who->descr) == loadedFaces.end() ) {
900         // not found
901         char *tc = pango_font_description_to_string(who->descr);
902         g_warning("unrefFace %p=%s: failed\n",who,tc);
903         g_free(tc);
904     } else {
905         loadedFaces.erase(loadedFaces.find(who->descr));
906         //                      printf("unrefFace %p: success\n",who);
907     }
910 void font_factory::AddInCache(font_instance *who)
912     if ( who == NULL ) return;
913     for (int i = 0;i < nbEnt;i++) ents[i].age *= 0.9;
914     for (int i = 0;i < nbEnt;i++) {
915         if ( ents[i].f == who ) {
916             //                  printf("present\n");
917             ents[i].age += 1.0;
918             return;
919         }
920     }
921     if ( nbEnt > maxEnt ) {
922         printf("cache sur-plein?\n");
923         return;
924     }
925     who->Ref();
926     if ( nbEnt == maxEnt ) {
927         int    bi = 0;
928         double ba = ents[bi].age;
929         for (int i = 1;i < nbEnt;i++) {
930             if ( ents[i].age < ba ) {
931                 bi = i;
932                 ba = ents[bi].age;
933             }
934         }
935         ents[bi].f->Unref();
936         ents[bi]=ents[--nbEnt];
937     }
938     ents[nbEnt].f = who;
939     ents[nbEnt].age = 1.0;
940     nbEnt++;
944 /*
945   Local Variables:
946   mode:c++
947   c-file-style:"stroustrup"
948   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
949   indent-tabs-mode:nil
950   fill-column:99
951   End:
952 */
953 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :