diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2014-10-15 18:56:16 +0000 |
|---|---|---|
| committer | tavmjong-free <tavmjong@free.fr> | 2014-10-15 18:56:16 +0000 |
| commit | 58989cdb66d715f968d4c3e77fd13532c92e1fda (patch) | |
| tree | 3ae5fad83e24b42753aa14e117d06ff810abc40d /src | |
| parent | Fix build (diff) | |
| parent | Various small font things. (diff) | |
| download | inkscape-58989cdb66d715f968d4c3e77fd13532c92e1fda.tar.gz inkscape-58989cdb66d715f968d4c3e77fd13532c92e1fda.zip | |
Font caching from experimental branch. Speeds up Inkscape start-up.
Most work by Liam. Various tweeks by Tav.
(bzr r13617)
Diffstat (limited to 'src')
| -rw-r--r-- | src/extension/internal/pdfinput/svg-builder.cpp | 11 | ||||
| -rw-r--r-- | src/ink-comboboxentry-action.cpp | 2 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.cpp | 562 | ||||
| -rw-r--r-- | src/libnrtype/FontFactory.h | 44 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.cpp | 1688 | ||||
| -rw-r--r-- | src/libnrtype/font-lister.h | 556 | ||||
| -rw-r--r-- | src/ui/dialog/text-edit.cpp | 6 | ||||
| -rw-r--r-- | src/ui/tools/tool-base.cpp | 3 | ||||
| -rw-r--r-- | src/widgets/font-selector.cpp | 4 | ||||
| -rw-r--r-- | src/widgets/text-toolbar.cpp | 10 |
10 files changed, 1296 insertions, 1590 deletions
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<PangoFontFamily *> families; + font_factory::Default()->GetUIFamilies(families); + for ( std::vector<PangoFontFamily *>::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/ink-comboboxentry-action.cpp b/src/ink-comboboxentry-action.cpp index 6579c8ff8..f7d1c8724 100644 --- a/src/ink-comboboxentry-action.cpp +++ b/src/ink-comboboxentry-action.cpp @@ -390,6 +390,8 @@ GtkWidget* create_tool_item( GtkAction* action ) NULL, NULL ); } + // FIXME: once gtk3 migration is done this can be removed + // https://bugzilla.gnome.org/show_bug.cgi?id=734915 gtk_widget_show_all (comboBoxEntry); // Optionally add formatting... diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index e11fed20c..d052eeb42 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,144 +260,136 @@ 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) +//static bool StyleNameCompareInternal(const StyleNames &style1, const StyleNames &style2) +//{ +// return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); +//} + +static gint StyleNameCompareInternalGlib(gconstpointer a, gconstpointer b) { - return( StyleNameValue( style1.CssName ) < StyleNameValue( style2.CssName ) ); + return( StyleNameValue( ((StyleNames *)a)->CssName ) < + StyleNameValue( ((StyleNames *)b)->CssName ) ? -1 : 1 ); } -void font_factory::GetUIFamiliesAndStyles(FamilyToStylesMap *map) +static bool ustringPairSort(std::pair<PangoFontFamily*, Glib::ustring> const& first, std::pair<PangoFontFamily*, Glib::ustring> const& second) { - 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++) { + // well, this looks weird. + return first.second < second.second; +} - // Gather the styles for this family - PangoFontFace** faces = NULL; - int numFaces = 0; - pango_font_family_list_faces(families[currentFamily], &faces, &numFaces); +void font_factory::GetUIFamilies(std::vector<PangoFontFamily *>& out) +{ + // Gather the family names as listed by Pango + PangoFontFamily** families = NULL; + int numFamilies = 0; + pango_font_map_list_families(fontServer, &families, &numFamilies); + + std::vector<std::pair<PangoFontFamily *, Glib::ustring> > sorted; + + // not size_t + for (int currentFamily = 0; currentFamily < numFamilies; ++currentFamily) { + const char* displayName = pango_font_family_get_name(families[currentFamily]); + + if (displayName == 0 || *displayName == '\0') { + continue; + } + sorted.push_back(std::make_pair(families[currentFamily], displayName)); + } - for (int currentFace=0; currentFace < numFaces; currentFace++) { + std::sort(sorted.begin(), sorted.end(), ustringPairSort); + + for (size_t i = 0; i < sorted.size(); ++i) { + out.push_back(sorted[i].first); + } +} - // If the face has a name, describe it, and then use the - // description to get the UI family and face strings +GList* font_factory::GetUIStyles(PangoFontFamily * in) +{ + GList* ret = NULL; + // Gather the styles for this family + PangoFontFace** faces = NULL; + int numFaces = 0; + pango_font_family_list_faces(in, &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]); + // std::cout << "Display Name: " << displayName << std::endl; + if (displayName == NULL || *displayName == '\0') { + continue; + } - const gchar* displayName = pango_font_face_get_face_name(faces[currentFace]); - if (displayName == NULL) { + 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 ) { 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" ); + } - 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<StyleNames>())); - } - - // 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<StyleNames> &styleList = (*map)[familyUIName]; - - for (std::list<StyleNames>::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); - } + 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; } } - 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); + if (!exists && !familyUIName.empty() && !styleUIName.empty()) { + // Add the style information + ret = g_list_append(ret, new StyleNames(styleUIName, displayName)); + } } + pango_font_description_free(faceDescr); } + g_free(faces); + + // Sort the style lists + ret = g_list_sort( ret, StyleNameCompareInternalGlib ); + return ret; } font_instance* font_factory::FaceFromStyle(SPStyle const *style) @@ -793,14 +536,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() ); - } } } @@ -816,37 +551,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; @@ -854,25 +558,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); } } @@ -1038,24 +732,6 @@ void font_factory::AddInCache(font_instance *who) } /* - { - 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++ c-file-style:"stroustrup" diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index bb3a8fa25..bd5a4460c 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -21,7 +21,7 @@ #include <pango/pango.h> #include "nr-type-primitives.h" -#include "../style.h" +#include "style.h" /* Freetype */ #ifdef USE_PANGO_WIN32 @@ -112,16 +112,10 @@ 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 - void GetUIFamiliesAndStyles(FamilyToStylesMap *map); + // Helpfully inserts all font families into the provided vector + void GetUIFamilies(std::vector<PangoFontFamily *>& out); + // Retrieves style information about a family in a newly allocated GList. + GList* GetUIStyles(PangoFontFamily * in); /// Retrieve a font_instance from a style object, first trying to use the font-specification, the CSS information font_instance* FaceFromStyle(SPStyle const *style); @@ -146,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<Glib::ustring, PangoFontDescription *> PangoStringToDescrMap; - PangoStringToDescrMap fontInstanceMap; + // typedef std::map<Glib::ustring, PangoFontDescription *> 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<Glib::ustring, Glib::ustring> UIStringToPangoStringMap; - UIStringToPangoStringMap fontStringMap; + // typedef std::map<Glib::ustring, Glib::ustring> UIStringToPangoStringMap; + // UIStringToPangoStringMap fontStringMap; }; @@ -174,4 +186,4 @@ private: fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 6727cdda6..39c557cc6 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -1,9 +1,9 @@ #ifdef HAVE_CONFIG_H -# include <config.h> +#include <config.h> #endif -#include <gtkmm/treemodel.h> #include <gtkmm/liststore.h> +#include <gtkmm/treemodel.h> #include <libnrtype/font-instance.h> #include <libnrtype/TextWrapper.h> @@ -27,410 +27,432 @@ // CSS dictates that font family names are case insensitive. // This should really implement full Unicode case unfolding. -bool familyNamesAreEqual( const Glib::ustring &a, const Glib::ustring &b ) { +bool familyNamesAreEqual(const Glib::ustring &a, const Glib::ustring &b) +{ + return (a.casefold().compare(b.casefold()) == 0); +} - return( a.casefold().compare( b.casefold() ) == 0 ); +static const char* sp_font_family_get_name(PangoFontFamily* family) +{ + const char* name = pango_font_family_get_name(family); + if (strncmp(name, "Sans", 4) == 0 && strlen(name) == 4) + return "sans-serif"; + if (strncmp(name, "Serif", 5) == 0 && strlen(name) == 5) + return "serif"; + if (strncmp(name, "Monospace", 9) == 0 && strlen(name) == 9) + return "monospace"; + return name; } -namespace Inkscape +namespace Inkscape { + +FontLister::FontLister() { - FontLister::FontLister () - { - font_list_store = Gtk::ListStore::create (FontList); - font_list_store->freeze_notify(); - - FamilyToStylesMap familyStyleMap; - font_factory::Default()->GetUIFamiliesAndStyles(&familyStyleMap); - - // Grab the family names into a list and then sort them - std::list<Glib::ustring> familyList; - for (FamilyToStylesMap::iterator iter = familyStyleMap.begin(); - iter != familyStyleMap.end(); - ++iter) { - familyList.push_back((*iter).first); + font_list_store = Gtk::ListStore::create(FontList); + font_list_store->freeze_notify(); + + /* Create default styles for use when font-family is unknown on system. */ + default_styles = g_list_append(NULL, new StyleNames("Normal")); + default_styles = g_list_append(default_styles, new StyleNames("Italic")); + default_styles = g_list_append(default_styles, new StyleNames("Bold")); + default_styles = g_list_append(default_styles, new StyleNames("Bold Italic")); + + // Get sorted font families from Pango + std::vector<PangoFontFamily *> familyVector; + font_factory::Default()->GetUIFamilies(familyVector); + + // Traverse through the family names and set up the list store + for (size_t i = 0; i < familyVector.size(); ++i) { + const char* displayName = sp_font_family_get_name(familyVector[i]); + + if (displayName == 0 || *displayName == '\0') { + continue; } - familyList.sort(); - // Traverse through the family names and set up the list store (note that - // the styles list that are the map's values are already sorted) - while (!familyList.empty()) { - Glib::ustring familyName = familyList.front(); - familyList.pop_front(); - - if (!familyName.empty()) { - Gtk::TreeModel::iterator treeModelIter = font_list_store->append(); - //(*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup(familyName.c_str())); - (*treeModelIter)[FontList.family] = familyName; - - // Now go through the styles - GList *styles = NULL; - std::list<StyleNames> &styleStrings = familyStyleMap[familyName]; - for (std::list<StyleNames>::iterator it=styleStrings.begin(); - it != styleStrings.end(); - ++it) { - // Our own copy - StyleNames *copy = new StyleNames( *it ); - styles = g_list_append(styles, copy); - } - - (*treeModelIter)[FontList.styles] = styles; - (*treeModelIter)[FontList.onSystem] = true; - } + Glib::ustring familyName = displayName; + if (!familyName.empty()) { + Gtk::TreeModel::iterator treeModelIter = font_list_store->append(); + (*treeModelIter)[FontList.family] = familyName; + + // we don't set this now (too slow) but the style will be cached if the user + // ever decides to use this font + (*treeModelIter)[FontList.styles] = NULL; + // store the pango representation for generating the style + (*treeModelIter)[FontList.pango_family] = familyVector[i]; + (*treeModelIter)[FontList.onSystem] = true; } - current_family_row = 0; - current_family = "sans-serif"; - current_style = "Normal"; - current_fontspec = "sans-serif"; // Empty style -> Normal - current_fontspec_system = "Sans"; - - /* Create default styles for use when font-family is unknown on system. */ - default_styles = g_list_append( NULL, new StyleNames( "Normal" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Italic" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Bold" ) ); - default_styles = g_list_append( default_styles, new StyleNames( "Bold Italic" ) ); - - font_list_store->thaw_notify(); - - style_list_store = Gtk::ListStore::create (FontStyleList); - - // Initialize style store with defaults - style_list_store->freeze_notify(); - style_list_store->clear(); - for (GList *l=default_styles; l; l = l->next) { - Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; - (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; + } + + current_family_row = 0; + current_family = "sans-serif"; + current_style = "Normal"; + current_fontspec = "sans-serif"; // Empty style -> Normal + current_fontspec_system = "Sans"; + + font_list_store->thaw_notify(); + + style_list_store = Gtk::ListStore::create(FontStyleList); + + // Initialize style store with defaults + style_list_store->freeze_notify(); + style_list_store->clear(); + for (GList *l = default_styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)l->data)->DisplayName; + } + style_list_store->thaw_notify(); +} + +FontLister::~FontLister() +{ + // Delete default_styles + for (GList *l = default_styles; l; l = l->next) { + delete ((StyleNames *)l->data); + } + + // Delete other styles + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { + Gtk::TreeModel::Row row = *iter; + GList *styles = row[FontList.styles]; + for (GList *l = styles; l; l = l->next) { + delete ((StyleNames *)l->data); } - style_list_store->thaw_notify(); + ++iter; } +} - FontLister::~FontLister() { +FontLister *FontLister::get_instance() +{ + static Inkscape::FontLister *instance = new Inkscape::FontLister(); + return instance; +} - // Delete default_styles - for (GList *l=default_styles; l; l = l->next) { - delete ((StyleNames*)l->data); +void FontLister::ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iterator) +{ + Gtk::TreeIter iter(model, iterator); + Gtk::TreeModel::Row row = *iter; + if (!row[FontList.styles]) { + if (row[FontList.pango_family]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); } + } +} - // Delete other styles - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { - Gtk::TreeModel::Row row = *iter; - GList *styles = row[FontList.styles]; - for (GList *l=styles; l; l = l->next) { - delete ((StyleNames*)l->data); +// Example of how to use "foreach_iter" +// bool +// FontLister::print_document_font( const Gtk::TreeModel::iterator &iter ) { +// Gtk::TreeModel::Row row = *iter; +// if( !row[FontList.onSystem] ) { +// std::cout << " Not on system: " << row[FontList.family] << std::endl; +// return false; +// } +// return true; +// } +// font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); + +/* Used to insert a font that was not in the document and not on the system into the font list. */ +void FontLister::insert_font_family(Glib::ustring new_family) +{ + GList *styles = default_styles; + + /* In case this is a fallback list, check if first font-family on system. */ + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family); + if (!tokens.empty() && !tokens[0].empty()) { + Gtk::TreeModel::iterator iter2 = font_list_store->get_iter("0"); + while (iter2 != font_list_store->children().end()) { + Gtk::TreeModel::Row row = *iter2; + if (row[FontList.onSystem] && familyNamesAreEqual(tokens[0], row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + styles = row[FontList.styles]; + break; } - ++iter; + ++iter2; } } - // Example of how to use "foreach_iter" - // bool - // FontLister::print_document_font( const Gtk::TreeModel::iterator &iter ) { - // Gtk::TreeModel::Row row = *iter; - // if( !row[FontList.onSystem] ) { - // std::cout << " Not on system: " << row[FontList.family] << std::endl; - // return false; - // } - // return true; - // } - // font_list_store->foreach_iter( sigc::mem_fun(*this, &FontLister::print_document_font )); - - /* Used to insert a font that was not in the document and not on the system into the font list. */ - void - FontLister::insert_font_family( Glib::ustring new_family ) { - - GList *styles = default_styles; - - /* In case this is a fallback list, check if first font-family on system. */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", new_family ); - if( !tokens.empty() && !tokens[0].empty() ) { - - Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); - while( iter2 != font_list_store->children().end() ) { - Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { - styles = row[FontList.styles]; + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = new_family; + (*treeModelIter)[FontList.styles] = styles; + (*treeModelIter)[FontList.onSystem] = false; +} + +void FontLister::update_font_list(SPDocument *document) +{ + SPObject *r = document->getRoot(); + if (!r) { + return; + } + + font_list_store->freeze_notify(); + + /* Find if current row is in document or system part of list */ + gboolean row_is_system = false; + if (current_family_row > -1) { + Gtk::TreePath path; + path.push_back(current_family_row); + Gtk::TreeModel::iterator iter = font_list_store->get_iter(path); + if (iter) { + row_is_system = (*iter)[FontList.onSystem]; + // std::cout << " In: row: " << current_family_row << " " << (*iter)[FontList.family] << std::endl; + } + } + + /* Clear all old document font-family entries */ + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { + Gtk::TreeModel::Row row = *iter; + if (!row[FontList.onSystem]) { + // std::cout << " Not on system: " << row[FontList.family] << std::endl; + iter = font_list_store->erase(iter); + } else { + // std::cout << " First on system: " << row[FontList.family] << std::endl; break; - } - ++iter2; } - } + } + + /* Get "font-family"s used in document. */ + std::list<Glib::ustring> fontfamilies; + update_font_list_recursive(r, &fontfamilies); - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup(new_family.c_str())); - (*treeModelIter)[FontList.styles] = styles; - (*treeModelIter)[FontList.onSystem] = false; + fontfamilies.sort(); + fontfamilies.unique(); + fontfamilies.reverse(); + + + /* Insert separator */ + if (!fontfamilies.empty()) { + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = "#"; + (*treeModelIter)[FontList.onSystem] = false; } - void - FontLister::update_font_list( SPDocument* document ) { - - SPObject *r = document->getRoot(); - if( !r ) { - return; - } - - font_list_store->freeze_notify(); - - /* Find if current row is in document or system part of list */ - gboolean row_is_system = false; - if( current_family_row > -1 ) { - Gtk::TreePath path; - path.push_back( current_family_row ); - Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); - if( iter ) { - row_is_system = (*iter)[FontList.onSystem]; - // std::cout << " In: row: " << current_family_row << " " << (*iter)[FontList.family] << std::endl; - } - } - - /* Clear all old document font-family entries */ - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { - Gtk::TreeModel::Row row = *iter; - if( !row[FontList.onSystem] ) { - // std::cout << " Not on system: " << row[FontList.family] << std::endl; - iter = font_list_store->erase( iter ); - } else { - // std::cout << " First on system: " << row[FontList.family] << std::endl; - break; - } - } - - /* Get "font-family"s used in document. */ - std::list<Glib::ustring> fontfamilies; - update_font_list_recursive( r, &fontfamilies ); - - fontfamilies.sort(); - fontfamilies.unique(); - fontfamilies.reverse(); - - /* Insert separator */ - if( !fontfamilies.empty() ) { - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = "#"; - (*treeModelIter)[FontList.onSystem] = false; - } - - /* Insert font-family's in document. */ - std::list<Glib::ustring>::iterator i; - for( i = fontfamilies.begin(); i != fontfamilies.end(); ++i) { - - GList *styles = default_styles; + /* Insert font-family's in document. */ + std::list<Glib::ustring>::iterator i; + for (i = fontfamilies.begin(); i != fontfamilies.end(); ++i) { + + GList *styles = default_styles; /* See if font-family (or first in fallback list) is on system. If so, get styles. */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", *i ); - if( !tokens.empty() && !tokens[0].empty() ) { - - Gtk::TreeModel::iterator iter2 = font_list_store->get_iter( "0" ); - while( iter2 != font_list_store->children().end() ) { - Gtk::TreeModel::Row row = *iter2; - if( row[FontList.onSystem] && familyNamesAreEqual( tokens[0], row[FontList.family] ) ) { - styles = row[FontList.styles]; - break; - } - ++iter2; - } - } - - Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); - (*treeModelIter)[FontList.family] = reinterpret_cast<const char*>(g_strdup((*i).c_str())); - (*treeModelIter)[FontList.styles] = styles; - (*treeModelIter)[FontList.onSystem] = false; - } - - /* Now we do a song and dance to find the correct row as the row corresponding - * to the current_family may have changed. We can't simply search for the - * family name in the list since it can occur twice, once in the document - * font family part and once in the system font family part. Above we determined - * which part it is in. - */ - if( current_family_row > -1 ) { - int start = 0; - if( row_is_system ) start = fontfamilies.size(); - int length = font_list_store->children().size(); - for( int i = 0; i < length; ++i ) { - int row = i + start; - if( row >= length ) row -= length; - Gtk::TreePath path; - path.push_back( row ); - Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); - if( iter ) { - if( familyNamesAreEqual( current_family, (*iter)[FontList.family] ) ) { - current_family_row = row; - break; - } - } - } - } - // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; - - font_list_store->thaw_notify(); + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple(",", *i); + if (!tokens.empty() && !tokens[0].empty()) { + + Gtk::TreeModel::iterator iter2 = font_list_store->get_iter("0"); + while (iter2 != font_list_store->children().end()) { + Gtk::TreeModel::Row row = *iter2; + if (row[FontList.onSystem] && familyNamesAreEqual(tokens[0], row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + styles = row[FontList.styles]; + break; + } + ++iter2; + } + } + + Gtk::TreeModel::iterator treeModelIter = font_list_store->prepend(); + (*treeModelIter)[FontList.family] = reinterpret_cast<const char *>(g_strdup((*i).c_str())); + (*treeModelIter)[FontList.styles] = styles; + (*treeModelIter)[FontList.onSystem] = false; + } - void - FontLister::update_font_list_recursive( SPObject *r, std::list<Glib::ustring> *l ) { + /* Now we do a song and dance to find the correct row as the row corresponding + * to the current_family may have changed. We can't simply search for the + * family name in the list since it can occur twice, once in the document + * font family part and once in the system font family part. Above we determined + * which part it is in. + */ + if (current_family_row > -1) { + int start = 0; + if (row_is_system) + start = fontfamilies.size(); + int length = font_list_store->children().size(); + for (int i = 0; i < length; ++i) { + int row = i + start; + if (row >= length) + row -= length; + Gtk::TreePath path; + path.push_back(row); + Gtk::TreeModel::iterator iter = font_list_store->get_iter(path); + if (iter) { + if (familyNamesAreEqual(current_family, (*iter)[FontList.family])) { + current_family_row = row; + break; + } + } + } + } + // std::cout << " Out: row: " << current_family_row << " " << current_family << std::endl; - const gchar *font_family = r->style->font_family.value; - if( font_family ) { - l->push_back( Glib::ustring( font_family ) ); - } + font_list_store->thaw_notify(); +} - for (SPObject *child = r->firstChild(); child; child = child->getNext()) { - update_font_list_recursive( child, l ); - } +void FontLister::update_font_list_recursive(SPObject *r, std::list<Glib::ustring> *l) +{ + const gchar *font_family = r->style->font_family.value; + if (font_family) { + l->push_back(Glib::ustring(font_family)); } - Glib::ustring - FontLister::canonize_fontspec( Glib::ustring fontspec ) { - - // Pass fontspec to and back from Pango to get a the fontspec in - // canonical form. -inkscape-font-specification relies on the - // Pango constructed fontspec not changing form. If it does, - // this is the place to fix it. - PangoFontDescription *descr = pango_font_description_from_string( fontspec.c_str() ); - gchar* canonized = pango_font_description_to_string ( descr ); - Glib::ustring Canonized = canonized; - g_free( canonized ); - pango_font_description_free( descr ); - - // Pango canonized strings remove space after comma between family names. Put it back. - size_t i = 0; - while( (i = Canonized.find(",", i)) != std::string::npos) { - Canonized.replace(i, 1, ", "); - i += 2; - } - - return Canonized; + for (SPObject *child = r->firstChild(); child; child = child->getNext()) { + update_font_list_recursive(child, l); + } +} + +Glib::ustring FontLister::canonize_fontspec(Glib::ustring fontspec) +{ + + // Pass fontspec to and back from Pango to get a the fontspec in + // canonical form. -inkscape-font-specification relies on the + // Pango constructed fontspec not changing form. If it does, + // this is the place to fix it. + PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); + gchar *canonized = pango_font_description_to_string(descr); + Glib::ustring Canonized = canonized; + g_free(canonized); + pango_font_description_free(descr); + + // Pango canonized strings remove space after comma between family names. Put it back. + size_t i = 0; + while ((i = Canonized.find(",", i)) != std::string::npos) { + Canonized.replace(i, 1, ", "); + i += 2; } - Glib::ustring - FontLister::system_fontspec( Glib::ustring fontspec ) { + return Canonized; +} + +Glib::ustring FontLister::system_fontspec(Glib::ustring fontspec) +{ - // Find what Pango thinks is the closest match. - Glib::ustring out = fontspec; + // Find what Pango thinks is the closest match. + Glib::ustring out = fontspec; - PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); - font_instance *res = (font_factory::Default())->Face(descr); - if (res->pFont) { + PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); + font_instance *res = (font_factory::Default())->Face(descr); + if (res->pFont) { PangoFontDescription *nFaceDesc = pango_font_describe(res->pFont); out = sp_font_description_get_family(nFaceDesc); - } - pango_font_description_free(descr); - - return out; } + pango_font_description_free(descr); + + return out; +} - std::pair<Glib::ustring, Glib::ustring> - FontLister::ui_from_fontspec( Glib::ustring fontspec ) { - - PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); - const gchar* family = pango_font_description_get_family(descr); - if(!family) - family = "sans-serif"; - Glib::ustring Family = family; - - // PANGO BUG... - // A font spec of Delicious, 500 Italic should result in a family of 'Delicious' - // and a style of 'Medium Italic'. It results instead with: a family of - // 'Delicious, 500' with a style of 'Medium Italic'. We chop of any weight numbers - // at the end of the family: match ",[1-9]00^". - Glib::RefPtr<Glib::Regex> weight = Glib::Regex::create(",[1-9]00$"); - Family = weight->replace( Family, 0, "", Glib::REGEX_MATCH_PARTIAL ); - - // Pango canonized strings remove space after comma between family names. Put it back. - size_t i = 0; - while( (i = Family.find(",", i)) != std::string::npos) { - Family.replace(i, 1, ", "); - i += 2; - } - - pango_font_description_unset_fields(descr, PANGO_FONT_MASK_FAMILY); - gchar* style = pango_font_description_to_string( descr ); - Glib::ustring Style = style; - pango_font_description_free(descr); - g_free( style ); - - return std::make_pair( Family, Style ); +std::pair<Glib::ustring, Glib::ustring> FontLister::ui_from_fontspec(Glib::ustring fontspec) +{ + PangoFontDescription *descr = pango_font_description_from_string(fontspec.c_str()); + const gchar *family = pango_font_description_get_family(descr); + if (!family) + family = "sans-serif"; + Glib::ustring Family = family; + + // PANGO BUG... + // A font spec of Delicious, 500 Italic should result in a family of 'Delicious' + // and a style of 'Medium Italic'. It results instead with: a family of + // 'Delicious, 500' with a style of 'Medium Italic'. We chop of any weight numbers + // at the end of the family: match ",[1-9]00^". + Glib::RefPtr<Glib::Regex> weight = Glib::Regex::create(",[1-9]00$"); + Family = weight->replace(Family, 0, "", Glib::REGEX_MATCH_PARTIAL); + + // Pango canonized strings remove space after comma between family names. Put it back. + size_t i = 0; + while ((i = Family.find(",", i)) != std::string::npos) { + Family.replace(i, 1, ", "); + i += 2; } - std::pair<Glib::ustring, Glib::ustring> - FontLister::selection_update () { + pango_font_description_unset_fields(descr, PANGO_FONT_MASK_FAMILY); + gchar *style = pango_font_description_to_string(descr); + Glib::ustring Style = style; + pango_font_description_free(descr); + g_free(style); + + return std::make_pair(Family, Style); +} + +std::pair<Glib::ustring, Glib::ustring> FontLister::selection_update() +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::selection_update: entrance" << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::selection_update: entrance" << std::endl; #endif - // Get fontspec from a selection, preferences, or thin air. - Glib::ustring fontspec; - SPStyle *query = sp_style_new (SP_ACTIVE_DOCUMENT); - - // Directly from stored font specification. - int result = - sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); - - //std::cout << " Attempting selected style" << std::endl; - if( result != QUERY_STYLE_NOTHING && query->font_specification.set ) { - fontspec = query->font_specification.value; - //std::cout << " fontspec from query :" << fontspec << ":" << std::endl; - } - - // From style - if( fontspec.empty() ) { + // Get fontspec from a selection, preferences, or thin air. + Glib::ustring fontspec; + SPStyle *query = sp_style_new(SP_ACTIVE_DOCUMENT); + + // Directly from stored font specification. + int result = + sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION); + + //std::cout << " Attempting selected style" << std::endl; + if (result != QUERY_STYLE_NOTHING && query->font_specification.set) { + fontspec = query->font_specification.value; + //std::cout << " fontspec from query :" << fontspec << ":" << std::endl; + } + + // From style + if (fontspec.empty()) { //std::cout << " Attempting desktop style" << std::endl; - int rfamily = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); - int rstyle = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); - - // Must have text in selection - if( rfamily != QUERY_STYLE_NOTHING && rstyle != QUERY_STYLE_NOTHING ) { - fontspec = fontspec_from_style( query ); - } - //std::cout << " fontspec from style :" << fontspec << ":" << std::endl; - } - - // From preferences - if( fontspec.empty() ) { + int rfamily = sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); + int rstyle = sp_desktop_query_style(SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); + + // Must have text in selection + if (rfamily != QUERY_STYLE_NOTHING && rstyle != QUERY_STYLE_NOTHING) { + fontspec = fontspec_from_style(query); + } + //std::cout << " fontspec from style :" << fontspec << ":" << std::endl; + } + + // From preferences + if (fontspec.empty()) { //std::cout << " Attempting preferences" << std::endl; sp_style_read_from_prefs(query, "/tools/text"); - fontspec = fontspec_from_style( query ); - //std::cout << " fontspec from prefs :" << fontspec << ":" << std::endl; - } - sp_style_unref(query); + fontspec = fontspec_from_style(query); + //std::cout << " fontspec from prefs :" << fontspec << ":" << std::endl; + } + sp_style_unref(query); - // From thin air - if( fontspec.empty() ) { + // From thin air + if (fontspec.empty()) { //std::cout << " Attempting thin air" << std::endl; - fontspec = current_family + ", " + current_style; - //std::cout << " fontspec from thin air :" << fontspec << ":" << std::endl; - } - - // Do we really need? Removes spaces between font-families. - //current_fontspec = canonize_fontspec( fontspec ); - current_fontspec = fontspec; // Ignore for now + fontspec = current_family + ", " + current_style; + //std::cout << " fontspec from thin air :" << fontspec << ":" << std::endl; + } - current_fontspec_system = system_fontspec( current_fontspec ); + // Do we really need? Removes spaces between font-families. + //current_fontspec = canonize_fontspec( fontspec ); + current_fontspec = fontspec; // Ignore for now - std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec( current_fontspec ); - set_font_family( ui.first ); - set_font_style( ui.second ); + current_fontspec_system = system_fontspec(current_fontspec); + + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(current_fontspec); + set_font_family(ui.first); + set_font_style(ui.second); #ifdef DEBUG_FONT - std::cout << " family_row: :" << current_family_row << ":" << std::endl; - std::cout << " canonized: :" << current_fontspec << ":" << std::endl; - std::cout << " system: :" << current_fontspec_system << ":" << std::endl; - std::cout << " family: :" << current_family << ":" << std::endl; - std::cout << " style: :" << current_style << ":" << std::endl; - std::cout << "FontLister::selection_update: exit" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << " family_row: :" << current_family_row << ":" << std::endl; + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: :" << current_family << ":" << std::endl; + std::cout << " style: :" << current_style << ":" << std::endl; + std::cout << "FontLister::selection_update: exit" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return std::make_pair( current_family, current_style ); - } - + return std::make_pair(current_family, current_style); +} + // Set fontspec. If check is false, best style match will not be done. -void FontLister::set_fontspec(Glib::ustring new_fontspec, gboolean /*check*/) +void FontLister::set_fontspec(Glib::ustring new_fontspec, bool /*check*/) { - std::pair<Glib::ustring,Glib::ustring> ui = ui_from_fontspec( new_fontspec ); + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(new_fontspec); Glib::ustring new_family = ui.first; Glib::ustring new_style = ui.second; @@ -439,13 +461,13 @@ void FontLister::set_fontspec(Glib::ustring new_fontspec, gboolean /*check*/) << " style:" << new_style << std::endl; #endif - set_font_family( new_family, false ); - set_font_style( new_style ); + set_font_family(new_family, false); + set_font_style(new_style); } // TODO: use to determine font-selector best style -std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustring new_family, gboolean /*check_style*/ ) +std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family(Glib::ustring new_family, bool /*check_style*/) { #ifdef DEBUG_FONT std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; @@ -453,12 +475,12 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri #endif // No need to do anything if new family is same as old family. - if ( familyNamesAreEqual( new_family, current_family ) ) { + if (familyNamesAreEqual(new_family, current_family)) { #ifdef DEBUG_FONT - std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << "FontLister::new_font_family: exit: no change in family." << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return std::make_pair( current_family, current_style ); + return std::make_pair(current_family, current_style); } // We need to do two things: @@ -466,601 +488,602 @@ std::pair<Glib::ustring, Glib::ustring> FontLister::new_font_family (Glib::ustri // 2. Select best valid style match to old style. // For finding style list, use list of first family in font-family list. - GList* styles = NULL; - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { + GList *styles = NULL; + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { - Gtk::TreeModel::Row row = *iter; + Gtk::TreeModel::Row row = *iter; - if( familyNamesAreEqual( new_family, row[FontList.family] ) ) { + if (familyNamesAreEqual(new_family, row[FontList.family])) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } styles = row[FontList.styles]; break; - } - ++iter; + } + ++iter; } // Newly typed in font-family may not yet be in list... use default list. // TODO: if font-family is list, check if first family in list is on system // and set style accordingly. - if( styles == NULL ) { - styles = default_styles; + if (styles == NULL) { + styles = default_styles; } - + // Update style list. style_list_store->freeze_notify(); style_list_store->clear(); - for (GList *l=styles; l; l = l->next) { - Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); - (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames*)l->data)->CssName; - (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames*)l->data)->DisplayName; + for (GList *l = styles; l; l = l->next) { + Gtk::TreeModel::iterator treeModelIter = style_list_store->append(); + (*treeModelIter)[FontStyleList.cssStyle] = ((StyleNames *)l->data)->CssName; + (*treeModelIter)[FontStyleList.displayStyle] = ((StyleNames *)l->data)->DisplayName; } style_list_store->thaw_notify(); - + // Find best match to the style from the old font-family to the // styles available with the new font. // TODO: Maybe check if an exact match exists before using Pango. - Glib::ustring best_style = get_best_style_match( new_family, current_style ); + Glib::ustring best_style = get_best_style_match(new_family, current_style); #ifdef DEBUG_FONT std::cout << "FontLister::new_font_family: exit: " << new_family << " " << best_style << std::endl; std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return std::make_pair( new_family, best_style ); + return std::make_pair(new_family, best_style); } - - std::pair<Glib::ustring, Glib::ustring> - FontLister::set_font_family (Glib::ustring new_family, gboolean check_style) { + +std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(Glib::ustring new_family, bool check_style) +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::set_font_family: " << new_family << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::set_font_family: " << new_family << std::endl; #endif - std::pair<Glib::ustring, Glib::ustring> ui = new_font_family( new_family, check_style ); - current_family = ui.first; - current_style = ui.second; - current_fontspec = canonize_fontspec( current_family + ", " + current_style ); - current_fontspec_system = system_fontspec( current_fontspec ); + std::pair<Glib::ustring, Glib::ustring> ui = new_font_family(new_family, check_style); + current_family = ui.first; + current_style = ui.second; + current_fontspec = canonize_fontspec(current_family + ", " + current_style); + current_fontspec_system = system_fontspec(current_fontspec); #ifdef DEBUG_FONT - std::cout << " family_row: :" << current_family_row << ":" << std::endl; - std::cout << " canonized: :" << current_fontspec << ":" << std::endl; - std::cout << " system: :" << current_fontspec_system << ":" << std::endl; - std::cout << " family: :" << current_family << ":" << std::endl; - std::cout << " style: :" << current_style << ":" << std::endl; - std::cout << "FontLister::set_font_family: end" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << " family_row: :" << current_family_row << ":" << std::endl; + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: :" << current_family << ":" << std::endl; + std::cout << " style: :" << current_style << ":" << std::endl; + std::cout << "FontLister::set_font_family: end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return ui; - } - + return ui; +} + - std::pair<Glib::ustring, Glib::ustring> - FontLister::set_font_family (int row, gboolean check_style) { +std::pair<Glib::ustring, Glib::ustring> FontLister::set_font_family(int row, bool check_style) +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::set_font_family( row ): " << row << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::set_font_family( row ): " << row << std::endl; #endif - current_family_row = row; - Gtk::TreePath path; - path.push_back( row ); - Glib::ustring new_family = current_family; - Gtk::TreeModel::iterator iter = font_list_store->get_iter( path ); - if( iter ) { - new_family = (*iter)[FontList.family]; - } + current_family_row = row; + Gtk::TreePath path; + path.push_back(row); + Glib::ustring new_family = current_family; + Gtk::TreeModel::iterator iter = font_list_store->get_iter(path); + if (iter) { + new_family = (*iter)[FontList.family]; + } - std::pair<Glib::ustring, Glib::ustring> ui = set_font_family( new_family, check_style ); + std::pair<Glib::ustring, Glib::ustring> ui = set_font_family(new_family, check_style); #ifdef DEBUG_FONT - std::cout << "FontLister::set_font_family( row ): end" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << "FontLister::set_font_family( row ): end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return ui; - } + return ui; +} - void - FontLister::set_font_style (Glib::ustring new_style) { +void FontLister::set_font_style(Glib::ustring new_style) +{ - // TODO: Validate input using Pango. If Pango doesn't recognize a style it will - // attach the "invalid" style to the font-family. +// TODO: Validate input using Pango. If Pango doesn't recognize a style it will +// attach the "invalid" style to the font-family. #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister:set_font_style: " << new_style << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister:set_font_style: " << new_style << std::endl; #endif - current_style = new_style; - current_fontspec = canonize_fontspec( current_family + ", " + current_style ); - current_fontspec_system = system_fontspec( current_fontspec ); + current_style = new_style; + current_fontspec = canonize_fontspec(current_family + ", " + current_style); + current_fontspec_system = system_fontspec(current_fontspec); #ifdef DEBUG_FONT - std::cout << " canonized: :" << current_fontspec << ":" << std::endl; - std::cout << " system: :" << current_fontspec_system << ":" << std::endl; - std::cout << " family: " << current_family << std::endl; - std::cout << " style: " << current_style << std::endl; - std::cout << "FontLister::set_font_style: end" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << " canonized: :" << current_fontspec << ":" << std::endl; + std::cout << " system: :" << current_fontspec_system << ":" << std::endl; + std::cout << " family: " << current_family << std::endl; + std::cout << " style: " << current_style << std::endl; + std::cout << "FontLister::set_font_style: end" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - } +} - // We do this ourselves as we can't rely on FontFactory. - void - FontLister::fill_css( SPCSSAttr *css, Glib::ustring fontspec ) { +// We do this ourselves as we can't rely on FontFactory. +void FontLister::fill_css(SPCSSAttr *css, Glib::ustring fontspec) +{ - if( fontspec.empty() ) { - fontspec = current_fontspec; - } - std::pair<Glib::ustring,Glib::ustring> ui = ui_from_fontspec( fontspec ); + if (fontspec.empty()) { + fontspec = current_fontspec; + } + std::pair<Glib::ustring, Glib::ustring> ui = ui_from_fontspec(fontspec); - Glib::ustring family = ui.first; + Glib::ustring family = ui.first; - // Font spec is single quoted... for the moment - Glib::ustring fontspec_quoted( fontspec ); - css_quote( fontspec_quoted ); - sp_repr_css_set_property (css, "-inkscape-font-specification", fontspec_quoted.c_str() ); + // Font spec is single quoted... for the moment + Glib::ustring fontspec_quoted(fontspec); + css_quote(fontspec_quoted); + sp_repr_css_set_property(css, "-inkscape-font-specification", fontspec_quoted.c_str()); - // Font families needs to be properly quoted in CSS (used unquoted in font-lister) - css_font_family_quote( family ); - sp_repr_css_set_property (css, "font-family", family.c_str() ); + // Font families needs to be properly quoted in CSS (used unquoted in font-lister) + css_font_family_quote(family); + sp_repr_css_set_property(css, "font-family", family.c_str()); - PangoFontDescription *desc = pango_font_description_from_string( fontspec.c_str() ); - PangoWeight weight = pango_font_description_get_weight( desc ); - switch ( weight ) { - case PANGO_WEIGHT_THIN: - sp_repr_css_set_property (css, "font-weight", "100" ); - break; - case PANGO_WEIGHT_ULTRALIGHT: - sp_repr_css_set_property (css, "font-weight", "200" ); - break; - case PANGO_WEIGHT_LIGHT: - sp_repr_css_set_property (css, "font-weight", "300" ); - break; + PangoFontDescription *desc = pango_font_description_from_string(fontspec.c_str()); + PangoWeight weight = pango_font_description_get_weight(desc); + switch (weight) { + case PANGO_WEIGHT_THIN: + sp_repr_css_set_property(css, "font-weight", "100"); + break; + case PANGO_WEIGHT_ULTRALIGHT: + sp_repr_css_set_property(css, "font-weight", "200"); + break; + case PANGO_WEIGHT_LIGHT: + sp_repr_css_set_property(css, "font-weight", "300"); + break; #if PANGO_VERSION_CHECK(1,36,6) - case PANGO_WEIGHT_SEMILIGHT: - sp_repr_css_set_property (css, "font-weight", "350" ); - break; + case PANGO_WEIGHT_SEMILIGHT: + sp_repr_css_set_property (css, "font-weight", "350"); + break; #endif - case PANGO_WEIGHT_BOOK: - sp_repr_css_set_property (css, "font-weight", "380" ); - break; - case PANGO_WEIGHT_NORMAL: - sp_repr_css_set_property (css, "font-weight", "normal" ); - break; - case PANGO_WEIGHT_MEDIUM: - sp_repr_css_set_property (css, "font-weight", "500" ); - break; - case PANGO_WEIGHT_SEMIBOLD: - sp_repr_css_set_property (css, "font-weight", "600" ); - break; - case PANGO_WEIGHT_BOLD: - sp_repr_css_set_property (css, "font-weight", "bold" ); - break; - case PANGO_WEIGHT_ULTRABOLD: - sp_repr_css_set_property (css, "font-weight", "800" ); - break; - case PANGO_WEIGHT_HEAVY: - sp_repr_css_set_property (css, "font-weight", "900" ); - break; - case PANGO_WEIGHT_ULTRAHEAVY: - sp_repr_css_set_property (css, "font-weight", "1000" ); - break; - } - - PangoStyle style = pango_font_description_get_style( desc ); - switch ( style ) { - case PANGO_STYLE_NORMAL: - sp_repr_css_set_property (css, "font-style", "normal" ); - break; - case PANGO_STYLE_OBLIQUE: - sp_repr_css_set_property (css, "font-style", "oblique" ); - break; - case PANGO_STYLE_ITALIC: - sp_repr_css_set_property (css, "font-style", "italic" ); - break; - } - - PangoStretch stretch = pango_font_description_get_stretch( desc ); - switch ( stretch ) { - case PANGO_STRETCH_ULTRA_CONDENSED: - sp_repr_css_set_property (css, "font-stretch", "ultra-condensed" ); - break; - case PANGO_STRETCH_EXTRA_CONDENSED: - sp_repr_css_set_property (css, "font-stretch", "extra-condensed" ); - break; - case PANGO_STRETCH_CONDENSED: - sp_repr_css_set_property (css, "font-stretch", "condensed" ); - break; - case PANGO_STRETCH_SEMI_CONDENSED: - sp_repr_css_set_property (css, "font-stretch", "semi-condensed" ); - break; - case PANGO_STRETCH_NORMAL: - sp_repr_css_set_property (css, "font-stretch", "normal" ); - break; - case PANGO_STRETCH_SEMI_EXPANDED: - sp_repr_css_set_property (css, "font-stretch", "semi-expanded" ); - break; - case PANGO_STRETCH_EXPANDED: - sp_repr_css_set_property (css, "font-stretch", "expanded" ); - break; - case PANGO_STRETCH_EXTRA_EXPANDED: - sp_repr_css_set_property (css, "font-stretch", "extra-expanded" ); - break; - case PANGO_STRETCH_ULTRA_EXPANDED: - sp_repr_css_set_property (css, "font-stretch", "ultra-expanded" ); - break; - } - - PangoVariant variant = pango_font_description_get_variant( desc ); - switch ( variant ) { - case PANGO_VARIANT_NORMAL: - sp_repr_css_set_property (css, "font-variant", "normal" ); - break; - case PANGO_VARIANT_SMALL_CAPS: - sp_repr_css_set_property (css, "font-variant", "small-caps" ); - break; - } + case PANGO_WEIGHT_BOOK: + sp_repr_css_set_property(css, "font-weight", "380"); + break; + case PANGO_WEIGHT_NORMAL: + sp_repr_css_set_property(css, "font-weight", "normal"); + break; + case PANGO_WEIGHT_MEDIUM: + sp_repr_css_set_property(css, "font-weight", "500"); + break; + case PANGO_WEIGHT_SEMIBOLD: + sp_repr_css_set_property(css, "font-weight", "600"); + break; + case PANGO_WEIGHT_BOLD: + sp_repr_css_set_property(css, "font-weight", "bold"); + break; + case PANGO_WEIGHT_ULTRABOLD: + sp_repr_css_set_property(css, "font-weight", "800"); + break; + case PANGO_WEIGHT_HEAVY: + sp_repr_css_set_property(css, "font-weight", "900"); + break; + case PANGO_WEIGHT_ULTRAHEAVY: + sp_repr_css_set_property(css, "font-weight", "1000"); + break; } - // We do this ourselves as we can't rely on FontFactory. - Glib::ustring - FontLister::fontspec_from_style (SPStyle* style) { + PangoStyle style = pango_font_description_get_style(desc); + switch (style) { + case PANGO_STYLE_NORMAL: + sp_repr_css_set_property(css, "font-style", "normal"); + break; + case PANGO_STYLE_OBLIQUE: + sp_repr_css_set_property(css, "font-style", "oblique"); + break; + case PANGO_STYLE_ITALIC: + sp_repr_css_set_property(css, "font-style", "italic"); + break; + } + + PangoStretch stretch = pango_font_description_get_stretch(desc); + switch (stretch) { + case PANGO_STRETCH_ULTRA_CONDENSED: + sp_repr_css_set_property(css, "font-stretch", "ultra-condensed"); + break; + case PANGO_STRETCH_EXTRA_CONDENSED: + sp_repr_css_set_property(css, "font-stretch", "extra-condensed"); + break; + case PANGO_STRETCH_CONDENSED: + sp_repr_css_set_property(css, "font-stretch", "condensed"); + break; + case PANGO_STRETCH_SEMI_CONDENSED: + sp_repr_css_set_property(css, "font-stretch", "semi-condensed"); + break; + case PANGO_STRETCH_NORMAL: + sp_repr_css_set_property(css, "font-stretch", "normal"); + break; + case PANGO_STRETCH_SEMI_EXPANDED: + sp_repr_css_set_property(css, "font-stretch", "semi-expanded"); + break; + case PANGO_STRETCH_EXPANDED: + sp_repr_css_set_property(css, "font-stretch", "expanded"); + break; + case PANGO_STRETCH_EXTRA_EXPANDED: + sp_repr_css_set_property(css, "font-stretch", "extra-expanded"); + break; + case PANGO_STRETCH_ULTRA_EXPANDED: + sp_repr_css_set_property(css, "font-stretch", "ultra-expanded"); + break; + } + + PangoVariant variant = pango_font_description_get_variant(desc); + switch (variant) { + case PANGO_VARIANT_NORMAL: + sp_repr_css_set_property(css, "font-variant", "normal"); + break; + case PANGO_VARIANT_SMALL_CAPS: + sp_repr_css_set_property(css, "font-variant", "small-caps"); + break; + } +} - //std::cout << "FontLister:fontspec_from_style: " << std::endl; +// We do this ourselves as we can't rely on FontFactory. +Glib::ustring FontLister::fontspec_from_style(SPStyle *style) +{ + + //std::cout << "FontLister:fontspec_from_style: " << std::endl; - Glib::ustring fontspec; - if (style) { + Glib::ustring fontspec; + if (style) { - // First try to use the font specification if it is set - if (style->font_specification.set - && style->font_specification.value - && *style->font_specification.value) { + // First try to use the font specification if it is set + if (style->font_specification.set && style->font_specification.value && *style->font_specification.value) { - fontspec = style->font_specification.value; + fontspec = style->font_specification.value; } else { - fontspec = style->font_family.value; - fontspec += ","; - - // Use weight names as defined by Pango - switch (style->font_weight.computed) { + fontspec = style->font_family.value; + fontspec += ","; - case SP_CSS_FONT_WEIGHT_100: - fontspec += " Thin"; - break; - - case SP_CSS_FONT_WEIGHT_200: - fontspec += " Ultra-Light"; - break; + // Use weight names as defined by Pango + switch (style->font_weight.computed) { - case SP_CSS_FONT_WEIGHT_300: - fontspec += " Light"; - break; + case SP_CSS_FONT_WEIGHT_100: + fontspec += " Thin"; + break; - case SP_CSS_FONT_WEIGHT_400: - case SP_CSS_FONT_WEIGHT_NORMAL: - //fontspec += " normal"; - break; - - case SP_CSS_FONT_WEIGHT_500: - fontspec += " Medium"; - break; - - case SP_CSS_FONT_WEIGHT_600: - fontspec += " Semi-Bold"; - break; - - case SP_CSS_FONT_WEIGHT_700: - case SP_CSS_FONT_WEIGHT_BOLD: - fontspec += " Bold"; - break; - - case SP_CSS_FONT_WEIGHT_800: - fontspec += " Ultra-Bold"; - break; - - case SP_CSS_FONT_WEIGHT_900: - fontspec += " Heavy"; - break; - - case SP_CSS_FONT_WEIGHT_LIGHTER: - case SP_CSS_FONT_WEIGHT_BOLDER: - default: - g_warning("Unrecognized font_weight.computed value"); - break; - } - - switch (style->font_style.computed) { - case SP_CSS_FONT_STYLE_ITALIC: - fontspec += " italic"; - break; - - case SP_CSS_FONT_STYLE_OBLIQUE: - fontspec += " oblique"; - break; - - case SP_CSS_FONT_STYLE_NORMAL: - default: - //fontspec += " normal"; - break; - } - - switch (style->font_stretch.computed) { - - case SP_CSS_FONT_STRETCH_ULTRA_CONDENSED: - fontspec += " ultra-condensed"; - break; - - case SP_CSS_FONT_STRETCH_EXTRA_CONDENSED: - fontspec += " extra-condensed"; - break; - - case SP_CSS_FONT_STRETCH_CONDENSED: - case SP_CSS_FONT_STRETCH_NARROWER: - fontspec += " condensed"; - break; - - case SP_CSS_FONT_STRETCH_SEMI_CONDENSED: - fontspec += " semi-condensed"; - break; - - case SP_CSS_FONT_STRETCH_NORMAL: - //fontspec += " normal"; - break; - - case SP_CSS_FONT_STRETCH_SEMI_EXPANDED: - fontspec += " semi-expanded"; - break; - - case SP_CSS_FONT_STRETCH_EXPANDED: - case SP_CSS_FONT_STRETCH_WIDER: - fontspec += " expanded"; - break; - - case SP_CSS_FONT_STRETCH_EXTRA_EXPANDED: - fontspec += " extra-expanded"; - break; - - case SP_CSS_FONT_STRETCH_ULTRA_EXPANDED: - fontspec += " ultra-expanded"; - break; - - default: - //fontspec += " normal"; - break; - } - - switch (style->font_variant.computed) { - - case SP_CSS_FONT_VARIANT_SMALL_CAPS: - fontspec += "small-caps"; - break; - - default: - //fontspec += "normal"; - break; - } - } - } - return canonize_fontspec( fontspec ); - } + case SP_CSS_FONT_WEIGHT_200: + fontspec += " Ultra-Light"; + break; + case SP_CSS_FONT_WEIGHT_300: + fontspec += " Light"; + break; - Gtk::TreeModel::Row - FontLister::get_row_for_font (Glib::ustring family) - { - Gtk::TreePath path; + case SP_CSS_FONT_WEIGHT_400: + case SP_CSS_FONT_WEIGHT_NORMAL: + //fontspec += " normal"; + break; - Gtk::TreeModel::iterator iter = font_list_store->get_iter( "0" ); - while( iter != font_list_store->children().end() ) { + case SP_CSS_FONT_WEIGHT_500: + fontspec += " Medium"; + break; - Gtk::TreeModel::Row row = *iter; + case SP_CSS_FONT_WEIGHT_600: + fontspec += " Semi-Bold"; + break; - if( familyNamesAreEqual( family, row[FontList.family] ) ) { - return row; - } + case SP_CSS_FONT_WEIGHT_700: + case SP_CSS_FONT_WEIGHT_BOLD: + fontspec += " Bold"; + break; - ++iter; - } + case SP_CSS_FONT_WEIGHT_800: + fontspec += " Ultra-Bold"; + break; - throw FAMILY_NOT_FOUND; - } + case SP_CSS_FONT_WEIGHT_900: + fontspec += " Heavy"; + break; - Gtk::TreePath - FontLister::get_path_for_font (Glib::ustring family) - { - return font_list_store->get_path( get_row_for_font ( family ) ); + case SP_CSS_FONT_WEIGHT_LIGHTER: + case SP_CSS_FONT_WEIGHT_BOLDER: + default: + g_warning("Unrecognized font_weight.computed value"); + break; + } + + switch (style->font_style.computed) { + case SP_CSS_FONT_STYLE_ITALIC: + fontspec += " italic"; + break; + + case SP_CSS_FONT_STYLE_OBLIQUE: + fontspec += " oblique"; + break; + + case SP_CSS_FONT_STYLE_NORMAL: + default: + //fontspec += " normal"; + break; + } + + switch (style->font_stretch.computed) { + + case SP_CSS_FONT_STRETCH_ULTRA_CONDENSED: + fontspec += " ultra-condensed"; + break; + + case SP_CSS_FONT_STRETCH_EXTRA_CONDENSED: + fontspec += " extra-condensed"; + break; + + case SP_CSS_FONT_STRETCH_CONDENSED: + case SP_CSS_FONT_STRETCH_NARROWER: + fontspec += " condensed"; + break; + + case SP_CSS_FONT_STRETCH_SEMI_CONDENSED: + fontspec += " semi-condensed"; + break; + + case SP_CSS_FONT_STRETCH_NORMAL: + //fontspec += " normal"; + break; + + case SP_CSS_FONT_STRETCH_SEMI_EXPANDED: + fontspec += " semi-expanded"; + break; + + case SP_CSS_FONT_STRETCH_EXPANDED: + case SP_CSS_FONT_STRETCH_WIDER: + fontspec += " expanded"; + break; + + case SP_CSS_FONT_STRETCH_EXTRA_EXPANDED: + fontspec += " extra-expanded"; + break; + + case SP_CSS_FONT_STRETCH_ULTRA_EXPANDED: + fontspec += " ultra-expanded"; + break; + + default: + //fontspec += " normal"; + break; + } + + switch (style->font_variant.computed) { + + case SP_CSS_FONT_VARIANT_SMALL_CAPS: + fontspec += "small-caps"; + break; + + default: + //fontspec += "normal"; + break; + } + } } + return canonize_fontspec(fontspec); +} - Gtk::TreeModel::Row - FontLister::get_row_for_style (Glib::ustring style) - { - Gtk::TreePath path; - Gtk::TreeModel::iterator iter = style_list_store->get_iter( "0" ); - while( iter != style_list_store->children().end() ) { +Gtk::TreeModel::Row FontLister::get_row_for_font(Glib::ustring family) +{ + Gtk::TreePath path; - Gtk::TreeModel::Row row = *iter; + Gtk::TreeModel::iterator iter = font_list_store->get_iter("0"); + while (iter != font_list_store->children().end()) { - if( familyNamesAreEqual( style, row[FontStyleList.cssStyle] ) ) { - return row; - } + Gtk::TreeModel::Row row = *iter; - ++iter; - } + if (familyNamesAreEqual(family, row[FontList.family])) { + return row; + } - throw STYLE_NOT_FOUND; + ++iter; } - static gint - compute_distance (const PangoFontDescription *a, - const PangoFontDescription *b ) { - - // Weight: multiples of 100 - gint distance = abs( pango_font_description_get_weight( a ) - - pango_font_description_get_weight( b ) ); - - distance += 10000 * abs( pango_font_description_get_stretch( a ) - - pango_font_description_get_stretch( b ) ); - - PangoStyle style_a = pango_font_description_get_style( a ); - PangoStyle style_b = pango_font_description_get_style( b ); - if( style_a != style_b ) { - if( (style_a == PANGO_STYLE_OBLIQUE && style_b == PANGO_STYLE_ITALIC) || - (style_b == PANGO_STYLE_OBLIQUE && style_a == PANGO_STYLE_ITALIC) ) { - distance += 1000; // Oblique and italic are almost the same - } else { - distance += 100000; // Normal vs oblique/italic, not so similar - } - } - - // Normal vs small-caps - distance += 1000000 * abs( pango_font_description_get_variant( a ) - - pango_font_description_get_variant( b ) ); - return distance; + throw FAMILY_NOT_FOUND; +} + +Gtk::TreePath FontLister::get_path_for_font(Glib::ustring family) +{ + return font_list_store->get_path(get_row_for_font(family)); +} + +Gtk::TreeModel::Row FontLister::get_row_for_style(Glib::ustring style) +{ + Gtk::TreePath path; + + Gtk::TreeModel::iterator iter = style_list_store->get_iter("0"); + while (iter != style_list_store->children().end()) { + + Gtk::TreeModel::Row row = *iter; + + if (familyNamesAreEqual(style, row[FontStyleList.cssStyle])) { + return row; + } + + ++iter; } - // This is inspired by pango_font_description_better_match, but that routine - // always returns false if variant or stretch are different. This means, for - // example, that PT Sans Narrow with style Bold Condensed is never matched - // to another font-family with Bold style. - gboolean - font_description_better_match( PangoFontDescription* target, - PangoFontDescription* old_desc, - PangoFontDescription* new_desc ) { + throw STYLE_NOT_FOUND; +} + +static gint compute_distance(const PangoFontDescription *a, const PangoFontDescription *b) +{ - if( old_desc == NULL ) return true; - if( new_desc == NULL ) return false; + // Weight: multiples of 100 + gint distance = abs(pango_font_description_get_weight(a) - + pango_font_description_get_weight(b)); - int old_distance = compute_distance( target, old_desc ); - int new_distance = compute_distance( target, new_desc ); - //std::cout << "font_description_better_match: old: " << old_distance << std::endl; - //std::cout << " new: " << new_distance << std::endl; + distance += 10000 * abs(pango_font_description_get_stretch(a) - + pango_font_description_get_stretch(b)); - return (new_distance < old_distance ); + PangoStyle style_a = pango_font_description_get_style(a); + PangoStyle style_b = pango_font_description_get_style(b); + if (style_a != style_b) { + if ((style_a == PANGO_STYLE_OBLIQUE && style_b == PANGO_STYLE_ITALIC) || + (style_b == PANGO_STYLE_OBLIQUE && style_a == PANGO_STYLE_ITALIC)) { + distance += 1000; // Oblique and italic are almost the same + } else { + distance += 100000; // Normal vs oblique/italic, not so similar + } } - // void - // font_description_dump( PangoFontDescription* target ) { - // std::cout << " Font: " << pango_font_description_to_string( target ) << std::endl; - // std::cout << " style: " << pango_font_description_get_style( target ) << std::endl; - // std::cout << " weight: " << pango_font_description_get_weight( target ) << std::endl; - // std::cout << " variant: " << pango_font_description_get_variant( target ) << std::endl; - // std::cout << " stretch: " << pango_font_description_get_stretch( target ) << std::endl; - // std::cout << " gravity: " << pango_font_description_get_gravity( target ) << std::endl; - // } - - /* Returns style string */ - // TODO: Remove or turn into function to be used by new_font_family. - Glib::ustring - FontLister::get_best_style_match (Glib::ustring family, Glib::ustring target_style) { + // Normal vs small-caps + distance += 1000000 * abs(pango_font_description_get_variant(a) - + pango_font_description_get_variant(b)); + return distance; +} + +// This is inspired by pango_font_description_better_match, but that routine +// always returns false if variant or stretch are different. This means, for +// example, that PT Sans Narrow with style Bold Condensed is never matched +// to another font-family with Bold style. +gboolean font_description_better_match(PangoFontDescription *target, PangoFontDescription *old_desc, PangoFontDescription *new_desc) +{ + if (old_desc == NULL) + return true; + if (new_desc == NULL) + return false; + + int old_distance = compute_distance(target, old_desc); + int new_distance = compute_distance(target, new_desc); + //std::cout << "font_description_better_match: old: " << old_distance << std::endl; + //std::cout << " new: " << new_distance << std::endl; + + return (new_distance < old_distance); +} + +// void +// font_description_dump( PangoFontDescription* target ) { +// std::cout << " Font: " << pango_font_description_to_string( target ) << std::endl; +// std::cout << " style: " << pango_font_description_get_style( target ) << std::endl; +// std::cout << " weight: " << pango_font_description_get_weight( target ) << std::endl; +// std::cout << " variant: " << pango_font_description_get_variant( target ) << std::endl; +// std::cout << " stretch: " << pango_font_description_get_stretch( target ) << std::endl; +// std::cout << " gravity: " << pango_font_description_get_gravity( target ) << std::endl; +// } + +/* Returns style string */ +// TODO: Remove or turn into function to be used by new_font_family. +Glib::ustring FontLister::get_best_style_match(Glib::ustring family, Glib::ustring target_style) +{ #ifdef DEBUG_FONT - std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; - std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; + std::cout << "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl; + std::cout << "FontLister::get_best_style_match: " << family << " : " << target_style << std::endl; #endif - Glib::ustring fontspec = family + ", " + target_style; + Glib::ustring fontspec = family + ", " + target_style; - Gtk::TreeModel::Row row; - try { - row = get_row_for_font( family ); - } catch (...) { - //std::cout << " ERROR: can't find family: " << family << std::endl; - return (target_style); - } + Gtk::TreeModel::Row row; + try + { + row = get_row_for_font(family); + } + catch (...) + { + //std::cout << " ERROR: can't find family: " << family << std::endl; + return (target_style); + } - PangoFontDescription* target = pango_font_description_from_string( fontspec.c_str() ); - PangoFontDescription* best = NULL; + PangoFontDescription *target = pango_font_description_from_string(fontspec.c_str()); + PangoFontDescription *best = NULL; - //font_description_dump( target ); + //font_description_dump( target ); - GList* styles = row[FontList.styles]; - for (GList *l=styles; l; l = l->next) { + if (!row[FontList.styles]) { + row[FontList.styles] = font_factory::Default()->GetUIStyles(row[FontList.pango_family]); + } + GList *styles = row[FontList.styles]; + for (GList *l = styles; l; l = l->next) { Glib::ustring fontspec = family + ", " + ((StyleNames *)l->data)->CssName; - PangoFontDescription* candidate = pango_font_description_from_string( fontspec.c_str() ); - //font_description_dump( candidate ); - //std::cout << " " << font_description_better_match( target, best, candidate ) << std::endl; - if( font_description_better_match( target, best, candidate ) ) { - pango_font_description_free( best ); - best = candidate; - //std::cout << " ... better: " << std::endl; - } else { - pango_font_description_free( candidate ); - //std::cout << " ... not better: " << std::endl; - } - } - - Glib::ustring best_style = target_style; - if( best ) { - pango_font_description_unset_fields( best, PANGO_FONT_MASK_FAMILY ); - best_style = pango_font_description_to_string( best ); - } - - if( target ) pango_font_description_free( target ); - if( best ) pango_font_description_free( best ); + PangoFontDescription *candidate = pango_font_description_from_string(fontspec.c_str()); + //font_description_dump( candidate ); + //std::cout << " " << font_description_better_match( target, best, candidate ) << std::endl; + if (font_description_better_match(target, best, candidate)) { + pango_font_description_free(best); + best = candidate; + //std::cout << " ... better: " << std::endl; + } else { + pango_font_description_free(candidate); + //std::cout << " ... not better: " << std::endl; + } + } + + Glib::ustring best_style = target_style; + if (best) { + pango_font_description_unset_fields(best, PANGO_FONT_MASK_FAMILY); + best_style = pango_font_description_to_string(best); + } + + if (target) + pango_font_description_free(target); + if (best) + pango_font_description_free(best); #ifdef DEBUG_FONT - std::cout << " Returning: " << best_style << std::endl; - std::cout << "FontLister::get_best_style_match: exit" << std::endl; - std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; + std::cout << " Returning: " << best_style << std::endl; + std::cout << "FontLister::get_best_style_match: exit" << std::endl; + std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << std::endl; #endif - return best_style; - } + return best_style; +} - const Glib::RefPtr<Gtk::ListStore> - FontLister::get_font_list () const - { - return font_list_store; - } +const Glib::RefPtr<Gtk::ListStore> FontLister::get_font_list() const +{ + return font_list_store; +} - const Glib::RefPtr<Gtk::ListStore> - FontLister::get_style_list () const - { - return style_list_store; - } +const Glib::RefPtr<Gtk::ListStore> FontLister::get_style_list() const +{ + return style_list_store; } +} // namespace Inkscape + // Helper functions // Separator function (if true, a separator will be drawn) -gboolean font_lister_separator_func(GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/) +gboolean font_lister_separator_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer /*data*/) { - gchar* text = 0; - gtk_tree_model_get(model, iter, 0, &text, -1 ); // Column 0: FontList.family - return (text && strcmp(text,"#") == 0); + gchar *text = 0; + gtk_tree_model_get(model, iter, 0, &text, -1); // Column 0: FontList.family + return (text && strcmp(text, "#") == 0); } -void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/) +void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer /*data*/) { gchar *family; gboolean onSystem = false; gtk_tree_model_get(model, iter, 0, &family, 2, &onSystem, -1); - Glib::ustring family_escaped = g_markup_escape_text(family, -1); + gchar* family_escaped = g_markup_escape_text(family, -1); //g_free(family); Glib::ustring markup; - if( !onSystem ) { + if (!onSystem) { markup = "<span foreground='darkblue'>"; /* See if font-family on system */ - std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family_escaped ); - for( size_t i=0; i < tokens.size(); ++i ) { + std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*,\\s*", family_escaped); + for (size_t i = 0; i < tokens.size(); ++i) { Glib::ustring token = tokens[i]; @@ -1069,17 +1092,17 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, gchar *family = 0; gboolean onSystem = true; gboolean found = false; - for( valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL(model), &iter ); + for (valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter); valid; - valid = gtk_tree_model_iter_next( GTK_TREE_MODEL(model), &iter ) ) { + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)) { gtk_tree_model_get(model, &iter, 0, &family, 2, &onSystem, -1); - if( onSystem && familyNamesAreEqual( token, family ) ) { + if (onSystem && familyNamesAreEqual(token, family)) { found = true; break; } } - if( found ) { + if (found) { markup += g_markup_escape_text(token.c_str(), -1); markup += ", "; } else { @@ -1090,13 +1113,13 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, } } // Remove extra comma and space from end. - if( markup.size() >= 2 ) { - markup.resize( markup.size()-2 ); + if (markup.size() >= 2) { + markup.resize(markup.size() - 2); } markup += "</span>"; // std::cout << markup << std::endl; } else { - markup = family_escaped; + markup = family_escaped; } Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1104,17 +1127,20 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, if (show_sample) { Glib::ustring sample = prefs->getString("/tools/text/font_sample"); - Glib::ustring sample_escaped = g_markup_escape_text(sample.data(), -1); + gchar* sample_escaped = g_markup_escape_text(sample.data(), -1); markup += " <span foreground='gray' font_family='"; markup += family_escaped; markup += "'>"; markup += sample_escaped; markup += "</span>"; + g_free(sample_escaped); } - g_object_set (G_OBJECT (cell), "markup", markup.c_str(), NULL); + g_object_set(G_OBJECT(cell), "markup", markup.c_str(), NULL); + g_free(family_escaped); } + /* Local Variables: mode:c++ @@ -1124,4 +1150,4 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/libnrtype/font-lister.h b/src/libnrtype/font-lister.h index c89dab550..18e0d4b6e 100644 --- a/src/libnrtype/font-lister.h +++ b/src/libnrtype/font-lister.h @@ -28,294 +28,280 @@ class SPDocument; class SPCSSAttr; class SPStyle; -namespace Inkscape -{ - /** - * This class enumerates fonts using libnrtype into reusable data stores and - * allows for random access to the font-family list and the font-style list. - * Setting the font-family updates the font-style list. "Style" in this case - * refers to everything but family and size (e.g. italic/oblique, weight). - * - * This class handles font-family lists and fonts that are not on the system, - * where there is not an entry in the fontInstanceMap. - * - * This class uses the idea of "font_spec". This is a plain text string as used by - * Pango. It is similar to the CSS font shorthand except that font-family comes - * first and in this class the font-size is not used. - * - * This class uses the FontFactory class to get a list of system fonts - * and to find best matches via Pango. The Pango interface is only setup - * to deal with fonts that are on the system so care must be taken. For - * example, best matches should only be done with the first font-family - * in a font-family list. If the first font-family is not on the system - * then a generic font-family should be used (sans-serif -> Sans). - * - * This class is used by the UI interface (text-toolbar, font-select, etc.). - * - * "Font" includes family and style. It should not be used when one - * means font-family. - */ - class FontLister - { - public: - - enum Exceptions - { - FAMILY_NOT_FOUND, - STYLE_NOT_FOUND - }; - - - virtual ~FontLister (); - - /** GtkTreeModelColumnRecord for the font-family list Gtk::ListStore - */ - class FontListClass - : public Gtk::TreeModelColumnRecord - { - public: - /** Column containing the family name - */ - Gtk::TreeModelColumn<Glib::ustring> family; - - /** Column containing the styles for each family name. - */ - Gtk::TreeModelColumn<GList*> styles; - - /** Column containing flag if font is on system - */ - Gtk::TreeModelColumn<gboolean> onSystem; - - FontListClass () - { - add (family); - add (styles); - add (onSystem); - } - }; - - FontListClass FontList; - - class FontStyleListClass - : public Gtk::TreeModelColumnRecord - { - public: - /** Column containing the styles as Font designer used. - */ - Gtk::TreeModelColumn<Glib::ustring> displayStyle; - - /** Column containing the styles in CSS/Pango format. - */ - Gtk::TreeModelColumn<Glib::ustring> cssStyle; - - FontStyleListClass () - { - add (cssStyle); - add (displayStyle); - } - }; - - FontStyleListClass FontStyleList; - - /** Returns the ListStore with the family names - * - * The return is const and the function is declared as const. - * The ListStore is ready to be used after class instantiation - * and should not (cannot) be modified. - */ - const Glib::RefPtr<Gtk::ListStore> - get_font_list () const; - - /** Returns the ListStore with the styles - * - */ - const Glib::RefPtr<Gtk::ListStore> - get_style_list () const; - - /** Inserts a font family or font-fallback list (for use when not - * already in document or on system). - */ - void - insert_font_family ( Glib::ustring new_family ); - - /** Updates font list to include fonts in document - * - */ - void - update_font_list ( SPDocument* document); - - private: - void - update_font_list_recursive( SPObject *r, std::list<Glib::ustring> *l ); - - public: - static Inkscape::FontLister* - get_instance () - { - static Inkscape::FontLister* instance = new Inkscape::FontLister(); - return instance; - } - - /** Takes a hand written font spec and returns a Pango generated one in - * standard form. - */ - Glib::ustring canonize_fontspec( Glib::ustring fontspec ); - - /** Find closest system font to given font. - */ - Glib::ustring system_fontspec( Glib::ustring fontspec ); - - /** Gets font-family and style from fontspec. - * font-family and style returned. - */ - std::pair<Glib::ustring, Glib::ustring> - ui_from_fontspec (Glib::ustring fontspec); - - /** Sets font-family and style after a selection change. - * New font-family and style returned. - */ - std::pair<Glib::ustring, Glib::ustring> - selection_update (); - - /** Sets current_fontspec, etc. If check is false, won't - * try to find best style match (assumes style in fontspec - * valid for given font-family). - */ - void - set_fontspec (Glib::ustring fontspec, gboolean check=true); - - Glib::ustring - get_fontspec () - { - return current_fontspec; - } - - /** Changes font-family, updating style list and attempting to find - * closest style to current_style style (if check_style is true). - * New font-family and style returned. - * Does NOT update current_family and current_style. - * (For potential use in font-selector which doesn't update until - * "Apply" button clicked.) - */ - std::pair<Glib::ustring, Glib::ustring> - new_font_family (Glib::ustring family, gboolean check_style = true); - - /** Sets font-family, updating style list and attempting - * to find closest style to old current_style. - * New font-family and style returned. - * Updates current_family and current_style. - * Calls new_font_family(). - * (For use in text-toolbar where update is immediate.) - */ - std::pair<Glib::ustring, Glib::ustring> - set_font_family (Glib::ustring family, gboolean check_style = true); - - /** Sets font-family from row in list store. - * The row can be used to determine if we are in the - * document or system part of the font-family list. - * This is needed to handle scrolling through the - * font-family list correctly. - * Calls set_font_family(). - */ - std::pair<Glib::ustring, Glib::ustring> - set_font_family (int row, gboolean check_style = true); - - Glib::ustring - get_font_family () - { - return current_family; - } - - int - get_font_family_row () - { - return current_family_row; - } - - /** Sets style. Does not validate style for family. - */ - void - set_font_style (Glib::ustring style); - - Glib::ustring - get_font_style () - { - return current_style; - } - - Glib::ustring - fontspec_from_style (SPStyle* style); - - /** Fill css using current_fontspec. - */ - void - fill_css( SPCSSAttr *css, Glib::ustring fontspec = "" ); - - Gtk::TreeModel::Row - get_row_for_font (Glib::ustring family); - - Gtk::TreePath - get_path_for_font (Glib::ustring family); - - Gtk::TreeModel::Row - get_row_for_style (Glib::ustring style); - - Gtk::TreePath - get_path_for_style (Glib::ustring style); - - std::pair<Gtk::TreePath, Gtk::TreePath> - get_paths (Glib::ustring family, Glib::ustring style); - - /** Return best style match for new font given style for old font. - */ - Glib::ustring - get_best_style_match (Glib::ustring family, Glib::ustring style); - - /* Not Used */ - const NRNameList - get_name_list () const - { - return families; - } - - private: - - FontLister (); - - NRNameList families; - - Glib::RefPtr<Gtk::ListStore> font_list_store; - Glib::RefPtr<Gtk::ListStore> style_list_store; - - /** Info for currently selected font (what is shown in the UI). - * May include font-family lists and fonts not on system. - */ - int current_family_row; - Glib::ustring current_family; - Glib::ustring current_style; - Glib::ustring current_fontspec; - - /** fontspec of system font closest to current_fontspec. - * (What the system will use to display current_fontspec.) - */ - Glib::ustring current_fontspec_system; - - /** If a font-family is not on system, this list of styles is used. - */ - GList *default_styles; - }; -} +namespace Inkscape { + +/** + * This class enumerates fonts using libnrtype into reusable data stores and + * allows for random access to the font-family list and the font-style list. + * Setting the font-family updates the font-style list. "Style" in this case + * refers to everything but family and size (e.g. italic/oblique, weight). + * + * This class handles font-family lists and fonts that are not on the system, + * where there is not an entry in the fontInstanceMap. + * + * This class uses the idea of "font_spec". This is a plain text string as used by + * Pango. It is similar to the CSS font shorthand except that font-family comes + * first and in this class the font-size is not used. + * + * This class uses the FontFactory class to get a list of system fonts + * and to find best matches via Pango. The Pango interface is only setup + * to deal with fonts that are on the system so care must be taken. For + * example, best matches should only be done with the first font-family + * in a font-family list. If the first font-family is not on the system + * then a generic font-family should be used (sans-serif -> Sans). + * + * This class is used by the UI interface (text-toolbar, font-select, etc.). + * + * "Font" includes family and style. It should not be used when one + * means font-family. + */ + +class FontLister { +public: + enum Exceptions { + FAMILY_NOT_FOUND, + STYLE_NOT_FOUND + }; + + virtual ~FontLister(); + + /** + * GtkTreeModelColumnRecord for the font-family list Gtk::ListStore + */ + struct FontListClass : public Gtk::TreeModelColumnRecord { + /** + * Column containing the family name + */ + Gtk::TreeModelColumn<Glib::ustring> family; + + /** + * Column containing the styles for each family name. + */ + Gtk::TreeModelColumn<GList *> styles; + + /** + * Column containing flag if font is on system + */ + Gtk::TreeModelColumn<bool> onSystem; + + /** + * Not actually a column. + * Necessary for quick initialization of FontLister, + * we initially store the pango family and if the + * font style is actually used we'll cache it in + * %styles. + */ + Gtk::TreeModelColumn<PangoFontFamily *> pango_family; + + FontListClass() + { + add(family); + add(styles); + add(onSystem); + add(pango_family); + } + }; + + FontListClass FontList; + + struct FontStyleListClass : public Gtk::TreeModelColumnRecord { + /** + * Column containing the styles as Font designer used. + */ + Gtk::TreeModelColumn<Glib::ustring> displayStyle; + + /** + * Column containing the styles in CSS/Pango format. + */ + Gtk::TreeModelColumn<Glib::ustring> cssStyle; + + FontStyleListClass() + { + add(cssStyle); + add(displayStyle); + } + }; + + FontStyleListClass FontStyleList; + + /** + * @return the ListStore with the family names + * + * The return is const and the function is declared as const. + * The ListStore is ready to be used after class instantiation + * and should not be modified. + */ + const Glib::RefPtr<Gtk::ListStore> get_font_list() const; + + /** + * @return the ListStore with the styles + */ + const Glib::RefPtr<Gtk::ListStore> get_style_list() const; + + /** + * Inserts a font family or font-fallback list (for use when not + * already in document or on system). + */ + void insert_font_family(Glib::ustring new_family); + + /** + * Updates font list to include fonts in document. + */ + void update_font_list(SPDocument *document); + +public: + static Inkscape::FontLister *get_instance(); + + /** + * Takes a hand written font spec and returns a Pango generated one in + * standard form. + */ + Glib::ustring canonize_fontspec(Glib::ustring fontspec); + + /** + * Find closest system font to given font. + */ + Glib::ustring system_fontspec(Glib::ustring fontspec); + + /** + * Gets font-family and style from fontspec. + * font-family and style returned. + */ + std::pair<Glib::ustring, Glib::ustring> ui_from_fontspec(Glib::ustring fontspec); + + /** + * Sets font-family and style after a selection change. + * New font-family and style returned. + */ + std::pair<Glib::ustring, Glib::ustring> selection_update(); + + /** + * Sets current_fontspec, etc. If check is false, won't + * try to find best style match (assumes style in fontspec + * valid for given font-family). + */ + void set_fontspec(Glib::ustring fontspec, bool check = true); + + Glib::ustring get_fontspec() + { + return current_fontspec; + } + + /** + * Changes font-family, updating style list and attempting to find + * closest style to current_style style (if check_style is true). + * New font-family and style returned. + * Does NOT update current_family and current_style. + * (For potential use in font-selector which doesn't update until + * "Apply" button clicked.) + */ + std::pair<Glib::ustring, Glib::ustring> new_font_family(Glib::ustring family, bool check_style = true); + + /** + * Sets font-family, updating style list and attempting + * to find closest style to old current_style. + * New font-family and style returned. + * Updates current_family and current_style. + * Calls new_font_family(). + * (For use in text-toolbar where update is immediate.) + */ + std::pair<Glib::ustring, Glib::ustring> set_font_family(Glib::ustring family, bool check_style = true); + + /** + * Sets font-family from row in list store. + * The row can be used to determine if we are in the + * document or system part of the font-family list. + * This is needed to handle scrolling through the + * font-family list correctly. + * Calls set_font_family(). + */ + std::pair<Glib::ustring, Glib::ustring> set_font_family(int row, bool check_style = true); + + Glib::ustring get_font_family() + { + return current_family; + } + + int get_font_family_row() + { + return current_family_row; + } + + /** + * Sets style. Does not validate style for family. + */ + void set_font_style(Glib::ustring style); + + Glib::ustring get_font_style() + { + return current_style; + } + + Glib::ustring fontspec_from_style(SPStyle *style); + + /** + * Fill css using current_fontspec. + */ + void fill_css(SPCSSAttr *css, Glib::ustring fontspec = ""); + + Gtk::TreeModel::Row get_row_for_font(Glib::ustring family); + + Gtk::TreePath get_path_for_font(Glib::ustring family); + + Gtk::TreeModel::Row get_row_for_style(Glib::ustring style); + + Gtk::TreePath get_path_for_style(Glib::ustring style); + + std::pair<Gtk::TreePath, Gtk::TreePath> get_paths(Glib::ustring family, Glib::ustring style); + + /** + * Return best style match for new font given style for old font. + */ + Glib::ustring get_best_style_match(Glib::ustring family, Glib::ustring style); + + void ensureRowStyles(GtkTreeModel* model, GtkTreeIter const* iter); + +private: + FontLister(); + + void update_font_list_recursive(SPObject *r, std::list<Glib::ustring> *l); + + Glib::RefPtr<Gtk::ListStore> font_list_store; + Glib::RefPtr<Gtk::ListStore> style_list_store; + + /** + * Info for currently selected font (what is shown in the UI). + * May include font-family lists and fonts not on system. + */ + int current_family_row; + Glib::ustring current_family; + Glib::ustring current_style; + Glib::ustring current_fontspec; + + /** + * fontspec of system font closest to current_fontspec. + * (What the system will use to display current_fontspec.) + */ + Glib::ustring current_fontspec_system; + + /** + * If a font-family is not on system, this list of styles is used. + */ + GList *default_styles; +}; + +} // namespace Inkscape // Helper functions gboolean font_lister_separator_func(GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/); + GtkTreeIter *iter, + gpointer /*data*/); -void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer /*data*/); +void font_lister_cell_data_func(GtkCellLayout * /*cell_layout*/, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer /*data*/); #endif @@ -328,4 +314,4 @@ void font_lister_cell_data_func(GtkCellLayout */*cell_layout*/, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8 : diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index a00db1715..9996fc0f9 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -343,9 +343,9 @@ void TextEdit::onReadSelection ( gboolean dostyle, gboolean /*docontent*/ ) Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - // This is done for us by text-toolbar. No need to do it twice. - // fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); - // fontlister->selection_update(); + // This is normally done for us by text-toolbar but only when we are in text editing context + fontlister->update_font_list(sp_desktop_document(this->desktop)); + fontlister->selection_update(); Glib::ustring fontspec = fontlister->get_fontspec(); diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index f1d90f6c6..1c1e8a17a 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -18,6 +18,8 @@ # include "config.h" #endif +#include "widgets/desktop-widget.h" + #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H #include <glibmm/threads.h> #endif @@ -40,7 +42,6 @@ #include "desktop-handles.h" #include "desktop-events.h" #include "desktop-style.h" -#include "widgets/desktop-widget.h" #include "sp-namedview.h" #include "selection.h" #include "interface.h" diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp index f00f05768..327349844 100644 --- a/src/widgets/font-selector.cpp +++ b/src/widgets/font-selector.cpp @@ -304,6 +304,9 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, GtkTreeModel *model; GtkTreeIter iter; if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; + + Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); + fontlister->ensureRowStyles(model, &iter); // Next get family name with its style list gchar *family; @@ -311,7 +314,6 @@ static void sp_font_selector_family_select_row(GtkTreeSelection *selection, gtk_tree_model_get (model, &iter, 0, &family, 1, &list, -1); // Find best style match for selected family with current style (e.g. of selected text). - Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); Glib::ustring style = fontlister->get_font_style(); Glib::ustring best = fontlister->get_best_style_match (family, style); diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 36a151c52..2697beb8a 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -819,7 +819,7 @@ static void sp_text_set_sizes(GtkListStore* model_size, int unit) * It is called whenever a text selection is changed, including stepping cursor * through text, or setting focus to text. */ -static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl) +static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl, bool subselection = false) // don't bother to update font list if subsel changed { #ifdef DEBUG_TEXT static int count = 0; @@ -859,7 +859,9 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ INK_COMBOBOXENTRY_ACTION( g_object_get_data( tbl, "TextFontStyleAction" ) ); Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + if (!subselection) { + fontlister->update_font_list( sp_desktop_document( SP_ACTIVE_DESKTOP )); + } fontlister->selection_update(); // Update font list, but only if widget already created. @@ -1154,7 +1156,7 @@ static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, g static void sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl) { - sp_text_toolbox_selection_changed (NULL, tbl); + sp_text_toolbox_selection_changed (NULL, tbl, true); } // TODO: possibly share with font-selector by moving most code to font-lister (passing family name) @@ -1640,7 +1642,7 @@ static void text_toolbox_watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolB if (SP_IS_TEXT_CONTEXT(ec)) { // Watch selection - c_selection_changed = sp_desktop_selection(desktop)->connectChanged(bind(ptr_fun(sp_text_toolbox_selection_changed), holder)); + c_selection_changed = sp_desktop_selection(desktop)->connectChanged(bind(ptr_fun(sp_text_toolbox_selection_changed), holder, false)); c_selection_modified = sp_desktop_selection (desktop)->connectModified(bind(ptr_fun(sp_text_toolbox_selection_modified), holder)); c_subselection_changed = desktop->connectToolSubselectionChanged(bind(ptr_fun(sp_text_toolbox_subselection_changed), holder)); } else { |
