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