Krita Source Code Documentation
Loading...
Searching...
No Matches
KoFFWWSConverter Class Reference

The KoFFWWSConverter class This class takes fontconfig patterns and tries to sort them into a hierarchy of typographic/wws/font files font families, as well as retrieving all sorts of information to display in the GUI. More...

#include <KoFFWWSConverter.h>

Classes

struct  FontFileEntry
 
struct  Private
 

Public Member Functions

bool addFontFromFile (const QString &filename, const int index, FT_LibrarySP freeTypeLibrary)
 
bool addFontFromPattern (const FcPattern *pattern, FT_LibrarySP freeTypeLibrary)
 Add a font from a fontconfig pattern.
 
void addGenericFamily (const QString &name)
 This adds a CSS generic family. Call this before sortIntoWWSFamilies.
 
void addSupportedLanguagesByFile (const QString &filename, const int index, const QList< QLocale > &supportedLanguages, FcCharSet *set)
 
QVector< FontFileEntrycandidatesForCssValues (const KoCSSFontInfo info, quint32 xRes=72, quint32 yRes=72) const
 candidatesForCssValues Search the nodes for the most appropriate font for the given css values. We want to give these preferential treatment to whatever fontconfig matches for us.
 
QList< KoFontFamilyWWSRepresentationcollectFamilies () const
 Collects all WWSFamilies (that is, CSS compatible groupings of font files) and return them.
 
void debugInfo () const
 Print out the font family hierarchy into the debug output.
 
 KoFFWWSConverter ()
 
std::optional< KoFontFamilyWWSRepresentationrepresentationByFamilyName (const QString &familyName) const
 Gets a single WWSFamily representation for a given CSS Family Name, used by KoFontStorage.
 
void sortIntoWWSFamilies ()
 Sort any straggling fonts into WWSFamilies.
 
std::optional< QString > wwsNameByFamilyName (const QString familyName) const
 Used to find the closest corresponding resource when the family name doesn't match.
 
 ~KoFFWWSConverter ()
 

Private Attributes

QScopedPointer< Privated
 

Detailed Description

The KoFFWWSConverter class This class takes fontconfig patterns and tries to sort them into a hierarchy of typographic/wws/font files font families, as well as retrieving all sorts of information to display in the GUI.

This is necessary because by default FontConfig patterns don't differentiate between fonts family names, which means that some fonts are not selectable by CSS values alone.

Definition at line 57 of file KoFFWWSConverter.h.

Constructor & Destructor Documentation

◆ KoFFWWSConverter()

KoFFWWSConverter::KoFFWWSConverter ( )

Definition at line 260 of file KoFFWWSConverter.cpp.

261 : d(new Private())
262{
263
264}
QScopedPointer< Private > d

◆ ~KoFFWWSConverter()

KoFFWWSConverter::~KoFFWWSConverter ( )

Definition at line 266 of file KoFFWWSConverter.cpp.

267{
268}

Member Function Documentation

◆ addFontFromFile()

bool KoFFWWSConverter::addFontFromFile ( const QString & filename,
const int index,
FT_LibrarySP freeTypeLibrary )

Add a font from a filename and index. This will use freetype and harfbuzz to figure out the family name(s), styles and other font features.

< This indicates that the family follows WWS without having a specified WWS name.

< twip is 'Twenty-in-point';

When isWWSFamilyWithoutName is active, we need to assume that...

  1. The font is indicating it follows a WWS format only.
  2. The font has no wws family name.
  3. Probably this means that the font family is the typographic family, unless the typographic family is the exact same as the RIBBI family.

Definition at line 342 of file KoFFWWSConverter.cpp.

