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

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

◆ ~KoFFWWSConverter()

KoFFWWSConverter::~KoFFWWSConverter ( )

Definition at line 265 of file KoFFWWSConverter.cpp.

266{
267}

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';

Definition at line 341 of file KoFFWWSConverter.cpp.

341 {
342
343 FontFamilyNode fontFamily;
344 fontFamily.fileName = filename;
345 fontFamily.fileIndex = index;
346 for (auto it = d->fontFamilyCollection.begin(); it != d->fontFamilyCollection.end(); it++) {
347 if (it->fileName == fontFamily.fileName && it->fileIndex == fontFamily.fileIndex) {
348 return true;
349 }
350 }
351
352 FT_Face f = nullptr;
353 FT_FaceSP face;
354 QByteArray utfData = fontFamily.fileName.toUtf8();
355 if (FT_New_Face(freeTypeLibrary.data(), utfData.data(), fontFamily.fileIndex, &f) == 0) {
356 face.reset(f);
357 } else {
358 return false;
359 }
360
361 fontFamily.fontFamily = face->family_name;
362 fontFamily.fontStyle = face->style_name;
363 fontFamily.lastModified = QFileInfo(fontFamily.fileName).lastModified();
364 FontFamilyNode typographicFamily;
365 FontFamilyNode wwsFamily;
366 bool isWWSFamilyWithoutName = false;
367
368 if (!FT_IS_SFNT(face.data())) {
369 fontFamily.type = FT_IS_SCALABLE(face.data())? KoSvgText::Type1FontType: KoSvgText::BDFFontType;
370
371 fontFamily.isItalic = face->style_flags & FT_STYLE_FLAG_ITALIC;
372 if (face->style_flags & FT_STYLE_FLAG_BOLD) {
374 } else {
376 }
377
378 for (int i=0; i< face->num_fixed_sizes; i++) {
379 // 64 = Freetype pixel
380 fontFamily.pixelSizes.insert((face->available_sizes[i].size / 64.0), {fontFamily.fileName});
381 }
382 } else {
384 hb_face_t_sp hbFace(hb_ft_face_create_referenced(face.data()));
385 hb_font_t_sp hbFont(hb_ft_font_create_referenced(face.data()));
386
387 // Retrieve width, weight and slant data.
388
389 fontFamily.axes.insert(WEIGHT_TAG, KoSvgText::FontFamilyAxis::weightAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WEIGHT)));
390 fontFamily.axes.insert(WIDTH_TAG, KoSvgText::FontFamilyAxis::widthAxis(hb_style_get_value(hbFont.data(), HB_STYLE_TAG_WIDTH)));
391 fontFamily.isItalic = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_ITALIC) > 0;
392 //fontFamily.isOblique = hb_style_get_value(hbFont.data(), HB_STYLE_TAG_SLANT_ANGLE) != 0;
393
394 TT_OS2 *os2Table = nullptr;
395 os2Table = (TT_OS2*)FT_Get_Sfnt_Table(face.data(), FT_SFNT_OS2);
396 if (os2Table) {
397
398 fontFamily.isOblique = os2Table->fsSelection & OS2_OBLIQUE;
399
400 if (os2Table->fsSelection & OS2_REGULAR) {
401 fontFamily.isItalic = false;
402 fontFamily.isOblique = false;
403 }
404
405 if (os2Table->version >= 5) {
406 FontFamilySizeInfo sizeInfo;
407 const qreal twip = 0.05;
408 sizeInfo.high = os2Table->usUpperOpticalPointSize * twip;
409 sizeInfo.low = os2Table->usLowerOpticalPointSize * twip;
410 sizeInfo.os2table = true;
411 sizeInfo.isSet = true;
412 fontFamily.sizeInfo = sizeInfo;
413 }
414 isWWSFamilyWithoutName = (os2Table->fsSelection & OS2_WWS);
415 }
416
417
418 // retrieve gpos size data...
419 uint designSize;
420 uint subFamilyId;
421 uint rangeStart;
422 uint rangeEnd;
423 hb_ot_name_id_t sizeNameId;
424 if (hb_ot_layout_get_size_params(hbFace.data(), &designSize, &subFamilyId, &sizeNameId, &rangeStart, &rangeEnd)) {
425 FontFamilySizeInfo sizeInfo;
426 qreal tenth = 0.1;
427 sizeInfo.low = rangeStart * tenth;
428 sizeInfo.high = rangeEnd * tenth;
429 sizeInfo.subFamilyID = subFamilyId;
430 sizeInfo.designSize = designSize * tenth;
431 sizeInfo.isSet = true;
432 fontFamily.sizeInfo = sizeInfo;
433 }
434
435 // retrieve axis data...
436 // 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.
437
438 QHash<hb_ot_name_id_t, QString> axisNameIDs;
439 QVector<hb_ot_name_id_t> instanceNameIDs;
440 if (hb_ot_var_has_data(hbFace.data())) {
441 fontFamily.isVariable = true;
442 uint count = hb_ot_var_get_axis_count(hbFace.data());
443 uint maxInfos = 1;
444 QStringList axesTags;
445 for (uint i = 0; i < count; i++) {
447 hb_ot_var_axis_info_t axis;
448 hb_ot_var_get_axis_infos(hbFace.data(), i, &maxInfos, &axis);
449 axisInfo.min = axis.min_value;
450 axisInfo.max = axis.max_value;
451 axisInfo.value = axis.default_value;
452 axisInfo.axisHidden = axis.flags & HB_OT_VAR_AXIS_FLAG_HIDDEN;
453 char buff[4];
454 hb_tag_to_string(axis.tag, buff);
455 axisInfo.tag = QString::fromLatin1(buff, 4);
456 axisNameIDs.insert(axis.name_id, axisInfo.tag);
457 axisInfo.variableAxis = true;
458 fontFamily.axes.insert(axisInfo.tag, axisInfo);
459 axesTags.append(axisInfo.tag);
460 }
461 count = hb_ot_var_get_named_instance_count (hbFace.data());
462 for (uint i = 0; i < count; i++) {
463 QHash<QString, float> instanceCoords;
464 uint coordLength = axesTags.size();
465 std::vector<float> coordinate(coordLength);
466 hb_ot_var_named_instance_get_design_coords (hbFace.data(), i, &coordLength, coordinate.data());
467 for (uint j =0; j < coordLength; j++ ){
468 instanceCoords.insert(axesTags.value(j), coordinate[j]);
469 }
471 style.instanceCoords = instanceCoords;
472 instanceNameIDs.append(hb_ot_var_named_instance_get_subfamily_name_id(hbFace.data(), i));
473 fontFamily.styleInfo.append(style);
474 }
475 }
476
477 // Get some basic color data.
478 fontFamily.colorBitMap = hb_ot_color_has_png(hbFace.data());
479 fontFamily.colorSVG = hb_ot_color_has_svg(hbFace.data());
480 fontFamily.colorClrV0 = hb_ot_color_has_layers(hbFace.data());
481 //fontFamily.colorClrV1 = hb_ot_color_has_paint(hbFace);
482 wwsFamily.colorBitMap = fontFamily.colorBitMap;
483 wwsFamily.colorSVG = fontFamily.colorSVG;
484 wwsFamily.colorClrV0 = fontFamily.colorClrV0;
485
486 uint numEntries = 0;
487 const hb_ot_name_entry_t *entries = hb_ot_name_list_names(hbFace.data(), &numEntries);
488
489 QHash<QLocale, QString> ribbiFamilyNames;
490 QHash<QLocale, QString> ribbiStyleNames;
491 QHash<QLocale, QString> WWSFamilyNames;
492 QHash<QLocale, QString> WWSStyleNames;
493 QHash<QLocale, QString> typographicFamilyNames;
494 QHash<QLocale, QString> typographicStyleNames;
495 QHash<QLocale, QString> fullNames;
496 for (uint i = 0; i < numEntries; i++) {
497 hb_ot_name_entry_t entry = entries[i];
498 QString lang(hb_language_to_string(entry.language));
499 QLocale locale(lang);
500 uint length = hb_ot_name_get_utf8(hbFace.data(), entry.name_id, entry.language, nullptr, nullptr)+1;
501 std::vector<char> buff(length);
502 hb_ot_name_get_utf8(hbFace.data(), entry.name_id, entry.language, &length, buff.data());
503 QString name = QString::fromUtf8(buff.data(), length);
504 if (name.isEmpty()) continue;
505
506 if (entry.name_id == HB_OT_NAME_ID_FONT_FAMILY) {
507 ribbiFamilyNames.insert(locale, name);
508 } else if (entry.name_id == HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY) {
509 typographicFamilyNames.insert(locale, name);
510 } else if (entry.name_id == HB_OT_NAME_ID_WWS_FAMILY) {
511 WWSFamilyNames.insert(locale, name);
512 } else if (entry.name_id == HB_OT_NAME_ID_FONT_SUBFAMILY) {
513 ribbiStyleNames.insert(locale, name);
514 } else if (entry.name_id == HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY) {
515 typographicStyleNames.insert(locale, name);
516 } else if (entry.name_id == HB_OT_NAME_ID_WWS_SUBFAMILY) {
517 WWSStyleNames.insert(locale, name);
518 } else if (entry.name_id == HB_OT_NAME_ID_FULL_NAME) {
519 fullNames.insert(locale, name);
520 } 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.
521 if (axisNameIDs.keys().contains(entry.name_id)) {
522 fontFamily.axes[axisNameIDs.value(entry.name_id)].localizedLabels.insert(locale, name);
523 } else if (entry.name_id == sizeNameId) {
524 fontFamily.sizeInfo.localizedLabels.insert(locale, name);
525 } else if (instanceNameIDs.contains(entry.name_id)) {
526 int idx = instanceNameIDs.indexOf(entry.name_id);
527 fontFamily.styleInfo[idx].localizedLabels.insert(locale, name);
528 }
529 }
530 }
531 QLocale english(QLocale::English);
532 if (!typographicFamilyNames.isEmpty()) {
533 typographicFamily.fontFamily = typographicFamilyNames.value(english, typographicFamilyNames.values().first());
534 typographicFamily.localizedFontFamilies = typographicFamilyNames;
535 }
536 fontFamily.localizedTypographicStyle = typographicStyleNames;
537 if (!ribbiFamilyNames.isEmpty()) {
538 fontFamily.fontFamily = ribbiFamilyNames.value(english, ribbiFamilyNames.values().first());
539 fontFamily.localizedFontFamilies = ribbiFamilyNames;
540 }
541 // Second check is a hack to avoid issues with the css test fonts. Why they are configure this way, beats me.
542 // Either way, if the fullname, which has 100% priority is the name as typographic name (which is tested last)
543 // the font search will only select the node with this fullname, which we don't want.
544 if (!fullNames.isEmpty() && fullNames != typographicFamilyNames) {
545 fontFamily.localizedFullName = fullNames;
546 }
547 if (!ribbiStyleNames.isEmpty()) {
548 fontFamily.fontStyle = ribbiStyleNames.value(english, ribbiStyleNames.values().first());
549 fontFamily.localizedFontStyle = ribbiStyleNames;
550 }
551 if (!WWSFamilyNames.isEmpty()) {
552 wwsFamily.fontFamily = WWSFamilyNames.value(english, WWSFamilyNames.values().first());
553 wwsFamily.localizedFontFamilies = WWSFamilyNames;
554 }
555 fontFamily.localizedWWSStyle = WWSStyleNames;
556 }
557
558 if (fontFamily.fontFamily.isEmpty()) {
559 fontFamily.fontFamily = QFileInfo(fontFamily.fileName).baseName();
560 }
561 if (typographicFamily.fontFamily.isEmpty()) {
562 typographicFamily.fontFamily = fontFamily.fontFamily;
563 }
564 wwsFamily.isVariable = fontFamily.isVariable;
565 wwsFamily.type = fontFamily.type;
566 typographicFamily.type = typographicFamily.type;
567
568 if (typographicFamily.fontFamily.isEmpty() && fontFamily.fontFamily.isEmpty()) {
569 d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), fontFamily);
570 } else {
571 // find potential typographic family
572 auto it = d->fontFamilyCollection.childBegin();
573 for (; it != d->fontFamilyCollection.childEnd(); it++) {
574 if (!typographicFamily.fontFamily.isEmpty() && it->fontFamily == typographicFamily.fontFamily) {
575 break;
576 } else if (it->fontFamily == fontFamily.fontFamily) {
577 break;
578 }
579 }
580 if (it != d->fontFamilyCollection.childEnd()) {
581
582 if (isWWSFamilyWithoutName) {
583 wwsFamily.fontFamily = fontFamily.fontFamily;
584 }
585 if (!wwsFamily.fontFamily.isEmpty()) {
586 // sort into wws family
587 auto wws = childBegin(it);
588 for (; wws != childEnd(it); wws++) {
589 if (wws->fontFamily == wwsFamily.fontFamily) {
590 break;
591 }
592 }
593 if (wws != childEnd(it)) {
594 d->fontFamilyCollection.insert(childEnd(wws), fontFamily);
595 } else {
596 auto wwsNew = d->fontFamilyCollection.insert(childEnd(it), wwsFamily);
597 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
598 }
599 } else if (!fontFamily.pixelSizes.isEmpty()) {
600 // sort any pixel sizes into the appropriate family.
601 auto pixel = childBegin(it);
602 for (; pixel != childEnd(it); pixel++) {
603 if (pixel->fontFamily == fontFamily.fontFamily && pixel->fontStyle == fontFamily.fontStyle && !pixel->pixelSizes.isEmpty()) {
604 for (int pxSize = 0; pxSize < fontFamily.pixelSizes.keys().size(); pxSize++) {
605 int px = fontFamily.pixelSizes.keys().at(pxSize);
606 QStringList files = pixel->pixelSizes.value(px, QStringList());
607 files.append(fontFamily.pixelSizes.value(px));
608 pixel->pixelSizes.insert(px, files);
609 }
610 break;
611 }
612 }
613 if (pixel == childEnd(it)) {
614 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
615 }
616
617 } else {
618 d->fontFamilyCollection.insert(childEnd(it), fontFamily);
619 }
620 } else {
621 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
622 if (isWWSFamilyWithoutName) {
623 wwsFamily.fontFamily = fontFamily.fontFamily;
624 }
625 if (!wwsFamily.fontFamily.isEmpty()) {
626 auto wwsNew = d->fontFamilyCollection.insert(childEnd(typographic), wwsFamily);
627 d->fontFamilyCollection.insert(childEnd(wwsNew), fontFamily);
628 } else {
629 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
630 }
631 }
632 }
633 return true;
634}
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 283 of file KoFFWWSConverter.cpp.

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

