Krita Source Code Documentation
Loading...
Searching...
No Matches
FontStyleModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include "FontStyleModel.h"
7#include <QDebug>
9#include <KisResourceModel.h>
10#include <KoFontRegistry.h>
12
13const QString WEIGHT_TAG = "wght";
14const QString WIDTH_TAG = "wdth";
15const QString SLANT_TAG = "slnt";
16const QString ITALIC_TAG = "ital";
17const QString OPTICAL_TAG = "opsz";
18
24
26 : QAbstractItemModel(parent)
27 , d(new Private)
28{
30 QList<QLocale> locales;
31 Q_FOREACH (const QString langCode, KLocalizedString::languages()) {
32 locales.append(QLocale(langCode));
33 }
34 d->locales = locales;
35}
36
40// sort the font styles in any given manner.
42
43 for (auto it = a.instanceCoords.begin(); it != a.instanceCoords.end(); it++) {
44 if (it.key() == ITALIC_TAG || it.key() == SLANT_TAG) continue;
45 qreal other = b.instanceCoords.value(it.key());
46 if (it.value() < other) return true;
47 }
48 // todo: support slant and ital variation axes.
49 QFont::Style aStyle = a.isItalic? a.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
50 QFont::Style bStyle = b.isItalic? a.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
51 return aStyle < bStyle;
52}
53
55{
56 beginResetModel();
57 std::sort(styles.begin(), styles.end(), styleLowerThan);
58 d->styles = styles;
59 endResetModel();
60}
61
63{
64 return d->styles.value(row).instanceCoords.value(WEIGHT_TAG, 400.0);
65}
66
68{
69 return d->styles.value(row).instanceCoords.value(WIDTH_TAG, 100.0);
70}
71
73{
74 KoSvgText::FontFamilyStyleInfo style = d->styles.value(row);
75 QFont::Style styleType = style.isItalic? style.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
76 if (style.instanceCoords.value(ITALIC_TAG, 0) != 0) {
77 styleType = QFont::StyleItalic;
78 } else if (style.instanceCoords.value(SLANT_TAG, 0) != 0) {
79 styleType = QFont::StyleOblique;
80 }
81 return styleType;
82}
83
85{
86 return -(d->styles.value(row).instanceCoords.value(SLANT_TAG, 0));
87}
88
89QVariantHash FontStyleModel::axesValues(int row)
90{
91 return data(index(row, 0), AxisValues).toHash();
92}
93
94#include <KoCssTextUtils.h>
95QHash<int, KoSvgText::FontFamilyStyleInfo> searchAxisTag(const QString &tag,
96 const qreal &value,
97 const QVector<qreal> &values,
98 const qreal &defaultVal,
99 const qreal &defaultValUpper,
100 const QHash<int, KoSvgText::FontFamilyStyleInfo> &styles) {
101 QHash<int, KoSvgText::FontFamilyStyleInfo> filteredStyles;
102 bool shouldNotReturnDefault = ((tag == ITALIC_TAG || tag == SLANT_TAG) && value != defaultVal);
103 qreal selectedValue = KoCssTextUtils::cssSelectFontStyleValue(values, value, defaultVal, defaultValUpper, shouldNotReturnDefault);
104 for (auto it = styles.begin(); it!= styles.end(); it++) {
105 qreal val = defaultVal;
106 if (it.value().instanceCoords.contains(tag)) {
107 val = it.value().instanceCoords.value(tag, defaultVal);
108 } else {
109 if (it.value().isItalic && tag == ITALIC_TAG) {
110 val = 1.0;
111 }
112 if (it.value().isOblique && it.value().isItalic && tag == SLANT_TAG) {
113 val = -14.0;
114 }
115 }
116
117 if (qFuzzyCompare(val, selectedValue)) {
118 if (shouldNotReturnDefault && qFuzzyCompare(val, defaultVal)) continue;
119 filteredStyles.insert(it.key(), it.value());
120 }
121 }
122 return filteredStyles;
123}
124
125int FontStyleModel::rowForStyle(const qreal &weight, const qreal &width, const int &styleMode, const qreal &styleValue)
126{
127 QHash<int, KoSvgText::FontFamilyStyleInfo> styles;
128 QVector<qreal> weights;
129 QVector<qreal> widths;
130 QVector<qreal> slants;
131 QVector<qreal> italics;
132 for (int i = 0; i< d->styles.size(); i++) {
133 styles.insert(i, d->styles.at(i));
134 weights.append(d->styles.value(i).instanceCoords.value(WEIGHT_TAG, 400.0));
135 widths.append(d->styles.value(i).instanceCoords.value(WIDTH_TAG, 100.0));
136 int fontStyle = d->styles.value(i).isItalic? d->styles.value(i).isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
137 if (d->styles.value(i).instanceCoords.contains(SLANT_TAG) || fontStyle == QFont::StyleOblique) {
138 slants.append(d->styles.value(i).instanceCoords.value(SLANT_TAG, -11.0));
139 }
140 if (d->styles.value(i).instanceCoords.contains(ITALIC_TAG) || fontStyle == QFont::StyleItalic) {
141 italics.append(d->styles.value(i).instanceCoords.value(ITALIC_TAG, 1.0));
142 }
143 }
144
145 if (styles.size() > 1) {
146 styles = searchAxisTag(WIDTH_TAG, width, widths, 100.0, 100.0, styles);
147 }
148 if (styles.size() > 1) {
149 styles = searchAxisTag(WEIGHT_TAG, weight, weights, 400.0, 500.0, styles);
150 }
151 // Test all the italics and slant stuff, complete with fallbacks...
152 if (styles.size() > 1) {
153 QHash<int, KoSvgText::FontFamilyStyleInfo> italicStyles;
154 QHash<int, KoSvgText::FontFamilyStyleInfo> obliqueStyles;
155 if (!slants.isEmpty()) {
156 obliqueStyles = searchAxisTag(SLANT_TAG,
157 styleMode == QFont::StyleItalic? -11.0: -styleValue, slants,
158 0.0,
159 0.0,
160 styles);
161 }
162 if (!italics.isEmpty()) {
163 italicStyles = searchAxisTag(ITALIC_TAG,
164 1.0,
165 italics,
166 0.0,
167 0.0,
168 styles);
169 }
170 if (styleMode == QFont::StyleItalic) {
171 if (!italicStyles.isEmpty()) {
172 styles = italicStyles;
173 } else if (!obliqueStyles.isEmpty()) {
174 styles = obliqueStyles;
175 }
176 } else if (styleMode == QFont::StyleOblique) {
177 if (!obliqueStyles.isEmpty()) {
178 styles = obliqueStyles;
179 } else if (!italicStyles.isEmpty()) {
180 styles = italicStyles;
181 }
182 } else {
183 QHash<int, KoSvgText::FontFamilyStyleInfo> regularStyles;
184 for (auto it = styles.begin(); it!= styles.end(); it++) {
185 if (!obliqueStyles.contains(it.key()) && !italicStyles.contains(it.key())) {
186 regularStyles.insert(it.key(), it.value());
187 }
188 }
189 if (!regularStyles.isEmpty()) styles = regularStyles;
190 }
191 }
192 return styles.isEmpty()? 0: styles.keys().first();
193}
194
196{
197 QStringList families = textPropertiesModel->fontFamilies();
199
200 if (!families.isEmpty() && d->fontModel) {
201
202 std::optional<QString> name = KoFontRegistry::instance()->wwsNameByFamilyName(families.first());
203 QString familyName = !name? families.first(): name.value();
204
205 QVector<KoResourceSP> res = d->fontModel->resourcesForFilename(familyName);
206 if (!res.isEmpty()) {
207 KoFontFamilySP family = res.first().staticCast<KoFontFamily>();
208 if (family) {
209 styles = family->styles();
210 }
211 }
212 }
213 setStylesInfo(styles);
214}
215
216QModelIndex FontStyleModel::index(int row, int column, const QModelIndex &parent) const
217{
218 Q_UNUSED(parent)
219 if (column != 0) return QModelIndex();
220 if (row >= 0 && row < d->styles.size()) return createIndex(row, column, &row);
221 return QModelIndex();
222}
223
224QModelIndex FontStyleModel::parent(const QModelIndex &child) const
225{
226 Q_UNUSED(child)
227 return QModelIndex();
228}
229
230int FontStyleModel::rowCount(const QModelIndex &parent) const
231{
232 Q_UNUSED(parent)
233 return d->styles.size();
234}
235
236int FontStyleModel::columnCount(const QModelIndex &parent) const
237{
238 Q_UNUSED(parent)
239 return 1;
240}
241
242QVariant FontStyleModel::data(const QModelIndex &index, int role) const
243{
244 if (!index.isValid()) return QVariant();
245
246 KoSvgText::FontFamilyStyleInfo style = d->styles.at(index.row());
247 if (role == Qt::DisplayRole) {
248 if (style.localizedLabels.isEmpty()) return QString();
249 QString label = style.localizedLabels.value(QLocale(QLocale::English), style.localizedLabels.values().first());
250 Q_FOREACH(const QLocale &locale, d->locales) {
251 if (style.localizedLabels.keys().contains(locale)) {
252 label = style.localizedLabels.value(locale, label);
253 break;
254 }
255 }
256 return label;
257 } else if (role == Weight){
258 return style.instanceCoords.value(WEIGHT_TAG, 400.0);
259 } else if (role == Width){
260 return style.instanceCoords.value(WIDTH_TAG, 100.0);
261 } else if (role == StyleMode){
262 QFont::Style styleType = style.isItalic? style.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
263 if (style.instanceCoords.value(ITALIC_TAG, 0) != 0) {
264 styleType = QFont::StyleItalic;
265 } else if (style.instanceCoords.value(SLANT_TAG, 0) != 0) {
266 styleType = QFont::StyleOblique;
267 }
268 return styleType;
269 } else if (role == Slant){
270 return -(style.instanceCoords.value(SLANT_TAG, 0));
271 } else if (role == AxisValues) {
272 QVariantHash vals;
273 for (auto it = style.instanceCoords.begin(); it != style.instanceCoords.end(); it++) {
274 if (!(it.key() == WEIGHT_TAG
275 || it.key() == WIDTH_TAG
276 || it.key() == SLANT_TAG
277 || it.key() == ITALIC_TAG)) {
278 vals.insert(it.key(), QVariant::fromValue(it.value()));
279 }
280 }
281 return vals;
282 }
283 return QVariant();
284}
285
286QHash<int, QByteArray> FontStyleModel::roleNames() const
287{
288 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
289 roles[Weight] = "weight";
290 roles[Width] = "width";
291 roles[StyleMode] = "stylemode";
292 roles[Slant] = "slant";
293 roles[AxisValues] = "axisvalues";
294 return roles;
295}
const QString SLANT_TAG
QHash< int, KoSvgText::FontFamilyStyleInfo > searchAxisTag(const QString &tag, const qreal &value, const QVector< qreal > &values, const qreal &defaultVal, const qreal &defaultValUpper, const QHash< int, KoSvgText::FontFamilyStyleInfo > &styles)
const QString WEIGHT_TAG
const QString ITALIC_TAG
const QString WIDTH_TAG
static bool styleLowerThan(const KoSvgText::FontFamilyStyleInfo &a, const KoSvgText::FontFamilyStyleInfo &b)
const QString OPTICAL_TAG
float value(const T *src, size_t ch)
const QString SLANT_TAG
const QString WEIGHT_TAG
const QString ITALIC_TAG
const QString WIDTH_TAG
Q_INVOKABLE void setFromTextPropertiesModel(KoSvgTextPropertiesModel *textPropertiesModel)
Update styles model from current text properties.
Q_INVOKABLE QVariantHash axesValues(int row)
Q_INVOKABLE int styleModeValue(int row)
int rowCount(const QModelIndex &parent) const override
Q_INVOKABLE qreal weightValue(int row)
int columnCount(const QModelIndex &parent) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE qreal widthValue(int row)
QVariant data(const QModelIndex &index, int role) const override
QHash< int, QByteArray > roleNames() const override
@ AxisValues
other axis values
@ StyleMode
QFont::Style.
@ Width
qreal, represents 'wdth'
@ Weight
qreal, represents 'wgth'
@ Slant
qreal, represents 'slnt'
QModelIndex parent(const QModelIndex &child) const override
Q_INVOKABLE qreal slantValue(int row)
Q_INVOKABLE int rowForStyle(const qreal &weight, const qreal &width, const int &styleMode, const qreal &styleValue)
Find the closest style that represents the current width, weight and stylemode.
const QScopedPointer< Private > d
void setStylesInfo(QList< KoSvgText::FontFamilyStyleInfo > styles)
Set the base style info;.
FontStyleModel(QObject *parent=nullptr)
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
static qreal cssSelectFontStyleValue(const QVector< qreal > &values, const qreal targetValue, const qreal defaultValue, const qreal defaultValueUpper, const bool shouldNotReturnDefault)
cssSelectFontStyleValue Select the closest font style value from the list, following the CSS Fonts se...
The KoFontFamily class Abstract representation of a Weight/Width/Slant font family,...
std::optional< QString > wwsNameByFamilyName(const QString familyName) const
static KoFontRegistry * instance()
The KoSvgTextPropertiesModel class.
static bool qFuzzyCompare(half p1, half p2)
const QString FontFamilies
QList< KoSvgText::FontFamilyStyleInfo > styles
KisResourceModel * fontModel
QHash< QString, float > instanceCoords
Definition KoSvgText.h:816
QHash< QLocale, QString > localizedLabels
Definition KoSvgText.h:815