342 {
343
344 FontFamilyNode fontFamily;
345 fontFamily.fileName = filename;
346 fontFamily.fileIndex = index;
347 for (auto it = d->fontFamilyCollection.begin(); it != d->fontFamilyCollection.end(); it++) {
348 if (it->fileName == fontFamily.fileName && it->fileIndex == fontFamily.fileIndex) {
349 return true;
350 }
351 }
352
353 FT_Face f = nullptr;
354 FT_FaceSP face;
355 QByteArray utfData = fontFamily.fileName.toUtf8();
356 if (FT_New_Face(freeTypeLibrary.data(), utfData.data(), fontFamily.fileIndex, &f) == 0) {
357 face.reset(f);
358 } else {
359 return false;
360 }
361
362 fontFamily.fontFamily = face->family_name;
363 fontFamily.fontStyle = face->style_name;
364 fontFamily.lastModified = QFileInfo(fontFamily.fileName).lastModified();
365 if (!fontFamily.lastModified.isValid()) {
366 QDateTime time = QFileInfo(fontFamily.fileName).birthTime();
367 if (time.isValid()) {
368 fontFamily.lastModified = time;
369 } else {
370 fontFamily.lastModified = QDateTime::fromMSecsSinceEpoch(0);
371 }
372 }
373 FontFamilyNode typographicFamily;
374 FontFamilyNode wwsFamily;
375 bool isWWSFamilyWithoutName = false;
376
377 if (!FT_IS_SFNT(face.data())) {
378 fontFamily.type = FT_IS_SCALABLE(face.data())? KoSvgText::Type1FontType: KoSvgText::BDFFontType;
379
380 fontFamily.isItalic = face->style_flags & FT_STYLE_FLAG_ITALIC;
381 if (face->style_flags & FT_STYLE_FLAG_BOLD) {
383 } else {
385 }
386
387 for (int i=0; i< face->num_fixed_sizes; i++) {
388 // 64 = Freetype pixel
389 fontFamily.pixelSizes.insert((face->available_sizes[i].size / 64.0), {fontFamily.fileName});
390 }
391 } else {
393 hb_face_t_sp hbFace(hb_ft_face_create_referenced(face.data()));
394 hb_font_t_sp hbFont(hb_ft_font_create_referenced(face.data()));
395
396 // Retrieve width, weight and slant data.
397
398 fontFamily.axes.insert(WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WEIGHT)));
399 fontFamily.axes.insert(WIDTH_TAG, KoSvgText::FontFamilyAxis::widthAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WIDTH)));
400 fontFamily.isItalic = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_ITALIC) > 0;
401 //fontFamily.isOblique = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_SLANT_ANGLE) != 0;
402
403 TT_OS2 *os2Table = nullptr;
404 os2Table = (TT_OS2*)FT_Get_Sfnt_Table(face.data(), FT_SFNT_OS2);
405 if (os2Table) {
406
407 fontFamily.isOblique = os2Table->fsSelection & OS2_OBLIQUE;
408
409 if (os2Table->fsSelection & OS2_REGULAR) {
410 fontFamily.isItalic = false;
411 fontFamily.isOblique = false;
412 }
413
414 if (os2Table->version >= 5) {
415 FontFamilySizeInfo sizeInfo;
416 const qreal twip = 0.05;
417 sizeInfo.high = os2Table->usUpperOpticalPointSize * twip;
418 sizeInfo.low = os2Table->usLowerOpticalPointSize * twip;
419 sizeInfo.os2table = true;
420 sizeInfo.isSet = true;
421 fontFamily.sizeInfo = sizeInfo;
422 }
423 isWWSFamilyWithoutName = (os2Table->fsSelection & OS2_WWS);
424 }
425
426
427 // retrieve gpos size data...
428 uint designSize;
429 uint subFamilyId;
430 uint rangeStart;
431 uint rangeEnd;
432 hb_ot_name_id_t sizeNameId;
433 if (hb_ot_layout_get_size_params(hbFace.data(), &designSize, &subFamilyId, &sizeNameId, &rangeStart, &rangeEnd)) {
434 FontFamilySizeInfo sizeInfo;
435 qreal tenth = 0.1;
436 sizeInfo.low = rangeStart * tenth;
437 sizeInfo.high = rangeEnd * tenth;
438 sizeInfo.subFamilyID = subFamilyId;
439 sizeInfo.designSize = designSize * tenth;
440 sizeInfo.isSet = true;
441 fontFamily.sizeInfo = sizeInfo;
442 }
443
444 // retrieve axis data...
445 // Would also be good if we could read the STAT table for more info, but we cannot as there's no API for that in harfbuzz.
446
447 QHash<hb_ot_name_id_t, QString> axisNameIDs;
448 QVector<hb_ot_name_id_t> instanceNameIDs;
449 if (hb_ot_var_has_data(hbFace.data())) {
450 fontFamily.isVariable = true;
451 uint count = hb_ot_var_get_axis_count(hbFace.data());
452 uint maxInfos = 1;
453 QStringList axesTags;
454 for (uint i = 0; i < count; i++) {
456 hb_ot_var_axis_info_t axis;
457 hb_ot_var_get_axis_infos(hbFace.data(), i, &maxInfos, &axis);
458 axisInfo.min = axis.min_value;
459 axisInfo.max = axis.max_value;
460 axisInfo.value = axis.default_value;
461 axisInfo.axisHidden = axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN;
462 char buff[4];
463 hb_tag_to_string(axis.tag, buff);
464 axisInfo.tag = QString::fromLatin1(buff, 4);
465 axisNameIDs.insert(axis.name_id, axisInfo.tag);
466 axisInfo.variableAxis = true;
467 fontFamily.axes.insert(axisInfo.tag, axisInfo);
468 axesTags.append(axisInfo.tag);
469 }
470 count = hb_ot_var_get_named_instance_count (hbFace.data());
471 for (uint i = 0; i < count; i++) {
472 QHash<QString, float> instanceCoords;
473 uint coordLength = axesTags.size();
474 std::vector<float> coordinate(coordLength);
475 hb_ot_var_named_instance_get_design_coords (hbFace.data(), i, &coordLength, coordinate.data());
476 for (uint j =0; j < coordLength; j++ ){
477 instanceCoords.insert(axesTags.value(j), coordinate[j]);
478 }
480 style.instanceCoords = instanceCoords;
481 instanceNameIDs.append(hb_ot_var_named_instance_get_subfamily_name_id(hbFace.data(), i));
482 fontFamily.styleInfo.append(style);
483 }
484 }
485
486 // Get some basic color data.
487 fontFamily.colorBitMap = hb_ot_color_has_png(hbFace.data());
488 fontFamily.colorSVG = hb_ot_color_has_svg(hbFace.data());
489 fontFamily.colorClrV0 = hb_ot_color_has_layers(hbFace.data());
490 //fontFamily.colorClrV1 = hb_ot_color_has_paint(hbFace);
491 wwsFamily.colorBitMap = fontFamily.colorBitMap;
492 wwsFamily.colorSVG = fontFamily.colorSVG;
493 wwsFamily.colorClrV0 = fontFamily.colorClrV0;
494
495 uint numEntries = 0;
496 const hb_ot_name_entry_t *entries = hb_ot_name_list_names(hbFace.data(), &numEntries);
497
498 QHash<QLocale, QString> ribbiFamilyNames;
499 QHash<QLocale, QString> ribbiStyleNames;
500 QHash<QLocale, QString> WWSFamilyNames;
501 QHash<QLocale, QString> WWSStyleNames;
502 QHash<QLocale, QString> typographicFamilyNames;
503 QHash<QLocale, QString> typographicStyleNames;
504 QHash<QLocale, QString> fullNames;
505 for (uint i = 0; i < numEntries; i++) {
506 hb_ot_name_entry_t entry = entries[i];
507 QString lang(hb_language_to_string(entry.language));
508 QLocale locale(lang);
509 uint length = hb_ot_name_get_utf8(hbFace.data(), entry.name_id, entry.language, nullptr, nullptr)+1;
510 std::vector<char> buff(length);
511 hb_ot_name_get_utf8(hbFace.data(), entry.name_id, entry.language, &length, buff.data());
512 QString name = QString::fromUtf8(buff.data(), length);
513 if (name.isEmpty()) continue;
514
515 if (entry.name_id == HB_OT_NAME_ID_FONT_FAMILY) {
516 ribbiFamilyNames.insert(locale, name);
517 } else if (entry.name_id == HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY) {
518 typographicFamilyNames.insert(locale, name);
519 } else if (entry.name_id == HB_OT_NAME_ID_WWS_FAMILY) {
520 WWSFamilyNames.insert(locale, name);
521 } else if (entry.name_id == HB_OT_NAME_ID_FONT_SUBFAMILY) {
522 ribbiStyleNames.insert(locale, name);
523 } else if (entry.name_id == HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY) {
524 typographicStyleNames.insert(locale, name);
525 } else if (entry.name_id == HB_OT_NAME_ID_WWS_SUBFAMILY) {
526 WWSStyleNames.insert(locale, name);
527 } else if (entry.name_id == HB_OT_NAME_ID_FULL_NAME) {
528 fullNames.insert(locale, name);
529 } else if (entry.name_id > 0) { // Fonts made by Adobe seem to use the copyright id (0) as the input when the given value is empty.
530 if (axisNameIDs.keys().contains(entry.name_id)) {
531 fontFamily.axes[axisNameIDs.value(entry.name_id)].localizedLabels.insert(locale, name);
532 } else if (entry.name_id == sizeNameId) {
533 fontFamily.sizeInfo.localizedLabels.insert(locale, name);
534 } else if (instanceNameIDs.contains(entry.name_id)) {
535 int idx = instanceNameIDs.indexOf(entry.name_id);
536 fontFamily.styleInfo[idx].localizedLabels.insert(locale, name);
537 }
538 }
539 }
540 QLocale english(QLocale::English);
541 if (!typographicFamilyNames.isEmpty()) {
542 typographicFamily.fontFamily = typographicFamilyNames.value(english, typographicFamilyNames.values().first());
543 typographicFamily.localizedFontFamilies = typographicFamilyNames;
544 }
545 fontFamily.localizedTypographicStyle = typographicStyleNames;
546 if (!ribbiFamilyNames.isEmpty()) {
547 fontFamily.fontFamily = ribbiFamilyNames.value(english, ribbiFamilyNames.values().first());
548 fontFamily.localizedFontFamilies = ribbiFamilyNames;
549 }
550 // Second check is a hack to avoid issues with the css test fonts. Why they are configure this way, beats me.
551 // Either way, if the fullname, which has 100% priority is the name as typographic name (which is tested last)
552 // the font search will only select the node with this fullname, which we don't want.
553 if (!fullNames.isEmpty() && fullNames != typographicFamilyNames) {
554 fontFamily.localizedFullName = fullNames;
555 }
556 if (!ribbiStyleNames.isEmpty()) {
557 fontFamily.fontStyle = ribbiStyleNames.value(english, ribbiStyleNames.values().first());
558 fontFamily.localizedFontStyle = ribbiStyleNames;
559 }
560 if (!WWSFamilyNames.isEmpty()) {
561 wwsFamily.fontFamily = WWSFamilyNames.value(english, WWSFamilyNames.values().first());
562 wwsFamily.localizedFontFamilies = WWSFamilyNames;
563 }
564 fontFamily.localizedWWSStyle = WWSStyleNames;
565 }
566
567 if (fontFamily.fontFamily.isEmpty()) {
568 fontFamily.fontFamily = QFileInfo(fontFamily.fileName).baseName();
569 }
570 if (typographicFamily.fontFamily.isEmpty()) {
571 typographicFamily.fontFamily = fontFamily.fontFamily;
572 }
573 wwsFamily.isVariable = fontFamily.isVariable;
574 wwsFamily.type = fontFamily.type;
575 typographicFamily.type = typographicFamily.type;
576
577 if (typographicFamily.fontFamily.isEmpty() && fontFamily.fontFamily.isEmpty()) {
578 d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), fontFamily);
579 } else {
580 // find potential typographic family
581 auto it = d->fontFamilyCollection.childBegin();
582 for (; it != d->fontFamilyCollection.childEnd(); it++) {
583 if (!typographicFamily.fontFamily.isEmpty() && it->fontFamily == typographicFamily.fontFamily) {
584 break;
585 } else if (it->fontFamily == fontFamily.fontFamily) {
586 break;
587 }
588 }
589 if (it != d->fontFamilyCollection.childEnd()) {
590
591 if (isWWSFamilyWithoutName) {
601 if (!typographicFamily.fontFamily.isEmpty() && typographicFamily.fontFamily != fontFamily.fontFamily) {
602 wwsFamily.fontFamily = typographicFamily.fontFamily;
603 } else {
604 wwsFamily.fontFamily = fontFamily.fontFamily;
605 }
606 }
607 if (!wwsFamily.fontFamily.isEmpty()) {
608 // sort into wws family
609 auto wws = childBegin(it);
610 for (; wws != childEnd(it); wws++) {
611 if (wws->fontFamily == wwsFamily.fontFamily) {
612 break;
613 }
614 }
615 if (wws != childEnd(it)) {
616 d->fontFamilyCollection.insert(childEnd(wws), fontFamily);
617 } else {
618 auto wwsNew = d->fontFamilyCollection.insert(childEnd(it), wwsFamily);
619 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
620 }
621 } else if (!fontFamily.pixelSizes.isEmpty()) {
622 // sort any pixel sizes into the appropriate family.
623 auto pixel = childBegin(it);
624 for (; pixel != childEnd(it); pixel++) {
625 if (pixel->fontFamily == fontFamily.fontFamily && pixel->fontStyle == fontFamily.fontStyle && !pixel->pixelSizes.isEmpty()) {
626 for (int pxSize = 0; pxSize < fontFamily.pixelSizes.keys().size(); pxSize++) {
627 int px = fontFamily.pixelSizes.keys().at(pxSize);
628 QStringList files = pixel->pixelSizes.value(px, QStringList());
629 files.append(fontFamily.pixelSizes.value(px));
630 pixel->pixelSizes.insert(px, files);
631 }
632 break;
633 }
634 }
635 if (pixel == childEnd(it)) {
636 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
637 }
638
639 } else {
640 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
641 }
642 } else {
643 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
644 if (isWWSFamilyWithoutName) {
645 if (!typographicFamily.fontFamily.isEmpty() && typographicFamily.fontFamily != fontFamily.fontFamily) {
646 wwsFamily.fontFamily = typographicFamily.fontFamily;
647 } else {
648 wwsFamily.fontFamily = fontFamily.fontFamily;
649 }
650 }
651 if (!wwsFamily.fontFamily.isEmpty()) {
652 auto wwsNew = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
653 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
654 } else {
655 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
656 }
657 }
658 }
659 return true;
660}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
QList< QString > QStringList
constexpr unsigned OS2_OBLIQUE
Indicates that the given font is primarily a WWS family and requires no further processing.
const QString WEIGHT_TAG
const QString WIDTH_TAG
constexpr unsigned OS2_WWS
Is truly regular (instead of italic or oblique)
constexpr unsigned OS2_REGULAR
Is bold.
unsigned int uint
const char * name(StandardAction id)
ChildIterator< value_type, is_const > childBegin(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:290
ChildIterator< value_type, is_const > childEnd(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:300
@ OpenTypeFontType
Definition KoSvgText.h:810
@ Type1FontType
Definition KoSvgText.h:809
QHash< int, QStringList > pixelSizes
pixelSizes This is only used for bitmap fonts, when searching we try to return the files associated w...
QHash< QLocale, QString > localizedTypographicStyle
QDateTime lastModified
Other files that seem related. These might be duplicate font files, or fonts where only the tech diff...
QList< KoSvgText::FontFamilyStyleInfo > styleInfo
styleInfo This abstracts both font families that consist of many separate font-files and variable fon...
QHash< QLocale, QString > localizedFontStyle
KoSvgText::FontFormatType type
QHash< QString, KoSvgText::FontFamilyAxis > axes
axes While typical font-files within the same family are defined by having a single weight or width,...
QHash< QLocale, QString > localizedFullName
QHash< QLocale, QString > localizedFontFamilies
Last time the file was modified.
QHash< QLocale, QString > localizedWWSStyle
FontFamilySizeInfo sizeInfo
sizeInfo This is only really used to ensure that sizes get sorted into different WWS families,...
The FontFamilySizeInfo class Some font-families have different designs for different sizes....
int subFamilyID
Whether this is using the OS2 table or the GPOS Size feature.
QHash< QLocale, QString > localizedLabels
bool os2table
Whether the size info is set.
static FontFamilyAxis weightAxis(qreal val)
Definition KoSvgText.h:754
static FontFamilyAxis widthAxis(qreal val)
Definition KoSvgText.h:761
QHash< QString, float > instanceCoords
Definition KoSvgText.h:816

References FontFamilyNode::axes, KoSvgText::FontFamilyAxis::axisHidden, KoSvgText::BDFFontType, FontFamilyNode::colorBitMap, FontFamilyNode::colorClrV0, FontFamilyNode::colorSVG, d, KisLibraryResourcePointer< T, P >::data(), FontFamilySizeInfo::designSize, FontFamilyNode::fileIndex, FontFamilyNode::fileName, FontFamilyNode::fontFamily, FontFamilyNode::fontStyle, FontFamilySizeInfo::high, KoSvgText::FontFamilyStyleInfo::instanceCoords, FontFamilyNode::isItalic, FontFamilyNode::isOblique, FontFamilySizeInfo::isSet, FontFamilyNode::isVariable, FontFamilyNode::lastModified, length(), FontFamilyNode::localizedFontFamilies, FontFamilyNode::localizedFontStyle, FontFamilyNode::localizedFullName, FontFamilySizeInfo::localizedLabels, FontFamilyNode::localizedTypographicStyle, FontFamilyNode::localizedWWSStyle, FontFamilySizeInfo::low, KoSvgText::FontFamilyAxis::max, KoSvgText::FontFamilyAxis::min, KoSvgText::OpenTypeFontType, OS2_OBLIQUE, OS2_REGULAR, OS2_WWS, FontFamilySizeInfo::os2table, FontFamilyNode::pixelSizes, KisLibraryResourcePointer< T, P >::reset(), FontFamilyNode::sizeInfo, FontFamilyNode::styleInfo, FontFamilySizeInfo::subFamilyID, KoSvgText::FontFamilyAxis::tag, FontFamilyNode::type, KoSvgText::Type1FontType, KoSvgText::FontFamilyAxis::value, KoSvgText::FontFamilyAxis::variableAxis, WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(), WIDTH_TAG, and KoSvgText::FontFamilyAxis::widthAxis().

◆ addFontFromPattern()

bool KoFFWWSConverter::addFontFromPattern ( const FcPattern * pattern,
FT_LibrarySP freeTypeLibrary )

Add a font from a fontconfig pattern.

Definition at line 284 of file KoFFWWSConverter.cpp.

285{
286 if (!freeTypeLibrary.data()) {
287 return false;
288 }
289
290 bool getFile = false;
291 FcChar8 *fileValue{};
292 if (FcPatternGetString(pattern, FC_FILE, 0, &fileValue) != FcResultMatch) {
293 qWarning() << "Failed to get font file for" << pattern;
294 } else {
295 getFile = true;
296 }
297 QString filename = QString::fromUtf8(reinterpret_cast<char *>(fileValue));
298
299 int indexValue{};
300 if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch) {
301 qWarning() << "Failed to get font index for" << pattern << "(file:" << filename << ")";
302 getFile = false;
303 }
304
305 if (getFile == false) {
306 return getFile;
307 }
308
309 if (indexValue > 0xffff) { // this indicates the font is a variable font instance, so we don't try to load it.
310 return false;
311 }
312
313 bool success = addFontFromFile(filename, indexValue, freeTypeLibrary);
314 if (success) {
315 FcLangSet *set;
316 if (FcPatternGetLangSet(pattern, FC_LANG, 0, &set) != FcResultMatch) {
317 qWarning() << "Failed to get font index for" << pattern << "(file:" << filename << ")";
318 return success;
319 }
320 FcStrList *list = FcStrListCreate(FcLangSetGetLangs(set));
321 FcStrListFirst(list);
322 FcChar8 *langString = FcStrListNext(list);
323 QString lang = QString::fromUtf8(reinterpret_cast<char *>(langString));
324 QList<QLocale> languages;
325 while (!lang.isEmpty()) {
326 languages.append(QLocale(lang));
327
328 langString = FcStrListNext(list);
329 lang = QString::fromUtf8(reinterpret_cast<char *>(langString));
330 }
331 FcStrListDone(list);
332 FcCharSet *charSet = nullptr;
333 if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charSet) != FcResultMatch) {
334 return success;
335 }
336 addSupportedLanguagesByFile(filename, indexValue, languages, charSet);
337
338 }
339 return success;
340}
bool addFontFromFile(const QString &filename, const int index, FT_LibrarySP freeTypeLibrary)
void addSupportedLanguagesByFile(const QString &filename, const int index, const QList< QLocale > &supportedLanguages, FcCharSet *set)