848{
849 FontFamilyNode typographicFamily;
850 FontFamilyNode fontFamily;
851
852 QHash<QLocale, QString> familyNames = {{QLocale(QLocale::English), name}};
853 // TODO: can and should we translate this?
854 QHash<QLocale, QString> styleNames = {{QLocale(QLocale::English), "Regular"}};
855
856 fontFamily.fontFamily = name;
857 fontFamily.localizedFontFamilies = familyNames;
858
860
861 typographicFamily = fontFamily;
863 fontFamily.fontStyle = styleNames.values().first();
864 fontFamily.localizedFontStyle = styleNames;
865 QString tag = KoWritingSystemUtils::sampleTagForQLocale(QLocale(QLocale::English));
866 fontFamily.sampleStrings.insert(tag, KoWritingSystemUtils::samples().key(tag));
867
868 auto typographic = d->fontFamilyCollection.insert(d->fontFamilyCollection.childEnd(), typographicFamily);
869 d->fontFamilyCollection.insert(childEnd(typographic), fontFamily);
870}
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 637 of file KoFFWWSConverter.cpp.

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

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

1083{
1084 QVector<FontFileEntry> candidateFileNames;
1085
1086 int pixelSize = info.size * (qMin(xRes, yRes) / 72.0);
1087
1088 Q_FOREACH(const QString &family, info.families) {
1089 auto it = d->fontFamilyCollection.compositionBegin();
1090 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), family);
1091 if (it != d->fontFamilyCollection.compositionEnd()) {
1092 auto wws = siblingCurrent(it);
1093
1094 // check if we're in a typographic family by testing the hierarchy.
1095 // if so, select all subnodes.
1096 // Because we test subtree depth-first for finding the nodes, wws
1097 // and full names are tested before typographic.
1098 auto hierarchy = hierarchyBegin(wws);
1099 hierarchy++;
1100 QVector<FontFamilyNode> candidates;
1101 if (hierarchy == hierarchyEnd(wws)) {
1102 auto nodes = subtreeBegin(wws);
1103 auto endNodes = subtreeEnd(wws);
1104 for (;nodes != endNodes; nodes++) {
1105 if (childBegin(nodes) == childEnd(nodes)) {
1106 candidates.append(*nodes);
1107 }
1108 }
1109 } else if (childBegin(wws) == childEnd(wws)) {
1110 candidates.append(*wws);
1111 } else {
1112 auto style = childBegin(wws);
1113 auto styleEnd = childEnd(wws);
1114 for (;style != styleEnd; style++) {
1115 candidates.append(*style);
1116 }
1117 }
1118
1119 if (candidates.size() > 1) {
1120 // first find width
1121 candidates = findNodesByAxis(candidates, WIDTH_TAG, info.width, 100.0, 100.0);
1122 }
1123
1124 if (candidates.size() > 1) {
1125 // then find weight
1126 candidates = findNodesByAxis(candidates, WEIGHT_TAG, info.weight, 400.0, 500.0);
1127 }
1128 // then match italic
1129 if (candidates.size() > 1) {
1131 QVector<FontFamilyNode> obliques;
1132
1133 if (wws->isVariable) {
1134 qreal slantValue = info.slantMode == QFont::StyleItalic? 11: info.autoSlant? 14: info.slantValue;
1135 italics = findNodesByAxis(candidates, ITALIC_TAG, 1.0, 0.0, 0.0);
1136 obliques = findNodesByAxis(candidates, SLANT_TAG, -slantValue, 0.0, 0.0);
1137 }
1138 if (italics.isEmpty() && obliques.isEmpty()) {
1139 Q_FOREACH(const FontFamilyNode &node, candidates) {
1140 if (node.isItalic) {
1141 if (!node.isOblique) {
1142 italics.append(node);
1143 } else {
1144 obliques.append(node);
1145 }
1146 }
1147 }
1148 }
1149
1150 if (info.slantMode == QFont::StyleItalic) {
1151 if (!italics.isEmpty()) {
1152 candidates = italics;
1153 } else if (!obliques.isEmpty()) {
1154 candidates = obliques;
1155 }
1156 } else if (info.slantMode == QFont::StyleOblique) {
1157 if (!obliques.isEmpty()) {
1158 candidates = obliques;
1159 } else if (!italics.isEmpty()) {
1160 candidates = italics;
1161 }
1162 } else {
1163 QStringList slantedFontFiles;
1165 Q_FOREACH(const FontFamilyNode &italic, italics) {
1166 slantedFontFiles.append(italic.fileName);
1167 }
1168 Q_FOREACH(const FontFamilyNode &oblique, obliques) {
1169 slantedFontFiles.append(oblique.fileName);
1170 }
1171 Q_FOREACH(const FontFamilyNode &node, candidates) {
1172 if (!slantedFontFiles.contains(node.fileName)) {
1173 regular.append(node);
1174 }
1175 }
1176 if (!regular.isEmpty()) {
1177 candidates = regular;
1178 }
1179 }
1180 }
1181
1182 // prefer opentype
1183 if (candidates.size() > 1) {
1184 QVector<FontFamilyNode> openType;
1185 Q_FOREACH(const FontFamilyNode &node, candidates) {
1186 if (node.type == KoSvgText::OpenTypeFontType) {
1187 openType.append(node);
1188 }
1189 }
1190 if (!openType.isEmpty()) {
1191 candidates = openType;
1192 }
1193 }
1194
1195 // finally, match size.
1196 Q_FOREACH(const FontFamilyNode &node, candidates) {
1197 QStringList fileNames = node.otherFiles;
1198 fileNames.append(node.fileName);
1199 fileNames = node.pixelSizes.value(pixelSize, fileNames);
1200 Q_FOREACH(const QString &fileName, fileNames) {
1201 if (fileName.isEmpty()) continue;
1202 FontFileEntry entry;
1203 entry.fileName = fileName;
1204 entry.fontIndex = node.fileIndex;
1205 candidateFileNames.append(entry);
1206 }
1207 }
1208 }
1209 }
1210 return candidateFileNames;
1211}
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 945 of file KoFFWWSConverter.cpp.

