Code

a63f70d758819033586bc66dd0237501519ef7ec
[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>
29 #include <tr1/unordered_map>
32 typedef std::tr1::unordered_map<PangoFontDescription*, font_instance*, font_descr_hash, font_descr_equal> FaceMapType;
34 // need to avoid using the size field
35 size_t font_descr_hash::operator()( PangoFontDescription *const &x) const {
36     int h = 0;
37     h *= 1128467;
38     char const *theF = pango_font_description_get_family(x);
39     h += (theF)?g_str_hash(theF):0;
40     h *= 1128467;
41     h += (int)pango_font_description_get_style(x);
42     h *= 1128467;
43     h += (int)pango_font_description_get_variant(x);
44     h *= 1128467;
45     h += (int)pango_font_description_get_weight(x);
46     h *= 1128467;
47     h += (int)pango_font_description_get_stretch(x);
48     return h;
49 }
50 bool  font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDescription *const &b) const {
51     //if ( pango_font_description_equal(a,b) ) return true;
52     char const *fa = pango_font_description_get_family(a);
53     char const *fb = pango_font_description_get_family(b);
54     if ( ( fa && fb == NULL ) || ( fb && fa == NULL ) ) return false;
55     if ( fa && fb && strcmp(fa,fb) != 0 ) return false;
56     if ( pango_font_description_get_style(a) != pango_font_description_get_style(b) ) return false;
57     if ( pango_font_description_get_variant(a) != pango_font_description_get_variant(b) ) return false;
58     if ( pango_font_description_get_weight(a) != pango_font_description_get_weight(b) ) return false;
59     if ( pango_font_description_get_stretch(a) != pango_font_description_get_stretch(b) ) return false;
60     return true;
61 }
63 /////////////////// helper functions
65 /**
66  * A wrapper for strcasestr that also provides an implementation for Win32.
67  */
68 static bool
69 ink_strstr(char const *haystack, char const *pneedle)
70 {
71     // windows has no strcasestr implementation, so here is ours...
72     // stolen from nmap
73     /* FIXME: This is broken for e.g. ink_strstr("aab", "ab").  Report to nmap.
74      *
75      * Also, suggest use of g_ascii_todown instead of buffer stuff, and g_ascii_tolower instead
76      * of tolower.  Given that haystack is a font name (i.e. fairly short), it should be ok to
77      * do g_ascii_strdown on both haystack and pneedle, and do normal strstr.
78      *
79      * Rather than fixing in inkscape, consider getting rid of this routine, instead using
80      * strdown and plain strstr at caller.  We have control over the needle values, so we can
81      * modify the callers rather than calling strdown there.
82      */
83     char buf[512];
84     register char const *p;
85     char *needle, *q, *foundto;
86     if (!*pneedle) return true;
87     if (!haystack) return false;
89     needle = buf;
90     p = pneedle; q = needle;
91     while ((*q++ = tolower(*p++)))
92         ;
93     p = haystack - 1; foundto = needle;
94     while (*++p) {
95         if (tolower(*p) == *foundto) {
96             if (!*++foundto) {
97                 /* Yeah, we found it */
98                 return true;
99             }
100         } else foundto = needle;
101     }
102     return false;
105 /**
106  * Regular fonts are 'Regular', 'Roman', 'Normal', or 'Plain'
107  */
108 // FIXME: make this UTF8, add non-English style names
109 static bool
110 is_regular(char const *s)
112     if (ink_strstr(s, "Regular")) return true;
113     if (ink_strstr(s, "Roman")) return true;
114     if (ink_strstr(s, "Normal")) return true;
115     if (ink_strstr(s, "Plain")) return true;
116     return false;
119 /**
120  * Non-bold fonts are 'Medium' or 'Book'
121  */
122 static bool
123 is_nonbold(char const *s)
125     if (ink_strstr(s, "Medium")) return true;
126     if (ink_strstr(s, "Book")) return true;
127     return false;
130 /**
131  * Italic fonts are 'Italic', 'Oblique', or 'Slanted'
132  */
133 static bool
134 is_italic(char const *s)
136     if (ink_strstr(s, "Italic")) return true;
137     if (ink_strstr(s, "Oblique")) return true;
138     if (ink_strstr(s, "Slanted")) return true;
139     return false;
142 /**
143  * Bold fonts are 'Bold'
144  */
145 static bool
146 is_bold(char const *s)
148     if (ink_strstr(s, "Bold")) return true;
149     return false;
152 /**
153  * Caps fonts are 'Caps'
154  */
155 static bool
156 is_caps(char const *s)
158     if (ink_strstr(s, "Caps")) return true;
159     return false;
162 #if 0 /* FIXME: These are all unused.  Please delete them or use them (presumably in
163 * style_name_compare). */
164 /**
165  * Monospaced fonts are 'Mono'
166  */
167 static bool
168 is_mono(char const *s)
170     if (ink_strstr(s, "Mono")) return true;
171     return false;
174 /**
175  * Rounded fonts are 'Round'
176  */
177 static bool
178 is_round(char const *s)
180     if (ink_strstr(s, "Round")) return true;
181     return false;
184 /**
185  * Outline fonts are 'Outline'
186  */
187 static bool
188 is_outline(char const *s)
190     if (ink_strstr(s, "Outline")) return true;
191     return false;
194 /**
195  * Swash fonts are 'Swash'
196  */
197 static bool
198 is_swash(char const *s)
200     if (ink_strstr(s, "Swash")) return true;
201     return false;
203 #endif
205 /**
206  * Determines if two style names match.  This allows us to match
207  * based on the type of style rather than simply doing string matching,
208  * because for instance 'Plain' and 'Normal' mean the same thing.
209  *
210  * Q:  Shouldn't this include the other tests such as is_outline, etc.?
211  * Q:  Is there a problem with strcasecmp on Win32?  Should it use stricmp?
212  */
213 int
214 style_name_compare(char const *aa, char const *bb)
216     char const *a = (char const *) aa;
217     char const *b = (char const *) bb;
219     if (is_regular(a) && !is_regular(b)) return -1;
220     if (is_regular(b) && !is_regular(a)) return 1;
222     if (is_bold(a) && !is_bold(b)) return 1;
223     if (is_bold(b) && !is_bold(a)) return -1;
225     if (is_italic(a) && !is_italic(b)) return 1;
226     if (is_italic(b) && !is_italic(a)) return -1;
228     if (is_nonbold(a) && !is_nonbold(b)) return 1;
229     if (is_nonbold(b) && !is_nonbold(a)) return -1;
231     if (is_caps(a) && !is_caps(b)) return 1;
232     if (is_caps(b) && !is_caps(a)) return -1;
234     return strcasecmp(a, b);
237 /*
238  defined but not used:
240 static int
241 style_record_compare(void const *aa, void const *bb)
243     NRStyleRecord const *a = (NRStyleRecord const *) aa;
244     NRStyleRecord const *b = (NRStyleRecord const *) bb;
246     return (style_name_compare(a->name, b->name));
249 static void font_factory_name_list_destructor(NRNameList *list)
251     for (unsigned int i = 0; i < list->length; i++)
252         g_free(list->names[i]);
253     if ( list->names ) g_free(list->names);
256 static void font_factory_style_list_destructor(NRStyleList *list)
258     for (unsigned int i = 0; i < list->length; i++) {
259         g_free((void *) (list->records)[i].name);
260         g_free((void *) (list->records)[i].descr);
261     }
262     if ( list->records ) g_free(list->records);
264 */
266 /**
267  * On Win32 performs a stricmp(a,b), otherwise does a strcasecmp(a,b)
268  */
269 int
270 family_name_compare(char const *a, char const *b)
272 #ifndef WIN32
273     return strcasecmp((*((char const **) a)), (*((char const **) b)));
274 #else
275     return stricmp((*((char const **) a)), (*((char const **) b)));
276 #endif
279 void noop(...) {}
280 //#define PANGO_DEBUG g_print
281 #define PANGO_DEBUG noop
285 ///////////////////// FontFactory
286 #ifndef USE_PANGO_WIN32
287 // the substitute function to tell fontconfig to enforce outline fonts
288 void FactorySubstituteFunc(FcPattern *pattern,gpointer /*data*/)
290     FcPatternAddBool(pattern, "FC_OUTLINE",FcTrue);
291     //char *fam = NULL;
292     //FcPatternGetString(pattern, "FC_FAMILY",0, &fam);
293     //printf("subst_f on %s\n",fam);
295 #endif
298 font_factory *font_factory::lUsine = NULL;
300 font_factory *font_factory::Default(void)
302     if ( lUsine == NULL ) lUsine = new font_factory;
303     return lUsine;
306 font_factory::font_factory(void) :
307     nbEnt(0),
308     maxEnt(32),
309     ents(static_cast<font_entry*>(g_malloc(maxEnt*sizeof(font_entry)))),
311 #ifdef USE_PANGO_WIN32
312     fontServer(pango_win32_font_map_for_display()),
313     fontContext(pango_win32_get_context()),
314     pangoFontCache(pango_win32_font_map_get_font_cache(fontServer)),
315     hScreenDC(pango_win32_get_dc()),
316 #else
317     fontServer(pango_ft2_font_map_new()),
318     fontContext(0),
319 #endif
320     fontSize(512),
321     loadedPtr(new FaceMapType())
323 #ifdef USE_PANGO_WIN32
324 #else
325     pango_ft2_font_map_set_resolution((PangoFT2FontMap*)fontServer, 72, 72);
326     fontContext = pango_ft2_font_map_create_context((PangoFT2FontMap*)fontServer);
327     pango_ft2_font_map_set_default_substitute((PangoFT2FontMap*)fontServer,FactorySubstituteFunc,this,NULL);
328 #endif
331 font_factory::~font_factory(void)
333     if (loadedPtr) {
334         FaceMapType* tmp = static_cast<FaceMapType*>(loadedPtr);
335         loadedPtr = 0;
336     }
338     for (int i = 0;i < nbEnt;i++) ents[i].f->Unref();
339     if ( ents ) g_free(ents);
341     g_object_unref(fontServer);
342 #ifdef USE_PANGO_WIN32
343     pango_win32_shutdown_display();
344 #else
345     //pango_ft2_shutdown_display();
346 #endif
347     //g_object_unref(fontContext);
349     // Delete the pango font pointers in the string to instance map
350     PangoStringToDescrMap::iterator it = fontInstanceMap.begin();
351     while (it != fontInstanceMap.end()) {
352         pango_font_description_free((*it).second);
353         it++;
354     }
358 Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *font)
360     Glib::ustring pangoString;
362     g_assert(font);
364     if (font) {
365         // Once the format for the font specification is decided, it must be
366         // kept.. if it is absolutely necessary to change it, the attribute
367         // it is written to needs to have a new version so the legacy files
368         // can be read.
370         PangoFontDescription *copy = pango_font_description_copy(font);
372         pango_font_description_unset_fields (copy, PANGO_FONT_MASK_SIZE);
373         pangoString = Glib::ustring(pango_font_description_to_string(copy));
375         pango_font_description_free(copy);
377     }
379     return pangoString;
382 Glib::ustring font_factory::ConstructFontSpecification(font_instance *font)
384     Glib::ustring pangoString;
386     g_assert(font);
388     if (font) {
389         pangoString = ConstructFontSpecification(font->descr);
390     }
392     return pangoString;
395 Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr)
397     Glib::ustring family;
399     g_assert(fontDescr);
401     if (fontDescr) {
402         // For now, keep it as family name taken from pango
403         family = pango_font_description_get_family(fontDescr);
404     }
406     return family;
409 Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDescr)
411     Glib::ustring style;
413     g_assert(fontDescr);
415     if (fontDescr) {
416         PangoFontDescription *fontDescrCopy = pango_font_description_copy(fontDescr);
418         pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY);
419         pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE);
421         // For now, keep it as style name taken from pango
422         style = pango_font_description_to_string(fontDescrCopy);
424         pango_font_description_free(fontDescrCopy);
425     }
427     return style;
430 Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily)
432     Glib::ustring newFontSpec;
434     // Although we are using the string from pango_font_description_to_string for the
435     // font specification, we definitely cannot just set the new family in the
436     // PangoFontDescription structure and ask for a new string.  This is because
437     // what constitutes a "family" in our own UI may be different from how Pango
438     // sees it.
440     // Find the PangoFontDescription associated to this fontSpec
441     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
443     if (it != fontInstanceMap.end()) {
444         PangoFontDescription *descr = pango_font_description_copy((*it).second);
446         // Grab the UI Family string from the descr
447         Glib::ustring uiFamily = GetUIFamilyString(descr);
449         // Replace the UI Family name with the new family name
450         std::size_t found = fontSpec.find(uiFamily);
451         if (found != Glib::ustring::npos) {
452             newFontSpec = fontSpec;
453             newFontSpec.erase(found, uiFamily.size());
454             newFontSpec.insert(found, newFamily);
456             // If the new font specification does not exist in the reference maps,
457             // search for the next best match for the faces in that style
458             it = fontInstanceMap.find(newFontSpec);
459             if (it == fontInstanceMap.end()) {
461                 PangoFontDescription *newFontDescr = pango_font_description_from_string(newFontSpec.c_str());
463                 PangoFontDescription *bestMatchForNewDescr = NULL;
464                 Glib::ustring bestMatchFontDescription;
466                 bool setFirstFamilyMatch = false;
467                 for (it = fontInstanceMap.begin(); it != fontInstanceMap.end(); it++) {
469                     Glib::ustring currentFontSpec = (*it).first;
471                     // Save some time by only looking at the right family
472                     if (currentFontSpec.find(newFamily) != Glib::ustring::npos) {
473                         if (!setFirstFamilyMatch) {
474                                 // This ensures that the closest match is at least within the correct
475                                 // family rather than the first font in the list
476                             bestMatchForNewDescr = pango_font_description_copy((*it).second);
477                             bestMatchFontDescription = currentFontSpec;
478                             setFirstFamilyMatch = true;
479                         } else {
480                             // Get the font description that corresponds, and
481                             // then see if we've found a better match
482                             PangoFontDescription *possibleMatch = pango_font_description_copy((*it).second);
484                             if (pango_font_description_better_match(
485                                     newFontDescr, bestMatchForNewDescr, possibleMatch)) {
487                                 pango_font_description_free(bestMatchForNewDescr);
488                                 bestMatchForNewDescr = possibleMatch;
489                                 bestMatchFontDescription = currentFontSpec;
490                             } else {
491                                 pango_font_description_free(possibleMatch);
492                             }
493                         }
494                     }
495                 }
497                 newFontSpec = bestMatchFontDescription;
499                 pango_font_description_free(newFontDescr);
500                 pango_font_description_free(bestMatchForNewDescr);
501             }
502         }
504         pango_font_description_free(descr);
505     }
507     return newFontSpec;
510 /**
511     apply style property to the given font
512     @param fontSpec the given font
513     @param turnOn true to set italic style
514     @return the changed fontspec, if the property can not be set return an empty string
515 */
516 Glib::ustring font_factory::FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn)
518     Glib::ustring newFontSpec;
520     // Find the PangoFontDesecription that goes with this font specification string
521     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
523     if (it != fontInstanceMap.end()) {
524         // If we did find one, make a copy and set/unset the italic as needed
525         PangoFontDescription *descr = pango_font_description_copy((*it).second);
527         PangoStyle style;
528         if (turnOn) {
529             style = PANGO_STYLE_ITALIC;
530         } else {
531             style = PANGO_STYLE_NORMAL;
532         }
533         pango_font_description_set_style(descr, style);
535         newFontSpec = ConstructFontSpecification(descr);
536         if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
537             if(turnOn) {
538                 // there is no PANGO_STYLE_ITALIC let's test for PANGO_STYLE_OBLIQUE
539                 style = PANGO_STYLE_OBLIQUE;
540                 pango_font_description_set_style(descr, style);
542                 newFontSpec = ConstructFontSpecification(descr);
543                 if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
544                     // If the new font does not have even an oblique face, don't
545                     // allow italics to be set!
546                     newFontSpec = Glib::ustring("");
547                 }
549             } else {
550                 // If the new font does not have an italic face, don't
551                 // allow italics to be set!
552                 newFontSpec = Glib::ustring("");
553             }
554         }
556         pango_font_description_free(descr);
557     }
559     return newFontSpec;
562 /**
563     apply width property to the given font
564     @param fontSpec the given font
565     @param turnOn true to set bold
566     @return the changed fontspec, if the property can not be set return an empty string
567 */
568 Glib::ustring font_factory::FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn)
570     Glib::ustring newFontSpec;
572     // Find the PangoFontDesecription that goes with this font specification string
573     PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
575     if (it != fontInstanceMap.end()) {
576         // If we did find one, make a copy and set/unset the bold as needed
577         PangoFontDescription *descr = pango_font_description_copy((*it).second);
579         PangoWeight weight;
580         if (turnOn) {
581             weight = PANGO_WEIGHT_BOLD;
582         } else {
583             weight = PANGO_WEIGHT_NORMAL;
584         }
585         pango_font_description_set_weight(descr, weight);
587         newFontSpec = ConstructFontSpecification(descr);
588         if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
589             // If the new font does not have a bold face, don't
590             // allow bold to be set!
591             newFontSpec = Glib::ustring("");
592         }
594         pango_font_description_free(descr);
595     }
597     return newFontSpec;
600 /////
602 static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2)
604     return (style_name_compare(style1.c_str(), style2.c_str()) < 0);
607 void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
609     g_assert(map);
611     if (map) {
613         // Gather the family names as listed by Pango
614         PangoFontFamily**  families = NULL;
615         int numFamilies = 0;
616         pango_font_map_list_families(fontServer, &families, &numFamilies);
618         for (int currentFamily=0; currentFamily < numFamilies; currentFamily++) {
620             // Gather the styles for this family
621             PangoFontFace** faces = NULL;
622             int numFaces = 0;
623             pango_font_family_list_faces(families[currentFamily], &faces, &numFaces);
625             for (int currentFace=0; currentFace < numFaces; currentFace++) {
627                 // If the face has a name, describe it, and then use the
628                 // description to get the UI family and face strings
630                 if (pango_font_face_get_face_name(faces[currentFace]) == NULL) {
631                     continue;
632                 }
634                 PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]);
635                 if (faceDescr) {
636                     Glib::ustring familyUIName = GetUIFamilyString(faceDescr);
637                     Glib::ustring styleUIName = GetUIStyleString(faceDescr);
639                     if (!familyUIName.empty() && !styleUIName.empty()) {
640                         // Find the right place to put the style information, adding
641                         // a map entry for the family name if it doesn't yet exist
643                         FamilyToStylesMap::iterator iter = map->find(familyUIName);
645                         if (iter == map->end()) {
646                             map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>()));
647                         }
649                         // Insert into the style list and save the info in the reference maps
650                         // only if the style does not yet exist
652                         bool exists = false;
653                         std::list<Glib::ustring> &styleList = (*map)[familyUIName];
655                         for (std::list<Glib::ustring>::iterator it=styleList.begin();
656                                  it != styleList.end();
657                                  it++) {
658                             if (*it == styleUIName) {
659                                 exists = true;
660                                 break;
661                             }
662                         }
664                         if (!exists) {
665                             styleList.push_back(styleUIName);
667                             // Add the string info needed in the reference maps
668                             fontStringMap.insert(
669                                     std::make_pair(
670                                             Glib::ustring(familyUIName) + Glib::ustring(styleUIName),
671                                             ConstructFontSpecification(faceDescr)));
672                             fontInstanceMap.insert(
673                                     std::make_pair(ConstructFontSpecification(faceDescr), faceDescr));
674                         } else {
675                             pango_font_description_free(faceDescr);
676                         }
677                     } else {
678                         pango_font_description_free(faceDescr);
679                     }
680                 }
681             }
682         }
684         // Sort the style lists
685         for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); iter++) {
686             (*iter).second.sort(StyleNameCompareInternal);
687         }
688     }
691 font_instance* font_factory::FaceFromStyle(SPStyle const *style)
693     font_instance *font = NULL;
695     g_assert(style);
697     if (style) {
698         //  First try to use the font specification if it is set
699         if (style->text->font_specification.set
700             && style->text->font_specification.value
701             && *style->text->font_specification.value) {
703             font = FaceFromFontSpecification(style->text->font_specification.value);
704         }
706         // If that failed, try using the CSS information in the style
707         if (!font) {
708             font = Face(style->text->font_family.value, font_style_to_pos(*style));
709         }
710     }
712     return font;
715 font_instance *font_factory::FaceFromDescr(char const *family, char const *style)
717     PangoFontDescription *temp_descr = pango_font_description_from_string(style);
718     pango_font_description_set_family(temp_descr,family);
719     font_instance *res = Face(temp_descr);
720     pango_font_description_free(temp_descr);
721     return res;
724 font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle)
726     font_instance *fontInstance = NULL;
728     g_assert(uiFamily && uiStyle);
729     if (uiFamily && uiStyle) {
730         Glib::ustring uiString = Glib::ustring(uiFamily) + Glib::ustring(uiStyle);
732         UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString);
734         if (uiToPangoIter != fontStringMap.end ()) {
735             PangoStringToDescrMap::iterator pangoToDescrIter = fontInstanceMap.find((*uiToPangoIter).second);
736             if (pangoToDescrIter != fontInstanceMap.end()) {
737                 // We found the pango description - now we can make a font_instance
738                 PangoFontDescription *tempDescr = pango_font_description_copy((*pangoToDescrIter).second);
739                 fontInstance = Face(tempDescr);
740                 pango_font_description_free(tempDescr);
741             }
742         }
743     }
745     return fontInstance;
748 font_instance* font_factory::FaceFromPangoString(char const *pangoString)
750     font_instance *fontInstance = NULL;
752     g_assert(pangoString);
754     if (pangoString) {
755         PangoFontDescription *descr = NULL;
757         // First attempt to find the font specification in the reference map
758         PangoStringToDescrMap::iterator it = fontInstanceMap.find(Glib::ustring(pangoString));
759         if (it != fontInstanceMap.end()) {
760             descr = pango_font_description_copy((*it).second);
761         }
763         // Or create a font description from the string - this may fail or
764         // produce unexpected results if the string does not have a good format
765         if (!descr) {
766             descr = pango_font_description_from_string(pangoString);
767         }
769         if (descr && (pango_font_description_get_family(descr) != NULL)) {
770             fontInstance = Face(descr);
771         }
773         if (descr) {
774             pango_font_description_free(descr);
775         }
776     }
778     return fontInstance;
781 font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecification)
783     font_instance *font = NULL;
785     g_assert(fontSpecification);
787     if (fontSpecification) {
788         // How the string is used to reconstruct a font depends on how it
789         // was constructed in ConstructFontSpecification.  As it stands,
790         // the font specification is a pango-created string
791         font = FaceFromPangoString(fontSpecification);
792     }
794     return font;
799 font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
801 #ifdef USE_PANGO_WIN32
802     // damn Pango fudges the size, so we need to unfudge. See source of pango_win32_font_map_init()
803     pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE*72/GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY))); // mandatory huge size (hinting workaround)
804 #else
805     pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE)); // mandatory huge size (hinting workaround)
806 #endif
808     font_instance *res = NULL;
810     FaceMapType& loadedFaces = *static_cast<FaceMapType*>(loadedPtr);
811     if ( loadedFaces.find(descr) == loadedFaces.end() ) {
812         // not yet loaded
813         PangoFont *nFace = NULL;
815         // workaround for bug #1025565.
816         // fonts without families blow up Pango.
817         if (pango_font_description_get_family(descr) != NULL) {
818             nFace = pango_font_map_load_font(fontServer,fontContext,descr);
819         }
820         else {
821             g_warning(_("Ignoring font without family that will crash Pango"));
822         }
824         if ( nFace ) {
825             // duplicate FcPattern, the hard way
826             res = new font_instance();
827             // store the descr of the font we asked for, since this is the key where we intend to put the font_instance at
828             // in the hash_map.  the descr of the returned pangofont may differ from what was asked, so we don't know (at this
829             // point) whether loadedFaces[that_descr] is free or not (and overwriting an entry will bring deallocation problems)
830             res->descr = pango_font_description_copy(descr);
831             res->daddy = this;
832             res->InstallFace(nFace);
833             if ( res->pFont == NULL ) {
834                 // failed to install face -> bitmap font
835                 // printf("face failed\n");
836                 res->daddy = NULL;
837                 delete res;
838                 res = NULL;
839                 if ( canFail ) {
840                     char *tc = pango_font_description_to_string(descr);
841                     PANGO_DEBUG("falling back from %s to Sans because InstallFace failed\n",tc);
842                     g_free(tc);
843                     pango_font_description_set_family(descr,"Sans");
844                     res = Face(descr,false);
845                 }
846             } else {
847                 loadedFaces[res->descr]=res;
848                 res->Ref();
849                 AddInCache(res);
850             }
851         } else {
852             // no match
853             if ( canFail ) {
854                 PANGO_DEBUG("falling back to Sans\n");
855                 descr = pango_font_description_new();
856                 pango_font_description_set_family(descr,"Sans");
857                 res = Face(descr,false);
858                 pango_font_description_free(descr);
859             }
860         }
861     } else {
862         // already here
863         res = loadedFaces[descr];
864         res->Ref();
865         AddInCache(res);
866     }
867     if (res) {
868         res->InitTheFace();
869     }
870     return res;
873 font_instance *font_factory::Face(char const *family, int variant, int style, int weight, int stretch, int /*size*/, int /*spacing*/)
875     PangoFontDescription *temp_descr = pango_font_description_new();
876     pango_font_description_set_family(temp_descr,family);
877     pango_font_description_set_weight(temp_descr,(PangoWeight)weight);
878     pango_font_description_set_stretch(temp_descr,(PangoStretch)stretch);
879     pango_font_description_set_style(temp_descr,(PangoStyle)style);
880     pango_font_description_set_variant(temp_descr,(PangoVariant)variant);
881     font_instance *res = Face(temp_descr);
882     pango_font_description_free(temp_descr);
883     return res;
886 font_instance *font_factory::Face(char const *family, NRTypePosDef apos)
888     PangoFontDescription *temp_descr = pango_font_description_new();
890     pango_font_description_set_family(temp_descr, family);
892     if ( apos.variant == NR_POS_VARIANT_SMALLCAPS ) {
893         pango_font_description_set_variant(temp_descr, PANGO_VARIANT_SMALL_CAPS);
894     } else {
895         pango_font_description_set_variant(temp_descr, PANGO_VARIANT_NORMAL);
896     }
898     if ( apos.italic ) {
899         pango_font_description_set_style(temp_descr, PANGO_STYLE_ITALIC);
900     } else if ( apos.oblique ) {
901         pango_font_description_set_style(temp_descr, PANGO_STYLE_OBLIQUE);
902     } else {
903         pango_font_description_set_style(temp_descr, PANGO_STYLE_NORMAL);
904     }
906     if ( apos.weight <= NR_POS_WEIGHT_ULTRA_LIGHT ) {
907         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRALIGHT);
908     } else if ( apos.weight <= NR_POS_WEIGHT_LIGHT ) {
909         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_LIGHT);
910     } else if ( apos.weight <= NR_POS_WEIGHT_NORMAL ) {
911         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_NORMAL);
912     } else if ( apos.weight <= NR_POS_WEIGHT_BOLD ) {
913         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_BOLD);
914     } else if ( apos.weight <= NR_POS_WEIGHT_ULTRA_BOLD ) {
915         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRABOLD);
916     } else {
917         pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_HEAVY);
918     }
920     if ( apos.stretch <= NR_POS_STRETCH_ULTRA_CONDENSED ) {
921         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_CONDENSED);
922     } else if ( apos.stretch <= NR_POS_STRETCH_CONDENSED ) {
923         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_CONDENSED);
924     } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_CONDENSED ) {
925         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_CONDENSED);
926     } else if ( apos.stretch <= NR_POS_WEIGHT_NORMAL ) {
927         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_NORMAL);
928     } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_EXPANDED ) {
929         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_EXPANDED);
930     } else if ( apos.stretch <= NR_POS_STRETCH_EXPANDED ) {
931         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXPANDED);
932     } else {
933         pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_EXPANDED);
934     }
936     font_instance *res = Face(temp_descr);
937     pango_font_description_free(temp_descr);
938     return res;
941 void font_factory::UnrefFace(font_instance *who)
943     if ( who ) {
944         FaceMapType& loadedFaces = *static_cast<FaceMapType*>(loadedPtr);
946         if ( loadedFaces.find(who->descr) == loadedFaces.end() ) {
947             // not found
948             char *tc = pango_font_description_to_string(who->descr);
949             g_warning("unrefFace %p=%s: failed\n",who,tc);
950             g_free(tc);
951         } else {
952             loadedFaces.erase(loadedFaces.find(who->descr));
953             //                  printf("unrefFace %p: success\n",who);
954         }
955     }
958 void font_factory::AddInCache(font_instance *who)
960     if ( who == NULL ) return;
961     for (int i = 0;i < nbEnt;i++) ents[i].age *= 0.9;
962     for (int i = 0;i < nbEnt;i++) {
963         if ( ents[i].f == who ) {
964             //                  printf("present\n");
965             ents[i].age += 1.0;
966             return;
967         }
968     }
969     if ( nbEnt > maxEnt ) {
970         printf("cache sur-plein?\n");
971         return;
972     }
973     who->Ref();
974     if ( nbEnt == maxEnt ) {
975         int    bi = 0;
976         double ba = ents[bi].age;
977         for (int i = 1;i < nbEnt;i++) {
978             if ( ents[i].age < ba ) {
979                 bi = i;
980                 ba = ents[bi].age;
981             }
982         }
983         ents[bi].f->Unref();
984         ents[bi]=ents[--nbEnt];
985     }
986     ents[nbEnt].f = who;
987     ents[nbEnt].age = 1.0;
988     nbEnt++;
992 /*
993   Local Variables:
994   mode:c++
995   c-file-style:"stroustrup"
996   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
997   indent-tabs-mode:nil
998   fill-column:99
999   End:
1000 */
1001 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :