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.

< twip is 'Twenty-in-point';

(os2Table->fsSelection & OS2_WWS) indicates WWS-family, but Krita has no use for it. It infact breaks some font handling, because fonts can be mixed in whether they have this flag set. See BUG:518874.

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
376 if (!FT_IS_SFNT(face.data())) {
377 fontFamily.type = FT_IS_SCALABLE(face.data())? KoSvgText::Type1FontType: KoSvgText::BDFFontType;
378
379 fontFamily.isItalic = face->style_flags & FT_STYLE_FLAG_ITALIC;
380 if (face->style_flags & FT_STYLE_FLAG_BOLD) {
382 } else {
384 }
385
386 for (int i=0; i< face->num_fixed_sizes; i++) {
387 // 64 = Freetype pixel
388 fontFamily.pixelSizes.insert((face->available_sizes[i].size / 64.0), {fontFamily.fileName});
389 }
390 } else {
392 hb_face_t_sp hbFace(hb_ft_face_create_referenced(face.data()));
393 hb_font_t_sp hbFont(hb_ft_font_create_referenced(face.data()));
394
395 // Retrieve width, weight and slant data.
396
397 fontFamily.axes.insert(WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WEIGHT)));
398 fontFamily.axes.insert(WIDTH_TAG, KoSvgText::FontFamilyAxis::widthAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WIDTH)));
399 fontFamily.isItalic = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_ITALIC) > 0;
400 //fontFamily.isOblique = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_SLANT_ANGLE) != 0;
401
402 TT_OS2 *os2Table = nullptr;
403 os2Table = (TT_OS2*)FT_Get_Sfnt_Table(face.data(), FT_SFNT_OS2);
404 if (os2Table) {
405
406 fontFamily.isOblique = os2Table->fsSelection & OS2_OBLIQUE;
407
408 if (os2Table->fsSelection & OS2_REGULAR) {
409 fontFamily.isItalic = false;
410 fontFamily.isOblique = false;
411 }
412
413 if (os2Table->version >= 5) {
414 FontFamilySizeInfo sizeInfo;
415 const qreal twip = 0.05;
416 sizeInfo.high = os2Table->usUpperOpticalPointSize * twip;
417 sizeInfo.low = os2Table->usLowerOpticalPointSize * twip;
418 sizeInfo.os2table = true;
419 sizeInfo.isSet = true;
420 fontFamily.sizeInfo = sizeInfo;
421 }
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 if (!wwsFamily.fontFamily.isEmpty()) {
591 // sort into wws family
592 auto wws = childBegin(it);
593 for (; wws != childEnd(it); wws++) {
594 if (wws->fontFamily == wwsFamily.fontFamily) {
595 break;
596 }
597 }
598 if (wws != childEnd(it)) {
599 d->fontFamilyCollection.insert(childEnd(wws), fontFamily);
600 } else {
601 auto wwsNew = d->fontFamilyCollection.insert(childEnd(it), wwsFamily);
602 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
603 }
604 } else if (!fontFamily.pixelSizes.isEmpty()) {
605 // sort any pixel sizes into the appropriate family.
606 auto pixel = childBegin(it);
607 for (; pixel != childEnd(it); pixel++) {
608 if (pixel->fontFamily == fontFamily.fontFamily && pixel->fontStyle == fontFamily.fontStyle && !pixel->pixelSizes.isEmpty()) {
609 for (int pxSize = 0; pxSize < fontFamily.pixelSizes.keys().size(); pxSize++) {
610 int px = fontFamily.pixelSizes.keys().at(pxSize);
611 QStringList files = pixel->pixelSizes.value(px, QStringList());
612 files.append(fontFamily.pixelSizes.value(px));
613 pixel->pixelSizes.insert(px, files);
614 }
615 break;
616 }
617 }
618 if (pixel == childEnd(it)) {
619 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
620 }
621
622 } else {
623 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
624 }
625 } else {
626 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
627 if (!wwsFamily.fontFamily.isEmpty()) {
628 auto wwsNew = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
629 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
630 } else {
631 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
632 }
633 }
634 }
635 return true;
636}
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_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, 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 917 of file KoFFWWSConverter.cpp.