946{
948 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
949 auto counter = childBegin(typographic);
950 counter++;
951 bool singleFamily = childBegin(typographic) != childEnd(typographic) && std::next(childBegin(typographic)) == childEnd(typographic);
952
953 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
954
955 collection.append(createRepresentation(wws, typographic, singleFamily));
956 }
957 }
958 return collection;
959}
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 1213 of file KoFFWWSConverter.cpp.

1214{
1215 qDebug() << "Debug for font family collection" << KisForestDetail::size(d->fontFamilyCollection);
1216 QString spaces;
1217 for (auto it = compositionBegin(d->fontFamilyCollection); it != compositionEnd(d->fontFamilyCollection); it++) {
1218 if (it.state() == KisForestDetail::Enter) {
1219 QStringList debugInfo = it->debugInfo();
1220 for (int i = 0; i< debugInfo.size(); i++) {
1221 if (i==0) {
1222 qDebug().noquote() << QString(spaces + "+") << debugInfo.at(i);
1223 } else {
1224 qDebug().noquote() << QString(spaces + "| ") << debugInfo.at(i);
1225 }
1226 }
1227 spaces.append(" ");
1228 }
1229
1230 if (it.state() == KisForestDetail::Leave) {
1231 spaces.chop(4);
1232 }
1233 }
1234}
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 998 of file KoFFWWSConverter.cpp.

999{
1000 for (auto typographic = d->fontFamilyCollection.childBegin(); typographic != d->fontFamilyCollection.childEnd(); typographic++) {
1001 auto counter = childBegin(typographic);
1002 counter++;
1003 bool singleFamily = counter == childEnd(typographic);
1004
1005 for (auto wws = childBegin(typographic); wws != childEnd(typographic); wws++) {
1006 if (wws->fontFamily == familyName) {
1007 return std::make_optional(createRepresentation(wws, typographic, singleFamily));
1008 }
1009 }
1010 }
1011 return std::nullopt;
1012}

References createRepresentation(), and d.

◆ sortIntoWWSFamilies()

void KoFFWWSConverter::sortIntoWWSFamilies ( )

Sort any straggling fonts into WWSFamilies.

Definition at line 666 of file KoFFWWSConverter.cpp.

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

1015{
1016 auto it = d->fontFamilyCollection.compositionBegin();
1017 it = searchNodes(it, d->fontFamilyCollection.compositionEnd(), familyName);
1018 if (it != d->fontFamilyCollection.compositionEnd()) {
1019
1020 bool isChild = childBegin(it) == childEnd(it);
1021 auto wws = siblingCurrent(it);
1022
1023 // check if we're in a typographic family by testing the hierarchy.
1024 // if so, select the wws family.
1025 auto hierarchy = hierarchyBegin(wws);
1026 hierarchy++;
1027 if (isChild) {
1028 wws = siblingCurrent(hierarchy);
1029 } else if (hierarchy == hierarchyEnd(wws)) {
1030 wws = childBegin(it);
1031 }
1032 return std::make_optional(wws->fontFamily);
1033 }
1034 return std::nullopt;
1035}

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: