a63f70d758819033586bc66dd0237501519ef7ec
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;
103 }
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)
111 {
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;
117 }
119 /**
120 * Non-bold fonts are 'Medium' or 'Book'
121 */
122 static bool
123 is_nonbold(char const *s)
124 {
125 if (ink_strstr(s, "Medium")) return true;
126 if (ink_strstr(s, "Book")) return true;
127 return false;
128 }
130 /**
131 * Italic fonts are 'Italic', 'Oblique', or 'Slanted'
132 */
133 static bool
134 is_italic(char const *s)
135 {
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;
140 }
142 /**
143 * Bold fonts are 'Bold'
144 */
145 static bool
146 is_bold(char const *s)
147 {
148 if (ink_strstr(s, "Bold")) return true;
149 return false;
150 }
152 /**
153 * Caps fonts are 'Caps'
154 */
155 static bool
156 is_caps(char const *s)
157 {
158 if (ink_strstr(s, "Caps")) return true;
159 return false;
160 }
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)
169 {
170 if (ink_strstr(s, "Mono")) return true;
171 return false;
172 }
174 /**
175 * Rounded fonts are 'Round'
176 */
177 static bool
178 is_round(char const *s)
179 {
180 if (ink_strstr(s, "Round")) return true;
181 return false;
182 }
184 /**
185 * Outline fonts are 'Outline'
186 */
187 static bool
188 is_outline(char const *s)
189 {
190 if (ink_strstr(s, "Outline")) return true;
191 return false;
192 }
194 /**
195 * Swash fonts are 'Swash'
196 */
197 static bool
198 is_swash(char const *s)
199 {
200 if (ink_strstr(s, "Swash")) return true;
201 return false;
202 }
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)
215 {
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);
235 }
237 /*
238 defined but not used:
240 static int
241 style_record_compare(void const *aa, void const *bb)
242 {
243 NRStyleRecord const *a = (NRStyleRecord const *) aa;
244 NRStyleRecord const *b = (NRStyleRecord const *) bb;
246 return (style_name_compare(a->name, b->name));
247 }
249 static void font_factory_name_list_destructor(NRNameList *list)
250 {
251 for (unsigned int i = 0; i < list->length; i++)
252 g_free(list->names[i]);
253 if ( list->names ) g_free(list->names);
254 }
256 static void font_factory_style_list_destructor(NRStyleList *list)
257 {
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);
263 }
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)
271 {
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
277 }
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*/)
289 {
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);
294 }
295 #endif
298 font_factory *font_factory::lUsine = NULL;
300 font_factory *font_factory::Default(void)
301 {
302 if ( lUsine == NULL ) lUsine = new font_factory;
303 return lUsine;
304 }
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())
322 {
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
329 }
331 font_factory::~font_factory(void)
332 {
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 }
355 }
358 Glib::ustring font_factory::ConstructFontSpecification(PangoFontDescription *font)
359 {
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;
380 }
382 Glib::ustring font_factory::ConstructFontSpecification(font_instance *font)
383 {
384 Glib::ustring pangoString;
386 g_assert(font);
388 if (font) {
389 pangoString = ConstructFontSpecification(font->descr);
390 }
392 return pangoString;
393 }
395 Glib::ustring font_factory::GetUIFamilyString(PangoFontDescription const *fontDescr)
396 {
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;
407 }
409 Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDescr)
410 {
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;
428 }
430 Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily)
431 {
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;
508 }
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)
517 {
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;
560 }
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)
569 {
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;
598 }
600 /////
602 static bool StyleNameCompareInternal(Glib::ustring style1, Glib::ustring style2)
603 {
604 return (style_name_compare(style1.c_str(), style2.c_str()) < 0);
605 }
607 void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map)
608 {
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 }
689 }
691 font_instance* font_factory::FaceFromStyle(SPStyle const *style)
692 {
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;
713 }
715 font_instance *font_factory::FaceFromDescr(char const *family, char const *style)
716 {
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;
722 }
724 font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle)
725 {
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;
746 }
748 font_instance* font_factory::FaceFromPangoString(char const *pangoString)
749 {
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;
779 }
781 font_instance* font_factory::FaceFromFontSpecification(char const *fontSpecification)
782 {
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;
795 }
799 font_instance *font_factory::Face(PangoFontDescription *descr, bool canFail)
800 {
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;
871 }
873 font_instance *font_factory::Face(char const *family, int variant, int style, int weight, int stretch, int /*size*/, int /*spacing*/)
874 {
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;
884 }
886 font_instance *font_factory::Face(char const *family, NRTypePosDef apos)
887 {
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;
939 }
941 void font_factory::UnrefFace(font_instance *who)
942 {
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 }
956 }
958 void font_factory::AddInCache(font_instance *who)
959 {
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++;
989 }
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 :