918{
919 FontFamilyNode typographicFamily;
920 FontFamilyNode fontFamily;
921
922 QHash<QLocale, QString> familyNames = {{QLocale(QLocale::English), name}};
923 // TODO: can and should we translate this?
924 QHash<QLocale, QString> styleNames = {{QLocale(QLocale::English), "Regular"}};
925
926 fontFamily.fontFamily = name;
927 fontFamily.localizedFontFamilies = familyNames;
928
930
931 typographicFamily = fontFamily;
933 fontFamily.fontStyle = styleNames.values().first();
934 fontFamily.localizedFontStyle = styleNames;
935 QString tag = KoWritingSystemUtils::sampleTagForQLocale(QLocale(QLocale::English));
936 fontFamily.sampleStrings.insert(tag, KoWritingSystemUtils::samples().key(tag));
937
938 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
939 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
940}
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 639 of file KoFFWWSConverter.cpp.

640{
641 auto it = d->fontFamilyCollection.depthFirstTailBegin();
642 for (; it!= d->fontFamilyCollection.depthFirstTailEnd(); it++) {
643 if (it->fileName == filename && it->fileIndex == index) {
644 break;
645 }
646 }
647 if (it != d->fontFamilyCollection.depthFirstTailEnd()) {
648 it->supportedLanguages = supportedLanguages;
649
650 QMap<QString, QString> samples = KoWritingSystemUtils::samples();
651
652 for (int i = 0; i < samples.size(); i++) {
653 QString sample = samples.keys().at(i);
654 bool matching = true;
655 Q_FOREACH (uint unicode, sample.toUcs4()) {
656 if (!FcCharSetHasChar(set, unicode)) {
657 matching = false;
658 break;
659 }
660 }
661 if (matching) {
662 it->sampleStrings.insert(samples.value(sample), sample);
663 }
664 }
665 }
666}

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 1159 of file KoFFWWSConverter.cpp.