References addFontFromFile(), addSupportedLanguagesByFile(), and KisLibraryResourcePointer< T, P >::data().

◆ addGenericFamily()

void KoFFWWSConverter::addGenericFamily ( const QString & name)

This adds a CSS generic family. Call this before sortIntoWWSFamilies.

Definition at line 873 of file KoFFWWSConverter.cpp.

874{
875 FontFamilyNode typographicFamily;
876 FontFamilyNode fontFamily;
877
878 QHash<QLocale, QString> familyNames = {{QLocale(QLocale::English), name}};
879 // TODO: can and should we translate this?
880 QHash<QLocale, QString> styleNames = {{QLocale(QLocale::English), "Regular"}};
881
882 fontFamily.fontFamily = name;
883 fontFamily.localizedFontFamilies = familyNames;
884
886
887 typographicFamily = fontFamily;
889 fontFamily.fontStyle = styleNames.values().first();
890 fontFamily.localizedFontStyle = styleNames;
891 QString tag = KoWritingSystemUtils::sampleTagForQLocale(QLocale(QLocale::English));
892 fontFamily.sampleStrings.insert(tag, KoWritingSystemUtils::samples().key(tag));
893
894 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
895 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
896}
static QString sampleTagForQLocale(const QLocale &locale)
static QMap< QString, QString > samples()
QHash< QString, QString > sampleStrings
Truetype collections have indices that need to be checked against.

References FontFamilyNode::axes, d, FontFamilyNode::fontFamily, FontFamilyNode::fontStyle, FontFamilyNode::localizedFontFamilies, FontFamilyNode::localizedFontStyle, KoSvgText::OpenTypeFontType, KoWritingSystemUtils::samples(), FontFamilyNode::sampleStrings, KoWritingSystemUtils::sampleTagForQLocale(), FontFamilyNode::type, WEIGHT_TAG, and KoSvgText::FontFamilyAxis::weightAxis().

◆ addSupportedLanguagesByFile()

void KoFFWWSConverter::addSupportedLanguagesByFile ( const QString & filename,
const int index,
const QList< QLocale > & supportedLanguages,
FcCharSet * set )

Definition at line 663 of file KoFFWWSConverter.cpp.

664{
665 auto it = d->fontFamilyCollection.depthFirstTailBegin();
666 for (; it!= d->fontFamilyCollection.depthFirstTailEnd(); it++) {
667 if (it->fileName == filename && it->fileIndex == index) {
668 break;
669 }
670 }
671 if (it != d->fontFamilyCollection.depthFirstTailEnd()) {
672 it->supportedLanguages = supportedLanguages;
673
674 QMap<QString, QString> samples = KoWritingSystemUtils::samples();
675
676 for (int i = 0; i < samples.size(); i++) {
677 QString sample = samples.keys().at(i);
678 bool matching = true;
679 Q_FOREACH (uint unicode, sample.toUcs4()) {
680 if (!FcCharSetHasChar(set, unicode)) {
681 matching = false;
682 break;
683 }
684 }
685 if (matching) {
686 it->sampleStrings.insert(samples.value(sample), sample);
687 }
688 }
689 }
690}

References d, and KoWritingSystemUtils::samples().

◆ candidatesForCssValues()

QVector< KoFFWWSConverter::FontFileEntry > KoFFWWSConverter::candidatesForCssValues ( const KoCSSFontInfo info,
quint32 xRes = 72,
quint32 yRes = 72 ) const

candidatesForCssValues Search the nodes for the most appropriate font for the given css values. We want to give these preferential treatment to whatever fontconfig matches for us.

Returns
list of QPairs representing the filenames and file indices for the candidates.

Definition at line 1115 of file KoFFWWSConverter.cpp.

1117{
1118 QVector<FontFileEntry> candidateFileNames;
1119
1120 int pixelSize = info.size * (qMin(xRes, yRes) / 72.0);
1121
1122 Q_FOREACH(const QString &family, info.families) {
1123 auto it = d->fontFamilyCollection.compositionBegin();
1124 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), family);
1125 if (it != d->fontFamilyCollection.compositionEnd()) {
1126 auto wws = siblingCurrent(it);
1127
1128 // check if we're in a typographic family by testing the hierarchy.
1129 // if so, select all subnodes.
1130 // Because we test subtree depth-first for finding the nodes, wws
1131 // and full names are tested before typographic.
1132 auto hierarchy = hierarchyBegin(wws);
1133 hierarchy++;
1134 QVector<FontFamilyNode> candidates;
1135 if (hierarchy == hierarchyEnd(wws)) {
1136 auto nodes = subtreeBegin(wws);
1137 auto endNodes = subtreeEnd(wws);
1138 for (;nodes != endNodes; nodes++) {
1139 if (childBegin(nodes) == childEnd(nodes)) {
1140 candidates.append(*nodes);
1141 }
1142 }
1143 } else if (childBegin(wws) == childEnd(wws)) {
1144 candidates.append(*wws);
1145 } else {
1146 auto style = childBegin(wws);
1147 auto styleEnd = childEnd(wws);
1148 for (;style != styleEnd; style++) {
1149 candidates.append(*style);
1150 }
1151 }
1152
1153 if (candidates.size() > 1) {
1154 // first find width
1155 candidates = findNodesByAxis(candidates, WIDTH_TAG, info.width, 100.0, 100.0);
1156 }
1157
1158 if (candidates.size() > 1) {
1159 // then find weight
1160 candidates = findNodesByAxis(candidates, WEIGHT_TAG, info.weight, 400.0, 500.0);
1161 }
1162 // then match italic
1163 if (candidates.size() > 1) {
1165 QVector<FontFamilyNode> obliques;
1166
1167 if (wws->isVariable) {
1168 qreal slantValue = info.slantMode == QFont::StyleItalic? 11: info.autoSlant? 14: info.slantValue;
1169 italics = findNodesByAxis(candidates, ITALIC_TAG, 1.0, 0.0, 0.0);
1170 obliques = findNodesByAxis(candidates, SLANT_TAG, -slantValue, 0.0, 0.0);
1171 }
1172 if (italics.isEmpty() && obliques.isEmpty()) {
1173 Q_FOREACH(const FontFamilyNode &node, candidates) {
1174 if (node.isItalic) {
1175 if (!node.isOblique) {
1176 italics.append(node);
1177 } else {
1178 obliques.append(node);
1179 }
1180 }
1181 }
1182 }
1183
1184 if (info.slantMode == QFont::StyleItalic) {
1185 if (!italics.isEmpty()) {
1186 candidates = italics;
1187 } else if (!obliques.isEmpty()) {
1188 candidates = obliques;
1189 }
1190 } else if (info.slantMode == QFont::StyleOblique) {
1191 if (!obliques.isEmpty()) {
1192 candidates = obliques;
1193 } else if (!italics.isEmpty()) {
1194 candidates = italics;
1195 }
1196 } else {
1197 QStringList slantedFontFiles;
1199 Q_FOREACH(const FontFamilyNode &italic, italics) {
1200 slantedFontFiles.append(italic.fileName);
1201 }
1202 Q_FOREACH(const FontFamilyNode &oblique, obliques) {
1203 slantedFontFiles.append(oblique.fileName);
1204 }
1205 Q_FOREACH(const FontFamilyNode &node, candidates) {
1206 if (!slantedFontFiles.contains(node.fileName)) {
1207 regular.append(node);
1208 }
1209 }
1210 if (!regular.isEmpty()) {
1211 candidates = regular;
1212 }
1213 }
1214 }
1215
1216 // prefer opentype
1217 if (candidates.size() > 1) {
1218 QVector<FontFamilyNode> openType;
1219 Q_FOREACH(const FontFamilyNode &node, candidates) {
1220 if (node.type == KoSvgText::OpenTypeFontType) {
1221 openType.append(node);
1222 }
1223 }
1224 if (!openType.isEmpty()) {
1225 candidates = openType;
1226 }
1227 }
1228
1229 // finally, match size.
1230 Q_FOREACH(const FontFamilyNode &node, candidates) {
1231 QStringList fileNames = node.otherFiles;
1232 fileNames.append(node.fileName);
1233 fileNames = node.pixelSizes.value(pixelSize, fileNames);
1234 Q_FOREACH(const QString &fileName, fileNames) {
1235 if (fileName.isEmpty()) continue;
1236 FontFileEntry entry;
1237 entry.fileName = fileName;
1238 entry.fontIndex = node.fileIndex;
1239 candidateFileNames.append(entry);
1240 }
1241 }
1242 }
1243 }
1244 return candidateFileNames;
1245}
const QString SLANT_TAG
QVector< FontFamilyNode > findNodesByAxis(const QVector< FontFamilyNode > &nodes, const QString axisTag, const qreal &value, const qreal &defaultValue, const qreal &defaultValueUpper)
const QString ITALIC_TAG
KisForest< FontFamilyNode >::composition_iterator searchNodes(KisForest< FontFamilyNode >::composition_iterator it, KisForest< FontFamilyNode >::composition_iterator endIt, const QString family)
ResultIterator subtreeBegin(Iterator it)
Definition KisForest.h:688
ResultIterator hierarchyBegin(Iterator it)
Definition KisForest.h:419
ResultIterator hierarchyEnd(Iterator it)
Definition KisForest.h:427
ChildIterator< value_type, is_const > siblingCurrent(ChildIterator< value_type, is_const > it)
Definition KisForest.h:240
ResultIterator subtreeEnd(Iterator it)
Definition KisForest.h:696
QStringList otherFiles
Languages supported, according to fontconfig.
QStringList families
QFont::Style slantMode

References KoCSSFontInfo::autoSlant, d, KoCSSFontInfo::families, FontFamilyNode::fileIndex, FontFamilyNode::fileName, KoFFWWSConverter::FontFileEntry::fileName, findNodesByAxis(), KoFFWWSConverter::FontFileEntry::fontIndex, FontFamilyNode::isItalic, FontFamilyNode::isOblique, ITALIC_TAG, KoSvgText::OpenTypeFontType, FontFamilyNode::otherFiles, FontFamilyNode::pixelSizes, searchNodes(), KoCSSFontInfo::size, SLANT_TAG, KoCSSFontInfo::slantMode, KoCSSFontInfo::slantValue, FontFamilyNode::type, KoCSSFontInfo::weight, WEIGHT_TAG, KoCSSFontInfo::width, and WIDTH_TAG.

◆ collectFamilies()

QList< KoFontFamilyWWSRepresentation > KoFFWWSConverter::collectFamilies ( ) const

Collects all WWSFamilies (that is, CSS compatible groupings of font files) and return them.

Definition at line 971 of file KoFFWWSConverter.cpp.

972{
974 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
975 auto counter = childBegin(typographic);
976 counter++;
977 bool singleFamily = childBegin(typographic) != childEnd(typographic) && std::next(childBegin(typographic)) == childEnd(typographic);
978
979 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
980
981 collection.append(createRepresentation(wws, typographic, singleFamily));
982 }
983 }
984 return collection;
985}
KoFontFamilyWWSRepresentation createRepresentation(KisForest< FontFamilyNode >::child_iterator wws, KisForest< FontFamilyNode >::child_iterator typographic, bool singleFamily)

References createRepresentation(), and d.

◆ debugInfo()

void KoFFWWSConverter::debugInfo ( ) const

Print out the font family hierarchy into the debug output.

Definition at line 1247 of file KoFFWWSConverter.cpp.

1248{
1249 qDebug() << "Debug for font family collection" << KisForestDetail::size(d->fontFamilyCollection);
1250 QString spaces;
1251 for (auto it = compositionBegin(d->fontFamilyCollection); it != compositionEnd(d->fontFamilyCollection); it++) {
1252 if (it.state() == KisForestDetail::Enter) {
1253 QStringList debugInfo = it->debugInfo();
1254 for (int i = 0; i< debugInfo.size(); i++) {
1255 if (i==0) {
1256 qDebug().noquote() << QString(spaces + "+") << debugInfo.at(i);
1257 } else {
1258 qDebug().noquote() << QString(spaces + "| ") << debugInfo.at(i);
1259 }
1260 }
1261 spaces.append(" ");
1262 }
1263
1264 if (it.state() == KisForestDetail::Leave) {
1265 spaces.chop(4);
1266 }
1267 }
1268}
void debugInfo() const
Print out the font family hierarchy into the debug output.
ResultIterator compositionEnd(Iterator it)
Definition KisForest.h:570
int size(const Forest< T > &forest)
Definition KisForest.h:1232
ResultIterator compositionBegin(Iterator it)
Definition KisForest.h:562

