From 89c93099750a1123ea99bc98feb00ff51ee64373 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 15 Oct 2014 20:17:43 +0200 Subject: More direct way of finding font-family. One entry per unique style. (experimental r13580 and r12581) (bzr r13616.1.3) --- src/extension/internal/pdfinput/svg-builder.cpp | 11 +- src/libnrtype/FontFactory.cpp | 483 ++---------------------- src/libnrtype/FontFactory.h | 38 +- 3 files changed, 50 insertions(+), 482 deletions(-) (limited to 'src') diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 71e6dc6ae..7a504add0 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -123,12 +123,11 @@ void SvgBuilder::_init() { _height = 0; // Fill _availableFontNames (Bug LP #179589) (code cfr. FontLister) - FamilyToStylesMap familyStyleMap; - font_factory::Default()->GetUIFamiliesAndStyles(&familyStyleMap); - for (FamilyToStylesMap::iterator iter = familyStyleMap.begin(); - iter != familyStyleMap.end(); - ++iter) { - _availableFontNames.push_back(iter->first.c_str()); + std::vector families; + font_factory::Default()->GetUIFamilies(families); + for ( std::vector::iterator iter = families.begin(); + iter != families.end(); ++iter ) { + _availableFontNames.push_back(pango_font_family_get_name(*iter)); } _transp_group_stack = NULL; diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index cb9af5eb0..cb9602394 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -130,13 +130,6 @@ font_factory::~font_factory(void) delete tmp; loadedPtr = 0; } - - // Delete the pango font pointers in the string to instance map - PangoStringToDescrMap::iterator it = fontInstanceMap.begin(); - while (it != fontInstanceMap.end()) { - pango_font_description_free((*it).second); - ++it; - } } @@ -249,248 +242,6 @@ Glib::ustring font_factory::GetUIStyleString(PangoFontDescription const *fontDes return style; } -/** - Replace font family leaving style alone (if possible). - @param fontSpec the given font - @param newFamily - @return the changed fontspec, if the property can not be set return an empty string - The routine first searches for an exact match. - If no exact match found, calls FontSpecificationBestMatch(). -*/ -Glib::ustring font_factory::ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily) -{ - Glib::ustring newFontSpec; - - // Although we are using the string from pango_font_description_to_string for the - // font specification, we definitely cannot just set the new family in the - // PangoFontDescription structure and ask for a new string. This is because - // what constitutes a "family" in our own UI may be different from how Pango - // sees it. - - // Find the PangoFontDescription associated with the old font specification string. - PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); - - - if (it != fontInstanceMap.end()) { - // Description found! - - // Make copy - PangoFontDescription *descr = pango_font_description_copy((*it).second); - - // Grab the old UI Family string from the descr - Glib::ustring uiFamily = GetUIFamilyString(descr); - - // Replace the UI Family name with the new family name - std::size_t found = fontSpec.find(uiFamily); - if (found != Glib::ustring::npos) { - - // Add comma to end of newFamily... commas at end don't hurt but are - // required if the last part of a family name is a valid font style - // (e.g. "Arial Black"). - Glib::ustring newFamilyComma = newFamily; - if( *newFamilyComma.rbegin() != ',' ) { - newFamilyComma += ","; - } - newFontSpec = fontSpec; - newFontSpec.erase(found, uiFamily.size()); - newFontSpec.insert(found, newFamilyComma); - - // If the new font specification does not exist in the reference maps, - // search for the next best match for the faces in that style - it = fontInstanceMap.find(newFontSpec); - if (it == fontInstanceMap.end()) { - - // Search for best match, empty string returned if not found. - newFontSpec = FontSpecificationBestMatch( newFontSpec ); - - } - } - - pango_font_description_free(descr); - } - - return newFontSpec; -} - -/** - Apply style property to the given font - @param fontSpec the given font - @param turnOn true to set italic style - @return the changed fontspec, if the property can not be set return an empty string - The routine first searches for an exact match to "FontFamily Italic" or - "Font Family Oblique" (turnOn is true) or "FontFamily" (turnOn is false). - If no exact match found, calls FontSpecificationBestMatch(). -*/ -Glib::ustring font_factory::FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn) -{ - Glib::ustring newFontSpec; - - // Find the PangoFontDescription associated with the font specification string. - PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); - - if (it != fontInstanceMap.end()) { - // Description found! - - // Make copy. - PangoFontDescription *descr = pango_font_description_copy((*it).second); - - PangoStyle style; - if (turnOn) { - // First try Oblique, we'll try Italic later - style = PANGO_STYLE_OBLIQUE; - } else { - style = PANGO_STYLE_NORMAL; - } - - pango_font_description_set_style(descr, style); - - newFontSpec = ConstructFontSpecification(descr); - - bool exactMatchFound = true; - if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) { - - exactMatchFound = false; - if (turnOn) { - // Next try Italic - style = PANGO_STYLE_ITALIC; - pango_font_description_set_style(descr, style); - - exactMatchFound = true; - if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) { - exactMatchFound = false; - } - } - } - - // Search for best match, empty string returned if not found. - if( !exactMatchFound ) { - newFontSpec = FontSpecificationBestMatch( newFontSpec ); - } - - pango_font_description_free(descr); - } - - return newFontSpec; // Empty if not found. -} - -/** - Apply weight property to the given font - @param fontSpec the given font - @param turnOn true to set bold - @return the changed fontspec, if the property can not be set return an empty string - This routine first searches for an exact match, if none found - it calls FontSpecificationBestMatch(). -*/ -Glib::ustring font_factory::FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn) -{ - Glib::ustring newFontSpec; - - // Find the PangoFontDescription associated with the font specification string. - PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); - - if (it != fontInstanceMap.end()) { - // Description found! - - // Make copy. - PangoFontDescription *descr = pango_font_description_copy((*it).second); - - - PangoWeight weight; - if (turnOn) { - weight = PANGO_WEIGHT_BOLD; - } else { - weight = PANGO_WEIGHT_NORMAL; - } - - pango_font_description_set_weight(descr, weight); - - newFontSpec = ConstructFontSpecification(descr); - - if (fontInstanceMap.find(newFontSpec) == fontInstanceMap.end()) { - // Search for best match, empty string returned if not found. - newFontSpec = FontSpecificationBestMatch( newFontSpec ); - } - - pango_font_description_free(descr); - } - - return newFontSpec; // Empty if not found. -} - -/** - Use pango_font_description_better_match() to find best font match. - This handles cases like Century Schoolbook L where the "normal" - font is Century Schoolbook L Medium so just removing Italic - from the font name doesn't yield the correct name. - @param fontSpec the given font - @return the changed fontspec, if the property can not be set return an empty string -*/ -// http://library.gnome.org/devel/pango/1.28/pango-Fonts.html#pango-font-description-better-match -Glib::ustring font_factory::FontSpecificationBestMatch(const Glib::ustring & fontSpec ) -{ - - Glib::ustring newFontSpec; - - // Look for exact match - PangoStringToDescrMap::iterator it = fontInstanceMap.find(fontSpec); - - // If there is no exact match, look for the best match. - if (it != fontInstanceMap.end()) { - - newFontSpec = fontSpec; - - } else { - - PangoFontDescription *fontDescr = pango_font_description_from_string(fontSpec.c_str()); - PangoFontDescription *bestMatchDescr = NULL; - - // Grab the UI Family string from the descr - Glib::ustring family = GetUIFamilyString(fontDescr); - Glib::ustring bestMatchDescription; - - bool setFirstFamilyMatch = false; - for (it = fontInstanceMap.begin(); it != fontInstanceMap.end(); ++it) { - - Glib::ustring currentFontSpec = (*it).first; - Glib::ustring currentFamily = GetUIFamilyString((*it).second); - - // Save some time by only looking at the right family. - // Must use family name rather than fontSpec - // (otherwise DejaVu Sans matches DejaVu Sans Mono). - if (currentFamily == family) { - if (!setFirstFamilyMatch) { - // This ensures that the closest match is at least within the correct - // family rather than the first font in the list - bestMatchDescr = pango_font_description_copy((*it).second); - bestMatchDescription = currentFontSpec; - setFirstFamilyMatch = true; - } else { - // Get the font description that corresponds, and - // then see if we've found a better match - PangoFontDescription *possibleMatch = pango_font_description_copy((*it).second); - - if (pango_font_description_better_match( - fontDescr, bestMatchDescr, possibleMatch)) { - - pango_font_description_free(bestMatchDescr); - bestMatchDescr = possibleMatch; - bestMatchDescription = currentFontSpec; - } else { - pango_font_description_free(possibleMatch); - } - } - } - } // for - - newFontSpec = bestMatchDescription; // If NULL, then no match found - - pango_font_description_free(fontDescr); - pango_font_description_free(bestMatchDescr); - - } - - return newFontSpec; -} ///// @@ -509,10 +260,10 @@ static int StyleNameValue( const Glib::ustring &style ) } // Determines order in which styles are presented (sorted by CSS style values) -static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames &style2) -{ - return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); -} +//static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames &style2) +//{ +// return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); +//} static bool ustringPairSort(std::pair const& first, std::pair const& second) { @@ -559,6 +310,7 @@ GList* font_factory::GetUIStyles(PangoFontFamily * in) // If the face has a name, describe it, and then use the // description to get the UI family and face strings const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); + // std::cout << "Display Name: " << displayName << std::endl; if (displayName == NULL || *displayName == '\0') { continue; } @@ -579,7 +331,19 @@ GList* font_factory::GetUIStyles(PangoFontFamily * in) } } - if (!familyUIName.empty() && !styleUIName.empty()) { + bool exists = false; + for(GList *temp = ret; temp; temp = temp->next) { + if( ((StyleNames*)temp->data)->CssName.compare( styleUIName ) == 0 ) { + exists = true; + std::cerr << "Warning: Font face with same CSS values already added: " + << familyUIName << " " << styleUIName + << " (" << ((StyleNames*)temp->data)->DisplayName + << ", " << displayName << ")" << std::endl; + break; + } + } + + if (!exists && !familyUIName.empty() && !styleUIName.empty()) { // Add the style information ret = g_list_append(ret, new StyleNames(styleUIName, displayName)); } @@ -590,140 +354,6 @@ GList* font_factory::GetUIStyles(PangoFontFamily * in) return ret; } -void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) -{ - g_assert(map); - - if (map) { - - // Gather the family names as listed by Pango - PangoFontFamily** families = NULL; - int numFamilies = 0; - pango_font_map_list_families(fontServer, &families, &numFamilies); - - for (int currentFamily=0; currentFamily < numFamilies; currentFamily++) { - - // Gather the styles for this family - PangoFontFace** faces = NULL; - int numFaces = 0; - pango_font_family_list_faces(families[currentFamily], &faces, &numFaces); - - for (int currentFace=0; currentFace < numFaces; currentFace++) { - - // If the face has a name, describe it, and then use the - // description to get the UI family and face strings - - const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); - if (displayName == NULL) { - continue; - } - - PangoFontDescription *faceDescr = pango_font_face_describe(faces[currentFace]); - if (faceDescr) { - Glib::ustring familyUIName = GetUIFamilyString(faceDescr); - Glib::ustring styleUIName = GetUIStyleString(faceDescr); - // std::cout << familyUIName << " " << styleUIName << " (" << displayName << ")" << std::endl; - - // Disable synthesized (faux) font faces except for CSS generic faces - if (pango_font_face_is_synthesized(faces[currentFace]) ) { - if( familyUIName.compare( "sans-serif" ) != 0 && - familyUIName.compare( "serif" ) != 0 && - familyUIName.compare( "monospace" ) != 0 && - familyUIName.compare( "fantasy" ) != 0 && - familyUIName.compare( "cursive" ) != 0 ) { - //std::cout << "faux: " << familyUIName << " | " << styleUIName << std::endl; - continue; - } - } - - // Pango breaks the 1 to 1 mapping between Pango weights and CSS weights by - // adding Semi-Light (as of 1.36.7), Book (as of 1.24), and Ultra-Heavy (as of - // 1.24). We need to map these weights to CSS weights. Book and Ultra-Heavy - // are rarely used. Semi-Light (350) is problematic as it is halfway between - // Light (300) and Normal (400) and if care is not taken it is converted to - // Normal, rather than Light. - // - // Note: The ultimate solution to handling various weight in the same - // font family is to support the @font rules from CSS. - // - // Additional notes, helpful for debugging: - // Pango's FC backend: - // Weights defined in fontconfig/fontconfig.h - // String equivalents in src/fcfreetype.c - // Weight set from os2->usWeightClass - // Use Fontforge: Element->Font Info...->OS/2->Misc->Weight Class to check font weight - size_t f = styleUIName.find( "Book" ); - if( f != Glib::ustring::npos ) { - styleUIName.replace( f, 4, "Normal" ); - } - f = styleUIName.find( "Semi-Light" ); - if( f != Glib::ustring::npos ) { - styleUIName.replace( f, 10, "Light" ); - } - f = styleUIName.find( "Ultra-Heavy" ); - if( f != Glib::ustring::npos ) { - styleUIName.replace( f, 11, "Heavy" ); - } - - if (!familyUIName.empty() && !styleUIName.empty()) { - - // Find the right place to put the style information, adding - // a map entry for the family name if it doesn't yet exist - - FamilyToStylesMap::iterator iter = map->find(familyUIName); - - // Insert new family - if (iter == map->end()) { - map->insert(std::make_pair(familyUIName, std::list())); - } - - // Insert into the style list and save the info in the reference maps - // only if the style does not yet exist - - bool exists = false; - std::list &styleList = (*map)[familyUIName]; - - for (std::list::iterator it=styleList.begin(); - it != styleList.end(); - ++it) { - if ( (*it).CssName == styleUIName) { - exists = true; - std::cerr << "Warning: Font face with same CSS values already added: " << familyUIName << " " << styleUIName << " (" << (*it).DisplayName << ", " << displayName << ")" << std::endl; - break; - } - } - - if (!exists) { - styleList.push_back( StyleNames(styleUIName,displayName) ); - - // Add the string info needed in the reference maps - fontStringMap.insert( - std::make_pair( - Glib::ustring(familyUIName) + Glib::ustring(styleUIName), - ConstructFontSpecification(faceDescr))); - fontInstanceMap.insert( - std::make_pair(ConstructFontSpecification(faceDescr), faceDescr)); - - } else { - pango_font_description_free(faceDescr); - } - } else { - pango_font_description_free(faceDescr); - } - } - } - g_free(faces); - faces = 0; - } - g_free(families); - families = 0; - - // Sort the style lists - for (FamilyToStylesMap::iterator iter = map->begin() ; iter != map->end(); ++iter) { - (*iter).second.sort(StyleNameCompareInternal); - } - } -} font_instance* font_factory::FaceFromStyle(SPStyle const *style) { @@ -869,14 +499,6 @@ font_instance* font_factory::FaceFromStyle(SPStyle const *style) font = Face(temp_descr); pango_font_description_free(temp_descr); - - // We now find closest match to this font: - Glib::ustring fontSpec = font_factory::Default()->ConstructFontSpecification(font); - Glib::ustring newFontSpec = FontSpecificationBestMatch( fontSpec ); - if( fontSpec != newFontSpec ) { - font->Unref(); - font = FaceFromFontSpecification( newFontSpec.c_str() ); - } } } @@ -892,37 +514,6 @@ font_instance *font_factory::FaceFromDescr(char const *family, char const *style return res; } -font_instance* font_factory::FaceFromUIStrings(char const *uiFamily, char const *uiStyle) -{ - font_instance *fontInstance = NULL; - - g_assert(uiFamily && uiStyle); - if (uiFamily && uiStyle) { - - // If font list, take only first font in list - gchar** tokens = g_strsplit( uiFamily, ",", 0 ); - g_strstrip( tokens[0] ); - - Glib::ustring uiString = Glib::ustring(tokens[0]) + Glib::ustring(uiStyle); - - g_strfreev( tokens ); - - UIStringToPangoStringMap::iterator uiToPangoIter = fontStringMap.find(uiString); - - if (uiToPangoIter != fontStringMap.end ()) { - PangoStringToDescrMap::iterator pangoToDescrIter = fontInstanceMap.find((*uiToPangoIter).second); - if (pangoToDescrIter != fontInstanceMap.end()) { - // We found the pango description - now we can make a font_instance - PangoFontDescription *tempDescr = pango_font_description_copy((*pangoToDescrIter).second); - fontInstance = Face(tempDescr); - pango_font_description_free(tempDescr); - } - } - } - - return fontInstance; -} - font_instance* font_factory::FaceFromPangoString(char const *pangoString) { font_instance *fontInstance = NULL; @@ -930,25 +521,15 @@ font_instance* font_factory::FaceFromPangoString(char const *pangoString) g_assert(pangoString); if (pangoString) { - PangoFontDescription *descr = NULL; - - // First attempt to find the font specification in the reference map - PangoStringToDescrMap::iterator it = fontInstanceMap.find(Glib::ustring(pangoString)); - if (it != fontInstanceMap.end()) { - descr = pango_font_description_copy((*it).second); - } - // Or create a font description from the string - this may fail or + // Create a font description from the string - this may fail or // produce unexpected results if the string does not have a good format - if (!descr) { - descr = pango_font_description_from_string(pangoString); - } - - if (descr && (sp_font_description_get_family(descr) != NULL)) { - fontInstance = Face(descr); - } + PangoFontDescription *descr = pango_font_description_from_string(pangoString); if (descr) { + if (sp_font_description_get_family(descr) != NULL) { + fontInstance = Face(descr); + } pango_font_description_free(descr); } } @@ -1113,24 +694,6 @@ void font_factory::AddInCache(font_instance *who) nbEnt++; } -/* - { - std::cout << " Printing out fontInstanceMap: " << std::endl; - PangoStringToDescrMap::iterator it = fontInstanceMap.begin(); - while (it != fontInstanceMap.end()) { - - PangoFontDescription *descr = pango_font_description_copy((*it).second); - - // Grab the UI Family string from the descr - Glib::ustring uiFamily = GetUIFamilyString(descr); - Glib::ustring uiStyle = GetUIStyleString(descr); - std::cout << " " << uiFamily << " " << uiStyle << std::endl; - - it++; - } - } -*/ - /* Local Variables: mode:c++ diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index 85576e08d..bd5a4460c 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -112,18 +112,6 @@ public: Glib::ustring GetUIFamilyString(PangoFontDescription const *fontDescr); Glib::ustring GetUIStyleString(PangoFontDescription const *fontDescr); - /// Modifiers for the font specification (returns new font specification) - Glib::ustring ReplaceFontSpecificationFamily(const Glib::ustring & fontSpec, const Glib::ustring & newFamily); - Glib::ustring FontSpecificationSetItalic(const Glib::ustring & fontSpec, bool turnOn); - Glib::ustring FontSpecificationSetBold(const Glib::ustring & fontSpec, bool turnOn); - - Glib::ustring FontSpecificationBestMatch(const Glib::ustring& fontSpec ); - - // Gathers all strings needed for UI while storing pango information in - // fontInstanceMap and fontStringMap - // don't use this function, it's too slow - void GetUIFamiliesAndStyles(FamilyToStylesMap *map); - // Helpfully inserts all font families into the provided vector void GetUIFamilies(std::vector& out); // Retrieves style information about a family in a newly allocated GList. @@ -152,19 +140,37 @@ public: private: void* loadedPtr; + + // The following two commented out maps were an attempt to allow Inkscape to use font faces + // that could not be distinguished by CSS values alone. In practice, they never were that + // useful as PangoFontDescription, which is used throughout our code, cannot distinguish + // between faces anymore than raw CSS values (with the exception of two additional weight + // values). + // + // During various works, for example to handle font-family lists and fonts that are not + // installed on the system, the code has become less reliant on these maps. And in the work to + // catch style information to speed up start up times, the maps were not being filled. + // I've removed all code that used these maps as of Oct 2014 in the experimental branch. + // The commented out maps are left here as a reminder of the path that was attempted. + // + // One possible method to keep track of font faces would be to use the 'display name', keeping + // pointers to the appropriate PangoFontFace. The font_factory loadedFaces map indexing would + // have to be changed to incorporate 'display name' (InkscapeFontDescription?). + + // These two maps are used for translating between what's in the UI and a pango // font description. This is necessary because Pango cannot always // reproduce these structures from the names it gave us in the first place. // Key: A string produced by font_factory::ConstructFontSpecification // Value: The associated PangoFontDescription - typedef std::map PangoStringToDescrMap; - PangoStringToDescrMap fontInstanceMap; + // typedef std::map PangoStringToDescrMap; + // PangoStringToDescrMap fontInstanceMap; // Key: Family name in UI + Style name in UI // Value: The associated string that should be produced with font_factory::ConstructFontSpecification - typedef std::map UIStringToPangoStringMap; - UIStringToPangoStringMap fontStringMap; + // typedef std::map UIStringToPangoStringMap; + // UIStringToPangoStringMap fontStringMap; }; -- cgit v1.2.3