1161{
1162 QVector<FontFileEntry> candidateFileNames;
1163
1164 int pixelSize = info.size * (qMin(xRes, yRes) / 72.0);
1165
1166 Q_FOREACH(const QString &family, info.families) {
1167 auto it = d->fontFamilyCollection.compositionBegin();
1168 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), family);
1169 if (it != d->fontFamilyCollection.compositionEnd()) {
1170 auto wws = siblingCurrent(it);
1171
1172 // check if we're in a typographic family by testing the hierarchy.
1173 // if so, select all subnodes.
1174 // Because we test subtree depth-first for finding the nodes, wws
1175 // and full names are tested before typographic.
1176 auto hierarchy = hierarchyBegin(wws);
1177 hierarchy++;
1178 QVector<FontFamilyNode> candidates;
1179 if (hierarchy == hierarchyEnd(wws)) {
1180 auto nodes = subtreeBegin(wws);
1181 auto endNodes = subtreeEnd(wws);
1182 for (;nodes != endNodes; nodes++) {
1183 if (childBegin(nodes) == childEnd(nodes)) {
1184 candidates.append(*nodes);
1185 }
1186 }
1187 } else if (childBegin(wws) == childEnd(wws)) {
1188 candidates.append(*wws);
1189 } else {
1190 auto style = childBegin(wws);
1191 auto styleEnd = childEnd(wws);
1192 for (;style != styleEnd; style++) {
1193 candidates.append(*style);
1194 }
1195 }
1196
1197 if (candidates.size() > 1) {
1198 // first find width
1199 candidates = findNodesByAxis(candidates, WIDTH_TAG, info.width, 100.0, 100.0);
1200 }
1201
1202 if (candidates.size() > 1) {
1203 // then find weight
1204 candidates = findNodesByAxis(candidates, WEIGHT_TAG, info.weight, 400.0, 500.0);
1205 }
1206 // then match italic
1207 if (candidates.size() > 1) {
1209 QVector<FontFamilyNode> obliques;
1210
1211 if (wws->isVariable) {
1212 qreal slantValue = info.slantMode == QFont::StyleItalic? 11: info.autoSlant? 14: info.slantValue;
1213 italics = findNodesByAxis(candidates, ITALIC_TAG, 1.0, 0.0, 0.0);
1214 obliques = findNodesByAxis(candidates, SLANT_TAG, -slantValue, 0.0, 0.0);
1215 }
1216 if (italics.isEmpty() && obliques.isEmpty()) {
1217 Q_FOREACH(const FontFamilyNode &node, candidates) {
1218 if (node.isItalic) {
1219 if (!node.isOblique) {
1220 italics.append(node);
1221 } else {
1222 obliques.append(node);
1223 }
1224 }
1225 }
1226 }
1227
1228 if (info.slantMode == QFont::StyleItalic) {
1229 if (!italics.isEmpty()) {
1230 candidates = italics;
1231 } else if (!obliques.isEmpty()) {
1232 candidates = obliques;
1233 }
1234 } else if (info.slantMode == QFont::StyleOblique) {
1235 if (!obliques.isEmpty()) {
1236 candidates = obliques;
1237 } else if (!italics.isEmpty()) {
1238 candidates = italics;
1239 }
1240 } else {
1241 QStringList slantedFontFiles;
1243 Q_FOREACH(const FontFamilyNode &italic, italics) {
1244 slantedFontFiles.append(italic.fileName);
1245 }
1246 Q_FOREACH(const FontFamilyNode &oblique, obliques) {
1247 slantedFontFiles.append(oblique.fileName);
1248 }
1249 Q_FOREACH(const FontFamilyNode &node, candidates) {
1250 if (!slantedFontFiles.contains(node.fileName)) {
1251 regular.append(node);
1252 }
1253 }
1254 if (!regular.isEmpty()) {
1255 candidates = regular;
1256 }
1257 }
1258 }
1259
1260 // prefer opentype
1261 if (candidates.size() > 1) {
1262 QVector<FontFamilyNode> openType;
1263 Q_FOREACH(const FontFamilyNode &node, candidates) {
1264 if (node.type == KoSvgText::OpenTypeFontType) {
1265 openType.append(node);
1266 }
1267 }
1268 if (!openType.isEmpty()) {
1269 candidates = openType;
1270 }
1271 }
1272
1273 // finally, match size.
1274 Q_FOREACH(const FontFamilyNode &node, candidates) {
1275 QStringList fileNames = node.otherFiles;
1276 fileNames.append(node.fileName);
1277 fileNames = node.pixelSizes.value(pixelSize, fileNames);
1278 Q_FOREACH(const QString &fileName, fileNames) {
1279 if (fileName.isEmpty()) continue;
1280 FontFileEntry entry;
1281 entry.fileName = fileName;
1282 entry.fontIndex = node.fileIndex;
1283 candidateFileNames.append(entry);
1284 }
1285 }
1286 }
1287 }
1288 return candidateFileNames;
1289}
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 1015 of file KoFFWWSConverter.cpp.

1016{
1018 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
1019 auto counter = childBegin(typographic);
1020 counter++;
1021 bool singleFamily = childBegin(typographic) != childEnd(typographic) && std::next(childBegin(typographic)) == childEnd(typographic);
1022
1023 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
1024
1025 collection.append(createRepresentation(wws, typographic, singleFamily));
1026 }
1027 }
1028 return collection;
1029}
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 1291 of file KoFFWWSConverter.cpp.

1292{
1293 qDebug() << "Debug for font family collection" << KisForestDetail::size(d->fontFamilyCollection);
1294 QString spaces;
1295 for (auto it = compositionBegin(d->fontFamilyCollection); it != compositionEnd(d->fontFamilyCollection); it++) {
1296 if (it.state() == KisForestDetail::Enter) {
1297 QStringList debugInfo = it->debugInfo();
1298 for (int i = 0; i< debugInfo.size(); i++) {
1299 if (i==0) {
1300 qDebug().noquote() << QString(spaces + "+") << debugInfo.at(i);
1301 } else {
1302 qDebug().noquote() << QString(spaces + "| ") << debugInfo.at(i);
1303 }
1304 }
1305 spaces.append(" ");
1306 }
1307
1308 if (it.state() == KisForestDetail::Leave) {
1309 spaces.chop(4);
1310 }
1311 }
1312}
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 1076 of file KoFFWWSConverter.cpp.