References d, debugInfo(), KisForestDetail::Enter, KisForestDetail::Leave, and KisForestDetail::size().

◆ representationByFamilyName()

std::optional< KoFontFamilyWWSRepresentation > KoFFWWSConverter::representationByFamilyName ( const QString & familyName) const

Gets a single WWSFamily representation for a given CSS Family Name, used by KoFontStorage.

Definition at line 1032 of file KoFFWWSConverter.cpp.

1033{
1034 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
1035 auto counter = childBegin(typographic);
1036 counter++;
1037 bool singleFamily = counter == childEnd(typographic);
1038
1039 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
1040 if (wws->fontFamily == familyName) {
1041 return std::make_optional(createRepresentation(wws, typographic, singleFamily));
1042 }
1043 }
1044 }
1045 return std::nullopt;
1046}

References createRepresentation(), and d.

◆ sortIntoWWSFamilies()

void KoFFWWSConverter::sortIntoWWSFamilies ( )

Sort any straggling fonts into WWSFamilies.

Definition at line 692 of file KoFFWWSConverter.cpp.

693{
694 QStringList wwsNames;
695 // Some font families have predefined wws families, others don't. This function sorts out everything so that each font file has
696 // a wws family in between the typographic and font-file nodes, this is important, because the wws family will be the one presented
697 // as the font-family resource.
698 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
700
701 QVector<qreal> weights;
702 QVector<qreal> widths;
703 QVector<int> fileIndices;
705
706 // This takes all of the current children that aren't inside a wws-node already and puts them into a temp list,
707 // as well as tallying the current widths and weights. We need these to find the most regular value.
709 for (auto child = childBegin(typographic); child != childEnd(typographic); child++) {
710 if (childBegin(child) != childEnd(child)) {
711 wwsNames.append(child->fontFamily);
712 continue;
713 }
714 tempList.insert(tempList.childEnd(), *child);
715 qreal wght = child->axes.value(WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(400)).value;
716 if (!weights.contains(wght)) weights.append(wght);
717 qreal wdth = child->axes.value(WIDTH_TAG, KoSvgText::FontFamilyAxis::widthAxis(100)).value;
718 if (!widths.contains(wdth)) widths.append(wdth);
719 if (!fileIndices.contains(child->fileIndex)) fileIndices.append(child->fileIndex);
720 types.append(child->type);
721 deleteList.append(child);
722 }
723 while (!deleteList.isEmpty()) {
724 auto child = deleteList.takeFirst();
726 d->fontFamilyCollection.erase(child);
727 }
728 if (KisForestDetail::size(tempList) > 0) {
729 //Do most regular first...
732 for (auto font = tempList.childBegin(); font != tempList.childEnd(); font++) {
733 const qreal testWeight = weights.contains(400)? 400: weights.first();
734 const qreal testWidth = widths.contains(100)? 100: widths.first();
735 // We want to select the first file index if possible.
736 const int testFileIndex = fileIndices.contains(0)? 0: fileIndices.first();
737
738 bool widthTested = !font->axes.keys().contains(WIDTH_TAG);
739 widthTested = widthTested? true: qFuzzyCompare(font->axes.value(WIDTH_TAG).value, testWidth);
740
741 QPair<QString, QString> fontStyle(font->fontFamily, font->fontStyle);
742 if (qFuzzyCompare(font->axes.value(WEIGHT_TAG).value, testWeight) && widthTested
743 && !font->isItalic
744 && !font->isOblique
745 && ( ( fileIndices.size() > 1 && font->fileIndex == testFileIndex ) || ( fileIndices.size()<=1 ))
746 && font->type == testType
747 && !existing.contains(fontStyle)) {
748 FontFamilyNode wwsFamily = FontFamilyNode::createWWSFamilyNode(*font, *typographic, wwsNames);
749 wwsNames.append(wwsFamily.fontFamily);
750 existing.append(fontStyle);
751
752 auto newWWS = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
753 d->fontFamilyCollection.insert(childEnd(newWWS), *font);
754 deleteList.append(font);
755 }
756 }
757 while (!deleteList.isEmpty()) {
758 auto child = deleteList.takeFirst();
760 tempList.erase(child);
761 }
762 // Then sort the rest of the family nodes into wws families.
763 for (auto font = tempList.childBegin(); font != tempList.childEnd(); font++) {
764 auto wws = childBegin(typographic);
765 auto wwsCandidate = childEnd(typographic);
766 for (; wws != childEnd(typographic); wws++) {
767 auto wwsChild = childBegin(wws);
768 if (font->type != KoSvgText::OpenTypeFontType && font->type != KoSvgText::Type1FontType) {
769 // Hack for really old fonts.
770 // It's questionable whether this is wise, given that it is not the family name,
771 // but it seems CSS is explicitly vague about what the family name is, because
772 // of the varying ways a font can be assigned a family name.
773 // Like, it is technically correct, because it allows us to select fonts with CSS
774 // that would otherwise be unselectable, but this does mean that other applications
775 // would need to have our exact idea of a CSS family name.
776 if (wws->fontStyle.toLower() != "regular"
777 && !font->fontStyle.contains(wws->fontStyle)) {
778 continue;
779 }
780 }
781 // In a previous version of the code, variable and non-variable were not mixed, but after reconsidering,
782 // they probably should be sorted together. The code will prioritize variable fonts in any case.
783
784 if (!wwsChild->sizeInfo.compare(font->sizeInfo)) {
785 // Skip sorting if the WWS family has size info that is incompatible with the sorted font.
786 continue;
787 }
788 for (; wwsChild != childEnd(wws); wwsChild++) {
789 if (wwsChild->isItalic == font->isItalic
790 && wwsChild->isOblique == font->isOblique
791 && wwsChild->compareAxes(font->axes)
792 && wwsChild->hasAnyColor() == font->hasAnyColor()) {
793 break;
794 }
795 }
796 if (wwsChild != childEnd(wws)) {
797 if (wwsChild->fontFamily == font->fontFamily && wwsChild->fontStyle == font->fontStyle) {
798 // If, for all intends and purposes, the font seems to be the same, merge nodes.
799 // This sometimes happens with installations where the same font is installed in
800 // a variety of formats. We want to prefer the opentype version in any case.
801 if (wwsChild->type != KoSvgText::OpenTypeFontType && font->type == KoSvgText::OpenTypeFontType) {
802 wwsChild->otherFiles.append(wwsChild->fileName);
803 wwsChild->otherFiles.append(font->otherFiles);
804 wwsChild->fileName = font->fileName;
805 wwsChild->type = KoSvgText::OpenTypeFontType;
806 } else {
807 wwsChild->otherFiles.append(font->fileName);
808 wwsChild->otherFiles.append(font->otherFiles);
809 }
810 if (wwsChild->lastModified < font->lastModified) {
811 wwsChild->lastModified = font->lastModified;
812 }
813 break;
814 } else {
815 continue;
816 }
817 } else {
818 /*
819 * Try to match the wws family with the same fontfamily, otherwise select the first candidate.
820 */
821 if (wwsCandidate == childEnd(typographic)) {
822 wwsCandidate = wws;
823 }
824 if (wws->fontFamily == font->fontFamily) {
825 wwsCandidate = wws;
826 break;
827 }
828 }
829 }
830 if (wwsCandidate != childEnd(typographic)) {
831 d->fontFamilyCollection.insert(childEnd(wwsCandidate), *font);
832 } else if (wws == childEnd(typographic)) {
833 FontFamilyNode wwsFamily = FontFamilyNode::createWWSFamilyNode(*font, *typographic, wwsNames);
834 wwsNames.append(wwsFamily.fontFamily);
835 auto newWWS = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
836 if (wwsFamily.fontFamily != typographic->fontFamily) {
837 font->localizedTypographicStyle.clear();
838 }
839 d->fontFamilyCollection.insert(childEnd(newWWS), *font);
840 }
841 }
842 // This only triggers when the first wws family was created with the typographic name,
843 // yet more wws families have followed after sorting was finished, and this name might be not the most precise.
844 if (wwsNames.contains(typographic->fontFamily) && std::distance(childBegin(typographic), childEnd(typographic)) > 1) {
845 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
846 if (wws->fontFamily == typographic->fontFamily) {
847 if (wwsNames.contains(childBegin(wws)->fontFamily)) {
848 const QString otherWWSName = childBegin(wws)->fontFamily;
849 // Also rename any other wwsfamilies that has been using the second style.
850 for (auto otherwws = childBegin(typographic); otherwws != childEnd(typographic); otherwws++) {
851 if (otherwws->fontFamily == otherWWSName) {
852 otherwws->fontFamily = childBegin(otherwws)->fontFamily + " " + childBegin(otherwws)->fontStyle;
853 QHash<QLocale, QString> families;
854 const QHash<QLocale, QString> styles = childBegin(otherwws)->localizedFontStyle;
855 Q_FOREACH (const QLocale l, otherwws->localizedFontFamilies.keys()) {
856 families.insert(l, otherwws->localizedFontFamilies.value(l)+" "+styles.value(l, childBegin(otherwws)->fontStyle));
857 }
858 otherwws->localizedFontFamilies = families;
859 break;
860 }
861 }
862 }
863 wws->fontFamily = childBegin(wws)->fontFamily;
864 childBegin(wws)->localizedTypographicStyle.clear();
865 break;
866 }
867 }
868 }
869 }
870 }
871}
float value(const T *src, size_t ch)
child_iterator childEnd()
Definition KisForest.h:880
child_iterator insert(child_iterator pos, X &&value)
Inserts element value into position pos. value becomes the child of the same parent as pos and is pla...
Definition KisForest.h:943
child_iterator childBegin()
Definition KisForest.h:876
child_iterator erase(child_iterator pos)
Removes element at position pos. If pos is 'end', then result is undefined.
Definition KisForest.h:956
static bool qFuzzyCompare(half p1, half p2)
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
static FontFamilyNode createWWSFamilyNode(const FontFamilyNode &child, const FontFamilyNode &typographic, QStringList existingWWSNames)

References KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::childEnd(), FontFamilyNode::createWWSFamilyNode(), d, KisForestDetail::Forest< T >::erase(), FontFamilyNode::fontFamily, KisForestDetail::Forest< T >::insert(), KIS_ASSERT_RECOVER_NOOP, KoSvgText::OpenTypeFontType, qFuzzyCompare(), KisForestDetail::size(), KoSvgText::Type1FontType, value(), WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(), WIDTH_TAG, and KoSvgText::FontFamilyAxis::widthAxis().

◆ wwsNameByFamilyName()

std::optional< QString > KoFFWWSConverter::wwsNameByFamilyName ( const QString familyName) const

Used to find the closest corresponding resource when the family name doesn't match.

Definition at line 1048 of file KoFFWWSConverter.cpp.

1049{
1050 auto it = d->fontFamilyCollection.compositionBegin();
1051 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), familyName);
1052 if (it != d->fontFamilyCollection.compositionEnd()) {
1053
1054 bool isChild = childBegin(it) == childEnd(it);
1055 auto wws = siblingCurrent(it);
1056
1057 // check if we're in a typographic family by testing the hierarchy.
1058 // if so, select the wws family.
1059 auto hierarchy = hierarchyBegin(wws);
1060 hierarchy++;
1061 if (isChild) {
1062 wws = siblingCurrent(hierarchy);
1063 } else if (hierarchy == hierarchyEnd(wws)) {
1064 wws = childBegin(it);
1065 }
1066 return std::make_optional(wws->fontFamily);
1067 }
1068 return std::nullopt;
1069}

References d, and searchNodes().

Member Data Documentation

◆ d

QScopedPointer<Private> KoFFWWSConverter::d
private

Definition at line 108 of file KoFFWWSConverter.h.


The documentation for this class was generated from the following files: