Code

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