1077{
1078 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
1079 auto counter = childBegin(typographic);
1080 counter++;
1081 bool singleFamily = counter == childEnd(typographic);
1082
1083 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
1084 if (wws->fontFamily == familyName) {
1085 return std::make_optional(createRepresentation(wws, typographic, singleFamily));
1086 }
1087 }
1088 }
1089 return std::nullopt;
1090}

References createRepresentation(), and d.

◆ sortIntoWWSFamilies()

void KoFFWWSConverter::sortIntoWWSFamilies ( )

Sort any straggling fonts into WWSFamilies.

Definition at line 668 of file KoFFWWSConverter.cpp.

669{
670 QStringList wwsNames;
671 QStringList wwsNamesDuplicates;
672 // Some font families have predefined wws families, others don't. This function sorts out everything so that each font file has
673 // a wws family in between the typographic and font-file nodes, this is important, because the wws family will be the one presented
674 // as the font-family resource.
675 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
677
678 QVector<qreal> weights;
679 QVector<qreal> widths;
680 QVector<int> fileIndices;
682
683 // This takes all of the current children that aren't inside a wws-node already and puts them into a temp list,
684 // as well as tallying the current widths and weights. We need these to find the most regular value.
686 for (auto child = childBegin(typographic); child != childEnd(typographic); child++) {
687 if (childBegin(child) != childEnd(child)) {
688 wwsNames.append(child->fontFamily);
689 continue;
690 }
691 tempList.insert(tempList.childEnd(), *child);
692 qreal wght = child->axes.value(WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(400)).value;
693 if (!weights.contains(wght)) weights.append(wght);
694 qreal wdth = child->axes.value(WIDTH_TAG, KoSvgText::FontFamilyAxis::widthAxis(100)).value;
695 if (!widths.contains(wdth)) widths.append(wdth);
696 if (!fileIndices.contains(child->fileIndex)) fileIndices.append(child->fileIndex);
697 types.append(child->type);
698 deleteList.append(child);
699 }
700 while (!deleteList.isEmpty()) {
701 auto child = deleteList.takeFirst();
703 d->fontFamilyCollection.erase(child);
704 }
705
707 for (auto font = tempList.childBegin(); font != tempList.childEnd(); font++) {
708 // prioritize the font with the name closest to the typographic family, so other fonts get sorted into it.
709 if(font->fontFamily == typographic->fontFamily && font != tempList.childBegin()) {
710 moveToFront.append(font);
711 }
712 }
713 while (!moveToFront.isEmpty()) {
714 auto font = moveToFront.takeLast();
715 tempList.move(font, tempList.childBegin());
716 }
717
718 if (KisForestDetail::size(tempList) > 0) {
719 //Do most regular first...
722 for (auto font = tempList.childBegin(); font != tempList.childEnd(); font++) {
723 const qreal testWeight = weights.contains(400)? 400: weights.first();
724 const qreal testWidth = widths.contains(100)? 100: widths.first();
725 // We want to select the first file index if possible.
726 const int testFileIndex = fileIndices.contains(0)? 0: fileIndices.first();
727
728 bool widthTested = !font->axes.keys().contains(WIDTH_TAG);
729 widthTested = widthTested? true: qFuzzyCompare(font->axes.value(WIDTH_TAG).value, testWidth);
730
731 QPair<QString, QString> fontStyle(font->fontFamily, font->fontStyle);
732 if (qFuzzyCompare(font->axes.value(WEIGHT_TAG).value, testWeight) && widthTested
733 && !font->isItalic
734 && !font->isOblique
735 && ( ( fileIndices.size() > 1 && font->fileIndex == testFileIndex ) || ( fileIndices.size()<=1 ))
736 && font->type == testType
737 && !existing.contains(fontStyle)) {
738 FontFamilyNode wwsFamily = FontFamilyNode::createWWSFamilyNode(*font, *typographic, wwsNames);
739 wwsNames.append(wwsFamily.fontFamily);
740 existing.append(fontStyle);
741
742 auto newWWS = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
743 d->fontFamilyCollection.insert(childEnd(newWWS), *font);
744 deleteList.append(font);
745 }
746 }
747 while (!deleteList.isEmpty()) {
748 auto child = deleteList.takeFirst();
750 tempList.erase(child);
751 }
752 // Then sort the rest of the family nodes into wws families.
753 for (auto font = tempList.childBegin(); font != tempList.childEnd(); font++) {
754 auto wws = childBegin(typographic);
755 auto wwsCandidate = childEnd(typographic);
756 for (; wws != childEnd(typographic); wws++) {
757 auto wwsChild = childBegin(wws);
758 if (font->type != KoSvgText::OpenTypeFontType && font->type != KoSvgText::Type1FontType) {
759 // Hack for really old fonts.
760 // It's questionable whether this is wise, given that it is not the family name,
761 // but it seems CSS is explicitly vague about what the family name is, because
762 // of the varying ways a font can be assigned a family name.
763 // Like, it is technically correct, because it allows us to select fonts with CSS
764 // that would otherwise be unselectable, but this does mean that other applications
765 // would need to have our exact idea of a CSS family name.
766 if (wws->fontStyle.toLower() != "regular"
767 && !font->fontStyle.contains(wws->fontStyle)) {
768 continue;
769 }
770 }
771 // In a previous version of the code, variable and non-variable were not mixed, but after reconsidering,
772 // they probably should be sorted together. The code will prioritize variable fonts in any case.
773
774 if (!wwsChild->sizeInfo.compare(font->sizeInfo)) {
775 // Skip sorting if the WWS family has size info that is incompatible with the sorted font.
776 continue;
777 }
778 for (; wwsChild != childEnd(wws); wwsChild++) {
779 if (wwsChild->isItalic == font->isItalic
780 && wwsChild->isOblique == font->isOblique
781 && wwsChild->compareAxes(font->axes)
782 && wwsChild->hasAnyColor() == font->hasAnyColor()) {
783 break;
784 }
785 }
786 if (wwsChild != childEnd(wws)) {
787 if (wwsChild->fontFamily == font->fontFamily && wwsChild->fontStyle == font->fontStyle) {
788 // If, for all intends and purposes, the font seems to be the same, merge nodes.
789 // This sometimes happens with installations where the same font is installed in
790 // a variety of formats. We want to prefer the opentype version in any case.
791 if (wwsChild->type != KoSvgText::OpenTypeFontType && font->type == KoSvgText::OpenTypeFontType) {
792 wwsChild->otherFiles.append(wwsChild->fileName);
793 wwsChild->otherFiles.append(font->otherFiles);
794 wwsChild->fileName = font->fileName;
795 wwsChild->type = KoSvgText::OpenTypeFontType;
796 } else {
797 wwsChild->otherFiles.append(font->fileName);
798 wwsChild->otherFiles.append(font->otherFiles);
799 }
800 if (wwsChild->lastModified < font->lastModified) {
801 wwsChild->lastModified = font->lastModified;
802 }
803 break;
804 } else {
805 continue;
806 }
807 } else {
808 /*
809 * Try to match the wws family with the same fontfamily, otherwise select the first candidate.
810 */
811 if (wwsCandidate == childEnd(typographic)) {
812 wwsCandidate = wws;
813 }
814 if (wws->fontFamily == font->fontFamily) {
815 wwsCandidate = wws;
816 break;
817 }
818 }
819 }
820 if (wwsCandidate != childEnd(typographic)) {
821 d->fontFamilyCollection.insert(childEnd(wwsCandidate), *font);
822 } else if (wws == childEnd(typographic)) {
823 FontFamilyNode wwsFamily = FontFamilyNode::createWWSFamilyNode(*font, *typographic, wwsNames);
824 wwsNames.append(wwsFamily.fontFamily);
825 auto newWWS = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
826 if (wwsFamily.fontFamily != typographic->fontFamily) {
827 font->localizedTypographicStyle.clear();
828 }
829 d->fontFamilyCollection.insert(childEnd(newWWS), *font);
830 }
831 }
832 // This only triggers when the first wws family was created with the typographic name,
833 // yet more wws families have followed after sorting was finished, and this name might be not the most precise.
834 if (wwsNames.contains(typographic->fontFamily) && std::distance(childBegin(typographic), childEnd(typographic)) > 1) {
835 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
836 if (wws->fontFamily == typographic->fontFamily) {
837 if (wwsNames.contains(childBegin(wws)->fontFamily)) {
838 const QString otherWWSName = childBegin(wws)->fontFamily;
839 // Also rename any other wwsfamilies that has been using the second style.
840 for (auto otherwws = childBegin(typographic); otherwws != childEnd(typographic); otherwws++) {
841 if (otherwws->fontFamily == otherWWSName) {
842 otherwws->fontFamily = childBegin(otherwws)->fontFamily + " " + childBegin(otherwws)->fontStyle;
843 QHash<QLocale, QString> families;
844 const QHash<QLocale, QString> styles = childBegin(otherwws)->localizedFontStyle;
845 Q_FOREACH (const QLocale l, otherwws->localizedFontFamilies.keys()) {
846 families.insert(l, otherwws->localizedFontFamilies.value(l)+" "+styles.value(l, childBegin(otherwws)->fontStyle));
847 }
848 otherwws->localizedFontFamilies = families;
849 break;
850 }
851 }
852 }
853 wws->fontFamily = childBegin(wws)->fontFamily;
854 childBegin(wws)->localizedTypographicStyle.clear();
855 break;
856 }
857 }
858 }
859 }
860
861 // One final deduplication check.
862
863 for (auto child = childBegin(typographic); child != childEnd(typographic); child++) {
864 if (childBegin(child) != childEnd(child)) {
865 if (wwsNamesDuplicates.contains(child->fontFamily)) {
866 // Here, we try to avoid duplicates in the same typographic family.
868 auto child2 = childBegin(typographic);
869 for (; child2 != childEnd(typographic); child2++) {
870 if (child2->fontFamily == child->fontFamily) {
871 break;
872 }
873 }
874 if (child2 != childEnd(typographic)) {
875 for (auto ribbi = childBegin(child); ribbi != childEnd(child); ribbi++) {
876 auto ribbi2 = childBegin(child2);
877 for (; ribbi2 != childEnd(child2); ribbi2++) {
878 if (ribbi->fontFamily == ribbi2->fontFamily && ribbi->fontStyle == ribbi2->fontStyle) {
879
880 break;
881 }
882 }
883 if (ribbi2 != childEnd(child2)) {
884 ribbi2->otherFiles.append(ribbi->otherFiles);
885 ribbi2->otherFiles.append(ribbi->fileName);
886 ribbi2->pixelSizes.insert(ribbi->pixelSizes);
887 deleteList.append(ribbi);
888 } else {
889 moveList.append(ribbi);
890 }
891 }
892 while (!moveList.isEmpty()) {
893 auto move = moveList.takeFirst();
894 d->fontFamilyCollection.move(move, childEnd(child2));
895 }
896 } else {
897 // Give up when it doesn't share the same typographic family, and just delete the node.
899 for (auto ribbi = childBegin(child); ribbi != childEnd(child); ribbi++) {
900 deleteList.append(ribbi);
901 }
902 }
903 deleteList.append(child);
904 } else {
905 wwsNamesDuplicates.append(child->fontFamily);
906 }
907 }
908 while (!deleteList.isEmpty()) {
909 auto del = deleteList.takeFirst();
911 d->fontFamilyCollection.erase(del);
912 }
913 }
914 }
915}
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 move(child_iterator subtree, child_iterator newPos)
move a subtree to new position Moves subtree into a new position pointer by newPos....
Definition KisForest.h:994
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, KisForestDetail::Forest< T >::move(), 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 1092 of file KoFFWWSConverter.cpp.

1093{
1094 auto it = d->fontFamilyCollection.compositionBegin();
1095 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), familyName);
1096 if (it != d->fontFamilyCollection.compositionEnd()) {
1097
1098 bool isChild = childBegin(it) == childEnd(it);
1099 auto wws = siblingCurrent(it);
1100
1101 // check if we're in a typographic family by testing the hierarchy.
1102 // if so, select the wws family.
1103 auto hierarchy = hierarchyBegin(wws);
1104 hierarchy++;
1105 if (isChild) {
1106 wws = siblingCurrent(hierarchy);
1107 } else if (hierarchy == hierarchyEnd(wws)) {
1108 wws = childBegin(it);
1109 }
1110 return std::make_optional(wws->fontFamily);
1111 }
1112 return std::nullopt;
1113}

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: