fec9316b98a7aa3e3493e0fd9ca77133aa5c02cd
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;
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)
107 {
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;
113 }
115 /**
116 * Non-bold fonts are 'Medium' or 'Book'
117 */
118 static bool
119 is_nonbold(char const *s)
120 {
121 if (ink_strstr(s, "Medium")) return true;
122 if (ink_strstr(s, "Book")) return true;
123 return false;
124 }
126 /**
127 * Italic fonts are 'Italic', 'Oblique', or 'Slanted'
128 */
129 static bool
130 is_italic(char const *s)
131 {
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;
136 }
138 /**
139 * Bold fonts are 'Bold'
140 */
141 static bool
142 is_bold(char const *s)
143 {
144 if (ink_strstr(s, "Bold")) return true;
145 return false;
146 }
148 /**
149 * Caps fonts are 'Caps'
150 */
151 static bool
152 is_caps(char const *s)
153 {
154 if (ink_strstr(s, "Caps")) return true;
155 return false;
156 }
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)
165 {
166 if (ink_strstr(s, "Mono")) return true;
167 return false;
168 }
170 /**
171 * Rounded fonts are 'Round'
172 */
173 static bool
174 is_round(char const *s)
175 {
176 if (ink_strstr(s, "Round")) return true;
177 return false;
178 }
180 /**
181 * Outline fonts are 'Outline'
182 */
183 static bool
184 is_outline(char const *s)
185 {
186 if (ink_strstr(s, "Outline")) return true;
187 return false;
188 }
190 /**
191 * Swash fonts are 'Swash'
192 */
193 static bool
194 is_swash(char const *s)
195 {
196 if (ink_strstr(s, "Swash")) return true;
197 return false;
198 }
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)
211 {
212 char const *a = (char const *) aa;
213 char const *b = (char const *) bb;
215 if (is_regular(a) && !is_regular(b)) return -1;
216 if (is_regular(b) && !is_regular(a)) return 1;
218 if (is_bold(a) && !is_bold(b)) return 1;
219 if (is_bold(b) && !is_bold(a)) return -1;
221 if (is_italic(a) && !is_italic(b)) return 1;
222 if (is_italic(b) && !is_italic(a)) return -1;
224 if (is_nonbold(a) && !is_nonbold(b)) return 1;
225 if (is_nonbold(b) && !is_nonbold(a)) return -1;
227 if (is_caps(a) && !is_caps(b)) return 1;
228 if (is_caps(b) && !is_caps(a)) return -1;
230 return strcasecmp(a, b);
231 }
233 /*
234 defined but not used:
236 static int
237 style_record_compare(void const *aa, void const *bb)
238 {
239 NRStyleRecord const *a = (NRStyleRecord const *) aa;
240 NRStyleRecord const *b = (NRStyleRecord const *) bb;
242 return (style_name_compare(a->name, b->name));
243 }
245 static void font_factory_name_list_destructor(NRNameList *list)
246 {
247 for (unsigned int i = 0; i < list->length; i++)
248 g_free(list->names[i]);
249 if ( list->names ) g_free(list->names);
250 }
252 static void font_factory_style_list_destructor(NRStyleList *list)
253 {
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);
259 }
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)
267 {
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
273 }
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*/)
285 {
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);
290 }
291 #endif
294 font_factory *font_factory::lUsine = NULL;
296 font_factory *font_factory::Default(void)
297 {
298 if ( lUsine == NULL ) lUsine = new font_factory;
299 return lUsine;
300 }
302 font_factory::font_factory(void)
303 {
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
320 }
322 font_factory::~font_factory(void)
323 {
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);
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 }
341 }
344 Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *font)
345 {
346 Glib::ustring pangoString;
348 g_assert(font);
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.
356 PangoFontDescription *copy = pango_font_description_copy(font);
358 pango_font_description_unset_fields (copy, PANGO_FONT_MASK_SIZE);
359 pangoString = Glib::ustring(pango_font_description_to_string(copy));
361 pango_font_description_free(copy);
363 }
365 return pangoString;
366 }
368 Glib::ustring font_factory::ConstructFontSpecification(font_instance *font)
369 {
370 Glib::ustring pangoString;
372 g_assert(font);
374 if (font) {
375 pangoString = ConstructFontSpecification(font->descr);
376 }
378 return pangoString;
379 }
381 Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr)
382 {
383 Glib::ustring family;
385 g_assert(fontDescr);
387 if (fontDescr) {
388 // For now, keep it as family name taken from pango
389 family = pango_font_description_get_family(fontDescr);
390 }
392 return family;
393 }
395 Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDescr)
396 {
397 Glib::ustring style;
399 g_assert(fontDescr);
401 if (fontDescr) {
402 PangoFontDescription *fontDescrCopy = pango_font_description_copy(fontDescr);
404 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_FAMILY);
405 pango_font_description_unset_fields(fontDescrCopy, PANGO_FONT_MASK_SIZE);
407 // For now, keep it as style name taken from pango
408 style = pango_font_description_to_string(fontDescrCopy);
410 pango_font_description_free(fontDescrCopy);
411 }
413 return style;
414 }
416 Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily)
417 {
418 Glib::ustring newFontSpec;
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.
426 // Find the PangoFontDescription associated to this fontSpec
427 PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
429 if (it != fontInstanceMap.end()) {
430 PangoFontDescription *descr = pango_font_description_copy((*it).second);
432 // Grab the UI Family string from the descr
433 Glib::ustring uiFamily = GetUIFamilyString(descr);
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);
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()) {
447 PangoFontDescription *newFontDescr = pango_font_description_from_string(newFontSpec.c_str());
449 PangoFontDescription *bestMatchForNewDescr = NULL;
450 Glib::ustring bestMatchFontDescription;
452 bool setFirstFamilyMatch = false;
453 for (it = fontInstanceMap.begin(); it != fontInstanceMap.end(); it++) {
455 Glib::ustring currentFontSpec = (*it).first;
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);
470 if (pango_font_description_better_match(
471 newFontDescr, bestMatchForNewDescr, possibleMatch)) {
473 pango_font_description_free(bestMatchForNewDescr);
474 bestMatchForNewDescr = possibleMatch;
475 bestMatchFontDescription = currentFontSpec;
476 } else {
477 pango_font_description_free(possibleMatch);
478 }
479 }
480 }
481 }
483 newFontSpec = bestMatchFontDescription;
485 pango_font_description_free(newFontDescr);
486 pango_font_description_free(bestMatchForNewDescr);
487 }
488 }
490 pango_font_description_free(descr);
491 }
493 return newFontSpec;
494 }
496 /**
497 apply style property to the given font
498 @param fontSpec the given font
499 @param turnOn true to set italic style
500 @return the changed fontspec, if the property can not be set return an empty string
501 */
502 Glib::ustring font_factory::FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn)
503 {
504 Glib::ustring newFontSpec;
506 // Find the PangoFontDesecription that goes with this font specification string
507 PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
509 if (it != fontInstanceMap.end()) {
510 // If we did find one, make a copy and set/unset the italic as needed
511 PangoFontDescription *descr = pango_font_description_copy((*it).second);
513 PangoStyle style;
514 if (turnOn) {
515 style = PANGO_STYLE_ITALIC;
516 } else {
517 style = PANGO_STYLE_NORMAL;
518 }
519 pango_font_description_set_style(descr, style);
521 newFontSpec = ConstructFontSpecification(descr);
522 if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
523 if(turnOn) {
524 // there is no PANGO_STYLE_ITALIC let's test for PANGO_STYLE_OBLIQUE
525 style = PANGO_STYLE_OBLIQUE;
526 pango_font_description_set_style(descr, style);
528 newFontSpec = ConstructFontSpecification(descr);
529 if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
530 // If the new font does not have even an oblique face, don't
531 // allow italics to be set!
532 newFontSpec = Glib::ustring("");
533 }
535 } else {
536 // If the new font does not have an italic face, don't
537 // allow italics to be set!
538 newFontSpec = Glib::ustring("");
539 }
540 }
542 pango_font_description_free(descr);
543 }
545 return newFontSpec;
546 }
548 /**
549 apply width property to the given font
550 @param fontSpec the given font
551 @param turnOn true to set bold
552 @return the changed fontspec, if the property can not be set return an empty string
553 */
554 Glib::ustring font_factory::FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn)
555 {
556 Glib::ustring newFontSpec;
558 // Find the PangoFontDesecription that goes with this font specification string
559 PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec);
561 if (it != fontInstanceMap.end()) {
562 // If we did find one, make a copy and set/unset the bold as needed
563 PangoFontDescription *descr = pango_font_description_copy((*it).second);
565 PangoWeight weight;
566 if (turnOn) {
567 weight = PANGO_WEIGHT_BOLD;
568 } else {
569 weight = PANGO_WEIGHT_NORMAL;
570 }
571 pango_font_description_set_weight(descr, weight);
573 newFontSpec = ConstructFontSpecification(descr);
574 if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) {
575 // If the new font does not have a bold face, don't
576 // allow bold to be set!
577 newFontSpec = Glib::ustring("");
578 }
580 pango_font_description_free(descr);
581 }
583 return newFontSpec;
584 }
586 /////
588 static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2)
589 {
590 return (style_name_compare(style1.c_str(), style2.c_str()) < 0);
591 }
593 void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
594 {
595 g_assert(map);
597 if (map) {
599 // Gather the family names as listed by Pango
600 PangoFontFamily** families = NULL;
601 int numFamilies = 0;
602 pango_font_map_list_families(fontServer, &families, &numFamilies);
604 for (int currentFamily=0; currentFamily < numFamilies; currentFamily++) {
606 // Gather the styles for this family
607 PangoFontFace** faces = NULL;
608 int numFaces = 0;
609 pango_font_family_list_faces(families[currentFamily], &faces, &numFaces);
611 for (int currentFace=0; currentFace < numFaces; currentFace++) {
613 // If the face has a name, describe it, and then use the
614 // description to get the UI family and face strings
616 if (pango_font_face_get_face_name(faces[currentFace]) == NULL) {
617 continue;
618 }
620 PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]);
621 if (faceDescr) {
622 Glib::ustring familyUIName = GetUIFamilyString(faceDescr);
623 Glib::ustring styleUIName = GetUIStyleString(faceDescr);
625 if (!familyUIName.empty() && !styleUIName.empty()) {
626 // Find the right place to put the style information, adding
627 // a map entry for the family name if it doesn't yet exist
629 FamilyToStylesMap::iterator iter = map->find(familyUIName);
631 if (iter == map->end()) {
632 map->insert(std::make_pair(familyUIName, std::list<Glib::ustring>()));
633 }
635 // Insert into the style list and save the info in the reference maps
636 // only if the style does not yet exist
638 bool exists = false;
639 std::list<Glib::ustring> &styleList = (*map)[familyUIName];
641 for (std::list<Glib::ustring>::iterator it=styleList.begin();
642 it != styleList.end();
643 it++) {
644 if (*it == styleUIName) {
645 exists = true;
646 break;
647 }
648 }
650 if (!exists) {
651 styleList.push_back(styleUIName);
653 // Add the string info needed in the reference maps
654 fontStringMap.insert(
655 std::make_pair(
656 Glib::ustring(familyUIName) + Glib::ustring(styleUIName),
657 ConstructFontSpecification(faceDescr)));
658 fontInstanceMap.insert(
659 std::make_pair(ConstructFontSpecification(faceDescr), faceDescr));
660 } else {
661 pango_font_description_free(faceDescr);
662 }
663 } else {
664 pango_font_description_free(faceDescr);
665 }
666 }
667 }
668 }
670 // Sort the style lists
671 for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); iter++) {
672 (*iter).second.sort(StyleNameCompareInternal);
673 }
674 }
675 }
677 font_instance* font_factory::FaceFromStyle(SPStyle const *style)
678 {
679 font_instance *font = NULL;
681 g_assert(style);
683 if (style) {
684 // First try to use the font specification if it is set
685 if (style->text->font_specification.set
686 && style->text->font_specification.value
687 && *style->text->font_specification.value) {
689 font = FaceFromFontSpecification(style->text->font_specification.value);
690 }
692 // If that failed, try using the CSS information in the style
693 if (!font) {
694 font = Face(style->text->font_family.value, font_style_to_pos(*style));
695 }
696 }
698 return font;
699 }
701 font_instance *font_factory::FaceFromDescr(char const *family, char const *style)
702 {
703 PangoFontDescription *temp_descr = pango_font_description_from_string(style);
704 pango_font_description_set_family(temp_descr,family);
705 font_instance *res = Face(temp_descr);
706 pango_font_description_free(temp_descr);
707 return res;
708 }
710 font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle)
711 {
712 font_instance *fontInstance = NULL;
714 g_assert(uiFamily && uiStyle);
715 if (uiFamily && uiStyle) {
716 Glib::ustring uiString = Glib::ustring(uiFamily) + Glib::ustring(uiStyle);
718 UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString);
720 if (uiToPangoIter != fontStringMap.end ()) {
721 PangoStringToDescrMap::iterator pangoToDescrIter = fontInstanceMap.find((*uiToPangoIter).second);
722 if (pangoToDescrIter != fontInstanceMap.end()) {
723 // We found the pango description - now we can make a font_instance
724 PangoFontDescription *tempDescr = pango_font_description_copy((*pangoToDescrIter).second);
725 fontInstance = Face(tempDescr);
726 pango_font_description_free(tempDescr);
727 }
728 }
729 }
731 return fontInstance;
732 }
734 font_instance* font_factory::FaceFromPangoString(char const *pangoString)
735 {
736 font_instance *fontInstance = NULL;
738 g_assert(pangoString);
740 if (pangoString) {
741 PangoFontDescription *descr = NULL;
743 // First attempt to find the font specification in the reference map
744 PangoStringToDescrMap::iterator it = fontInstanceMap.find(Glib::ustring(pangoString));
745 if (it != fontInstanceMap.end()) {
746 descr = pango_font_description_copy((*it).second);
747 }
749 // Or create a font description from the string - this may fail or
750 // produce unexpected results if the string does not have a good format
751 if (!descr) {
752 descr = pango_font_description_from_string(pangoString);
753 }
755 if (descr && (pango_font_description_get_family(descr) != NULL)) {
756 fontInstance = Face(descr);
757 }
759 if (descr) {
760 pango_font_description_free(descr);
761 }
762 }
764 return fontInstance;
765 }
767 font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecification)
768 {
769 font_instance *font = NULL;
771 g_assert(fontSpecification);
773 if (fontSpecification) {
774 // How the string is used to reconstruct a font depends on how it
775 // was constructed in ConstructFontSpecification. As it stands,
776 // the font specification is a pango-created string
777 font = FaceFromPangoString(fontSpecification);
778 }
780 return font;
781 }
785 font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
786 {
787 #ifdef USE_PANGO_WIN32
788 // damn Pango fudges the size, so we need to unfudge. See source of pango_win32_font_map_init()
789 pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE*72/GetDeviceCaps(pango_win32_get_dc(),LOGPIXELSY))); // mandatory huge size (hinting workaround)
790 #else
791 pango_font_description_set_size(descr, (int) (fontSize*PANGO_SCALE)); // mandatory huge size (hinting workaround)
792 #endif
794 font_instance *res = NULL;
796 if ( loadedFaces.find(descr) == loadedFaces.end() ) {
797 // not yet loaded
798 PangoFont *nFace = NULL;
800 // workaround for bug #1025565.
801 // fonts without families blow up Pango.
802 if (pango_font_description_get_family(descr) != NULL) {
803 nFace = pango_font_map_load_font(fontServer,fontContext,descr);
804 }
805 else {
806 g_warning(_("Ignoring font without family that will crash Pango"));
807 }
809 if ( nFace ) {
810 // duplicate FcPattern, the hard way
811 res = new font_instance();
812 // store the descr of the font we asked for, since this is the key where we intend to put the font_instance at
813 // in the hash_map. the descr of the returned pangofont may differ from what was asked, so we don't know (at this
814 // point) whether loadedFaces[that_descr] is free or not (and overwriting an entry will bring deallocation problems)
815 res->descr = pango_font_description_copy(descr);
816 res->daddy = this;
817 res->InstallFace(nFace);
818 if ( res->pFont == NULL ) {
819 // failed to install face -> bitmap font
820 // printf("face failed\n");
821 res->daddy = NULL;
822 delete res;
823 res = NULL;
824 if ( canFail ) {
825 char *tc = pango_font_description_to_string(descr);
826 PANGO_DEBUG("falling back from %s to Sans because InstallFace failed\n",tc);
827 g_free(tc);
828 pango_font_description_set_family(descr,"Sans");
829 res = Face(descr,false);
830 }
831 } else {
832 loadedFaces[res->descr]=res;
833 res->Ref();
834 AddInCache(res);
835 }
836 } else {
837 // no match
838 if ( canFail ) {
839 PANGO_DEBUG("falling back to Sans\n");
840 descr = pango_font_description_new();
841 pango_font_description_set_family(descr,"Sans");
842 res = Face(descr,false);
843 pango_font_description_free(descr);
844 }
845 }
846 } else {
847 // already here
848 res = loadedFaces[descr];
849 res->Ref();
850 AddInCache(res);
851 }
852 if(res)
853 res->InitTheFace();
854 return res;
855 }
857 font_instance *font_factory::Face(char const *family, int variant, int style, int weight, int stretch, int /*size*/, int /*spacing*/)
858 {
859 PangoFontDescription *temp_descr = pango_font_description_new();
860 pango_font_description_set_family(temp_descr,family);
861 pango_font_description_set_weight(temp_descr,(PangoWeight)weight);
862 pango_font_description_set_stretch(temp_descr,(PangoStretch)stretch);
863 pango_font_description_set_style(temp_descr,(PangoStyle)style);
864 pango_font_description_set_variant(temp_descr,(PangoVariant)variant);
865 font_instance *res = Face(temp_descr);
866 pango_font_description_free(temp_descr);
867 return res;
868 }
870 font_instance *font_factory::Face(char const *family, NRTypePosDef apos)
871 {
872 PangoFontDescription *temp_descr = pango_font_description_new();
874 pango_font_description_set_family(temp_descr, family);
876 if ( apos.variant == NR_POS_VARIANT_SMALLCAPS ) {
877 pango_font_description_set_variant(temp_descr, PANGO_VARIANT_SMALL_CAPS);
878 } else {
879 pango_font_description_set_variant(temp_descr, PANGO_VARIANT_NORMAL);
880 }
882 if ( apos.italic ) {
883 pango_font_description_set_style(temp_descr, PANGO_STYLE_ITALIC);
884 } else if ( apos.oblique ) {
885 pango_font_description_set_style(temp_descr, PANGO_STYLE_OBLIQUE);
886 } else {
887 pango_font_description_set_style(temp_descr, PANGO_STYLE_NORMAL);
888 }
890 if ( apos.weight <= NR_POS_WEIGHT_ULTRA_LIGHT ) {
891 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRALIGHT);
892 } else if ( apos.weight <= NR_POS_WEIGHT_LIGHT ) {
893 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_LIGHT);
894 } else if ( apos.weight <= NR_POS_WEIGHT_NORMAL ) {
895 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_NORMAL);
896 } else if ( apos.weight <= NR_POS_WEIGHT_BOLD ) {
897 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_BOLD);
898 } else if ( apos.weight <= NR_POS_WEIGHT_ULTRA_BOLD ) {
899 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_ULTRABOLD);
900 } else {
901 pango_font_description_set_weight(temp_descr, PANGO_WEIGHT_HEAVY);
902 }
904 if ( apos.stretch <= NR_POS_STRETCH_ULTRA_CONDENSED ) {
905 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_CONDENSED);
906 } else if ( apos.stretch <= NR_POS_STRETCH_CONDENSED ) {
907 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_CONDENSED);
908 } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_CONDENSED ) {
909 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_CONDENSED);
910 } else if ( apos.stretch <= NR_POS_WEIGHT_NORMAL ) {
911 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_NORMAL);
912 } else if ( apos.stretch <= NR_POS_STRETCH_SEMI_EXPANDED ) {
913 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_SEMI_EXPANDED);
914 } else if ( apos.stretch <= NR_POS_STRETCH_EXPANDED ) {
915 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXPANDED);
916 } else {
917 pango_font_description_set_stretch(temp_descr, PANGO_STRETCH_EXTRA_EXPANDED);
918 }
920 font_instance *res = Face(temp_descr);
921 pango_font_description_free(temp_descr);
922 return res;
923 }
925 void font_factory::UnrefFace(font_instance *who)
926 {
927 if ( who == NULL ) return;
928 if ( loadedFaces.find(who->descr) == loadedFaces.end() ) {
929 // not found
930 char *tc = pango_font_description_to_string(who->descr);
931 g_warning("unrefFace %p=%s: failed\n",who,tc);
932 g_free(tc);
933 } else {
934 loadedFaces.erase(loadedFaces.find(who->descr));
935 // printf("unrefFace %p: success\n",who);
936 }
937 }
939 void font_factory::AddInCache(font_instance *who)
940 {
941 if ( who == NULL ) return;
942 for (int i = 0;i < nbEnt;i++) ents[i].age *= 0.9;
943 for (int i = 0;i < nbEnt;i++) {
944 if ( ents[i].f == who ) {
945 // printf("present\n");
946 ents[i].age += 1.0;
947 return;
948 }
949 }
950 if ( nbEnt > maxEnt ) {
951 printf("cache sur-plein?\n");
952 return;
953 }
954 who->Ref();
955 if ( nbEnt == maxEnt ) {
956 int bi = 0;
957 double ba = ents[bi].age;
958 for (int i = 1;i < nbEnt;i++) {
959 if ( ents[i].age < ba ) {
960 bi = i;
961 ba = ents[bi].age;
962 }
963 }
964 ents[bi].f->Unref();
965 ents[bi]=ents[--nbEnt];
966 }
967 ents[nbEnt].f = who;
968 ents[nbEnt].age = 1.0;
969 nbEnt++;
970 }
973 /*
974 Local Variables:
975 mode:c++
976 c-file-style:"stroustrup"
977 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
978 indent-tabs-mode:nil
979 fill-column:99
980 End:
981 */
982 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :