Line data Source code
1 : /**
2 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "XLFontController.h"
24 :
25 : #include "XLTemporaryResource.h"
26 : #include "XLTexture.h"
27 : #include "XLFontExtension.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::xenolith::font {
30 :
31 : XL_DECLARE_EVENT_CLASS(FontController, onLoaded)
32 : XL_DECLARE_EVENT_CLASS(FontController, onFontSourceUpdated)
33 :
34 : struct FontController::Builder::Data {
35 : String name;
36 : Rc<FontController> target;
37 : Map<String, FontSource> dataQueries;
38 : Map<String, FamilyQuery> familyQueries;
39 : Map<String, String> aliases;
40 : };
41 :
42 48 : FontController::Builder::~Builder() {
43 48 : if (_data) {
44 24 : delete _data;
45 24 : _data = nullptr;
46 : }
47 48 : }
48 :
49 24 : FontController::Builder::Builder(StringView name) {
50 24 : _data = new Data();
51 24 : _data->name = name.str<Interface>();
52 24 : }
53 :
54 0 : FontController::Builder::Builder(FontController *target) {
55 0 : _data = new Data();
56 0 : _data->target = target;
57 0 : }
58 :
59 24 : FontController::Builder::Builder(Builder &&other) {
60 24 : _data = other._data;
61 24 : other._data = nullptr;
62 24 : }
63 :
64 0 : FontController::Builder &FontController::Builder::operator=(Builder &&other) {
65 0 : if (_data) {
66 0 : delete _data;
67 0 : _data = nullptr;
68 : }
69 :
70 0 : _data = other._data;
71 0 : other._data = nullptr;
72 0 : return *this;
73 : }
74 :
75 24 : StringView FontController::Builder::getName() const {
76 24 : return _data->name;
77 : }
78 72 : FontController *FontController::Builder::getTarget() const {
79 72 : return _data->target ? _data->target.get() : nullptr;
80 : }
81 :
82 24 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, BytesView data) {
83 24 : auto it = _data->dataQueries.find(name);
84 24 : if (it == _data->dataQueries.end()) {
85 24 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
86 24 : it->second.fontExternalData = data;
87 24 : it->second.preconfiguredParams = false;
88 24 : return &it->second;
89 : }
90 :
91 0 : log::warn("FontController", "Duplicate font source: ", name);
92 0 : return nullptr;
93 : }
94 :
95 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, Bytes && data) {
96 0 : auto it = _data->dataQueries.find(name);
97 0 : if (it == _data->dataQueries.end()) {
98 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
99 0 : it->second.fontMemoryData = move(data);
100 0 : it->second.preconfiguredParams = false;
101 0 : return &it->second;
102 : }
103 :
104 0 : log::warn("FontController", "Duplicate font source: ", name);
105 0 : return nullptr;
106 : }
107 :
108 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, FilePath data) {
109 0 : auto it = _data->dataQueries.find(name);
110 0 : if (it == _data->dataQueries.end()) {
111 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
112 0 : it->second.fontFilePath = data.get().str<Interface>();
113 0 : it->second.preconfiguredParams = false;
114 0 : return &it->second;
115 : }
116 :
117 0 : log::warn("FontController", "Duplicate font source: ", name);
118 0 : return nullptr;
119 : }
120 :
121 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, Function<Bytes()> &&cb) {
122 0 : auto it = _data->dataQueries.find(name);
123 0 : if (it == _data->dataQueries.end()) {
124 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
125 0 : it->second.fontCallback = move(cb);
126 0 : it->second.preconfiguredParams = false;
127 0 : return &it->second;
128 : }
129 :
130 0 : log::warn("FontController", "Duplicate font source: ", name);
131 0 : return nullptr;
132 : }
133 :
134 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, BytesView data, FontLayoutParameters params) {
135 0 : auto it = _data->dataQueries.find(name);
136 0 : if (it == _data->dataQueries.end()) {
137 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
138 0 : it->second.fontExternalData = data;
139 0 : it->second.params = params;
140 0 : it->second.preconfiguredParams = true;
141 0 : return &it->second;
142 : }
143 :
144 0 : log::warn("FontController", "Duplicate font source: ", name);
145 0 : return nullptr;
146 : }
147 :
148 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, Bytes && data, FontLayoutParameters params) {
149 0 : auto it = _data->dataQueries.find(name);
150 0 : if (it == _data->dataQueries.end()) {
151 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
152 0 : it->second.fontMemoryData = move(data);
153 0 : it->second.params = params;
154 0 : it->second.preconfiguredParams = true;
155 0 : return &it->second;
156 : }
157 :
158 0 : log::warn("FontController", "Duplicate font source: ", name);
159 0 : return nullptr;
160 : }
161 :
162 0 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, FilePath data, FontLayoutParameters params) {
163 0 : auto it = _data->dataQueries.find(name);
164 0 : if (it == _data->dataQueries.end()) {
165 0 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
166 0 : it->second.fontFilePath = data.get().str<Interface>();
167 0 : it->second.params = params;
168 0 : it->second.preconfiguredParams = true;
169 0 : return &it->second;
170 : }
171 :
172 0 : log::warn("FontController", "Duplicate font source: ", name);
173 0 : return nullptr;
174 : }
175 :
176 72 : const FontController::FontSource * FontController::Builder::addFontSource(StringView name, Function<Bytes()> &&cb, FontLayoutParameters params) {
177 72 : auto it = _data->dataQueries.find(name);
178 72 : if (it == _data->dataQueries.end()) {
179 72 : it = _data->dataQueries.emplace(name.str<Interface>(), FontSource()).first;
180 72 : it->second.fontCallback = move(cb);
181 72 : it->second.params = params;
182 72 : it->second.preconfiguredParams = true;
183 72 : return &it->second;
184 : }
185 :
186 0 : log::warn("FontController", "Duplicate font source: ", name);
187 0 : return nullptr;
188 : }
189 :
190 0 : const FontController::FontSource *FontController::Builder::getFontSource(StringView name) const {
191 0 : auto it = _data->dataQueries.find(name);
192 0 : if (it != _data->dataQueries.end()) {
193 0 : return &it->second;
194 : }
195 0 : return nullptr;
196 : }
197 :
198 96 : const FontController::FamilyQuery * FontController::Builder::addFontFaceQuery(StringView family, const FontSource *source, bool front) {
199 96 : XL_ASSERT(source, "Source should not be nullptr");
200 :
201 96 : auto it = _data->familyQueries.find(family);
202 96 : if (it == _data->familyQueries.end()) {
203 48 : it = _data->familyQueries.emplace(family.str<Interface>(), FamilyQuery{family.str<Interface>()}).first;
204 : }
205 :
206 96 : addSources(&it->second, Vector<const FontSource *>{source}, front);
207 96 : return &it->second;
208 : }
209 :
210 0 : const FontController::FamilyQuery * FontController::Builder::addFontFaceQuery(StringView family, Vector<const FontSource *> &&sources, bool front) {
211 0 : auto it = _data->familyQueries.find(family);
212 0 : if (it == _data->familyQueries.end()) {
213 0 : it = _data->familyQueries.emplace(family.str<Interface>(), FamilyQuery{family.str<Interface>()}).first;
214 : }
215 :
216 0 : addSources(&it->second, move(sources), front);
217 0 : return &it->second;
218 : }
219 :
220 48 : bool FontController::Builder::addAlias(StringView newAlias, StringView familyName) {
221 48 : auto iit = _data->aliases.find(familyName);
222 48 : if (iit != _data->aliases.end()) {
223 0 : _data->aliases.insert_or_assign(newAlias.str<Interface>(), iit->second);
224 0 : return true;
225 : } else {
226 : // check if family defined
227 96 : for (auto &it : _data->familyQueries) {
228 96 : if (it.second.family == familyName) {
229 48 : _data->aliases.insert_or_assign(newAlias.str<Interface>(), it.second.family);
230 48 : return true;
231 : }
232 : }
233 0 : return false;
234 : }
235 : }
236 :
237 0 : Vector<const FontController::FamilyQuery *> FontController::Builder::getFontFamily(StringView family) const {
238 0 : Vector<const FontController::FamilyQuery *> families;
239 0 : for (auto &it : _data->familyQueries) {
240 0 : if (it.second.family == family) {
241 0 : families.emplace_back(&it.second);
242 : }
243 : }
244 0 : return families;
245 0 : }
246 :
247 48 : Map<String, FontController::FontSource> &FontController::Builder::getDataQueries() {
248 48 : return _data->dataQueries;
249 : }
250 :
251 24 : Map<String, FontController::FamilyQuery> &FontController::Builder::getFamilyQueries() {
252 24 : return _data->familyQueries;
253 : }
254 :
255 24 : Map<String, String> &FontController::Builder::getAliases() {
256 24 : return _data->aliases;
257 : }
258 :
259 96 : void FontController::Builder::addSources(FamilyQuery *query, Vector<const FontSource *> &&sources, bool front) {
260 96 : if (query->sources.empty() || !front) {
261 96 : query->sources.reserve(query->sources.size() + sources.size());
262 192 : for (auto &iit : sources) {
263 96 : XL_ASSERT(iit, "Source should not be nullptr");
264 96 : if (std::find(query->sources.begin(), query->sources.end(), iit) == query->sources.end()) {
265 96 : query->sources.emplace_back(iit);
266 : }
267 : }
268 : } else {
269 0 : auto iit = query->sources.begin();
270 0 : while (iit != query->sources.end()) {
271 0 : if (std::find(sources.begin(), sources.end(), *iit) != sources.end()) {
272 0 : iit = query->sources.erase(iit);
273 : } else {
274 0 : ++ iit;
275 : }
276 : }
277 :
278 0 : query->sources.reserve(query->sources.size() + sources.size());
279 :
280 0 : auto insertIt = query->sources.begin();
281 0 : for (auto &source : sources) {
282 0 : XL_ASSERT(source, "Source should not be nullptr");
283 0 : if (std::find(query->sources.begin(), query->sources.end(), source) == query->sources.end()) {
284 0 : query->sources.emplace(insertIt, source);
285 : }
286 : }
287 : }
288 96 : query->addInFront = front;
289 96 : }
290 :
291 48 : FontController::~FontController() {
292 24 : invalidate(nullptr);
293 48 : }
294 :
295 24 : bool FontController::init(const Rc<FontExtension> &ext) {
296 24 : _ext = ext;
297 24 : return true;
298 : }
299 :
300 0 : void FontController::extend(const Callback<bool(FontController::Builder &)> &cb) {
301 0 : Builder builder(this);
302 0 : if (cb(builder)) {
303 0 : _ext->acquireController(move(builder));
304 : }
305 0 : }
306 :
307 0 : void FontController::initialize(Application *) {
308 :
309 0 : }
310 :
311 48 : void FontController::invalidate(Application *) {
312 48 : if (_image) {
313 : // image need to be finalized to remove cycled refs
314 24 : _image->finalize();
315 24 : _image = nullptr;
316 : }
317 48 : }
318 :
319 0 : void FontController::addFont(StringView family, Rc<FontFaceData> &&data, bool front) {
320 0 : std::unique_lock lock(_layoutSharedMutex);
321 0 : auto familyIt = _families.find(family);
322 0 : if (familyIt == _families.end()) {
323 0 : familyIt = _families.emplace(family.str<Interface>(), FamilySpec()).first;
324 0 : _familiesNames.emplace_back(familyIt->first);
325 : }
326 :
327 0 : if (!familyIt->second.data.empty() && front) {
328 0 : familyIt->second.data.emplace(familyIt->second.data.begin(), move(data));
329 : } else {
330 0 : familyIt->second.data.emplace_back(move(data));
331 : }
332 :
333 0 : _dirty = true;
334 0 : lock.unlock();
335 0 : }
336 :
337 48 : void FontController::addFont(StringView family, Vector<Rc<FontFaceData>> &&data, bool front) {
338 48 : std::unique_lock lock(_layoutSharedMutex);
339 48 : auto familyIt = _families.find(family);
340 48 : if (familyIt == _families.end()) {
341 48 : familyIt = _families.emplace(family.str<Interface>(), FamilySpec()).first;
342 48 : _familiesNames.emplace_back(familyIt->first);
343 : }
344 :
345 48 : if (familyIt->second.data.empty()) {
346 48 : familyIt->second.data = move(data);
347 : } else {
348 0 : if (front) {
349 0 : for (auto &it : data) {
350 0 : familyIt->second.data.emplace(familyIt->second.data.begin(), move(it));
351 : }
352 : } else {
353 0 : for (auto &it : data) {
354 0 : familyIt->second.data.emplace_back(move(it));
355 : }
356 : }
357 : }
358 :
359 48 : _dirty = true;
360 48 : lock.unlock();
361 48 : }
362 :
363 0 : bool FontController::addAlias(StringView newAlias, StringView familyName) {
364 0 : std::unique_lock lock(_layoutSharedMutex);
365 0 : if (_aliases.find(newAlias) != _aliases.end()) {
366 0 : return false;
367 : }
368 :
369 0 : auto iit = _aliases.find(familyName);
370 0 : if (iit != _aliases.end()) {
371 0 : _aliases.emplace(newAlias.str<Interface>(), iit->second);
372 0 : return true;
373 : } else {
374 0 : auto f_it = _families.find(familyName);
375 0 : if (f_it != _families.end()) {
376 0 : _aliases.emplace(newAlias.str<Interface>(), familyName.str<Interface>());
377 0 : return true;
378 : }
379 0 : return false;
380 : }
381 0 : }
382 :
383 10559 : Rc<FontFaceSet> FontController::getLayout(FontParameters style) {
384 10559 : Rc<FontFaceSet> ret;
385 :
386 10559 : FontFaceSet *face = nullptr;
387 :
388 10559 : style.fontSize = style.fontSize * style.density;
389 :
390 : // check if layout already loaded
391 10559 : std::shared_lock sharedLock(_layoutSharedMutex);
392 10559 : if (!_loaded) {
393 24 : return nullptr;
394 : }
395 :
396 10535 : if (style.fontFamily.empty()) {
397 0 : style.fontFamily = StringView(_defaultFontFamily);
398 : }
399 :
400 10535 : auto a_it = _aliases.find(style.fontFamily);
401 10535 : if (a_it != _aliases.end()) {
402 3244 : style.fontFamily = a_it->second;
403 : }
404 :
405 10535 : auto familyIt = _families.find(style.fontFamily);
406 10535 : if (familyIt == _families.end()) {
407 0 : return nullptr;
408 : }
409 :
410 : // search for exact match
411 10535 : auto cfgName = FontFaceSet::constructName(style.fontFamily, style);
412 10535 : auto it = _layouts.find(cfgName);
413 10535 : if (it != _layouts.end()) {
414 9751 : face = it->second.get();
415 : }
416 :
417 10535 : FontSpecializationVector spec;
418 10535 : if (!face) {
419 : // find best possible config
420 784 : spec = findSpecialization(familyIt->second, style, nullptr);
421 784 : cfgName = FontFaceSet::constructName(style.fontFamily, spec);
422 784 : auto layoutIt = _layouts.find(cfgName);
423 784 : if (layoutIt != _layouts.end()) {
424 114 : face = layoutIt->second.get();
425 : }
426 : }
427 :
428 10535 : if (face) {
429 9865 : face->touch(_clock, style.persistent);
430 9865 : return face;
431 : }
432 :
433 : // we need to create new layout
434 670 : sharedLock.unlock();
435 670 : std::unique_lock uniqueLock(_layoutSharedMutex);
436 :
437 670 : Vector<Rc<FontFaceData>> data;
438 :
439 : // update best match (if fonts was updated)
440 670 : spec = findSpecialization(familyIt->second, style, &data);
441 670 : cfgName = FontFaceSet::constructName(style.fontFamily, spec);
442 :
443 : // check if somebody already created layout for us in another thread
444 670 : it = _layouts.find(cfgName);
445 670 : if (it != _layouts.end()) {
446 0 : it->second->touch(_clock, style.persistent);
447 0 : return it->second.get();
448 : }
449 :
450 : // create layout
451 670 : ret = Rc<FontFaceSet>::create(move(cfgName), style.fontFamily, move(spec), move(data), _ext->getLibrary());
452 670 : _layouts.emplace(ret->getName(), ret);
453 670 : ret->touch(_clock, style.persistent);
454 670 : return ret;
455 10559 : }
456 :
457 0 : Rc<FontFaceSet> FontController::getLayoutForString(const FontParameters &f, const CharVector &str) {
458 0 : if (auto l = getLayout(f)) {
459 0 : Vector<char32_t> failed;
460 0 : if (f.persistent) {
461 0 : l->addString(str, failed);
462 : } else {
463 0 : l->addString(str, failed);
464 : }
465 0 : return l;
466 0 : }
467 0 : return nullptr;
468 : }
469 :
470 7844 : Rc<core::DependencyEvent> FontController::addTextureChars(const Rc<FontFaceSet> &l, SpanView<CharLayoutData> chars) {
471 7844 : if (l->addTextureChars(chars)) {
472 1148 : if (!_dependency) {
473 2400 : _dependency = Rc<core::DependencyEvent>::alloc(core::DependencyEvent::QueueSet{
474 600 : _ext->getQueue()
475 1800 : });
476 : }
477 1148 : _dirty = true;
478 1148 : return _dependency;
479 : }
480 6696 : return nullptr;
481 : }
482 :
483 0 : uint32_t FontController::getFamilyIndex(StringView name) const {
484 0 : std::shared_lock lock(_layoutSharedMutex);
485 0 : auto it = std::find(_familiesNames.begin(), _familiesNames.end(), name);
486 0 : if (it != _familiesNames.end()) {
487 0 : return it - _familiesNames.begin();
488 : }
489 0 : return maxOf<uint32_t>();
490 0 : }
491 :
492 130 : StringView FontController::getFamilyName(uint32_t idx) const {
493 130 : std::shared_lock lock(_layoutSharedMutex);
494 130 : if (idx < _familiesNames.size()) {
495 0 : return _familiesNames[idx];
496 : }
497 130 : return StringView();
498 130 : }
499 :
500 2357 : void FontController::update(Application *, const UpdateTime &clock) {
501 2357 : _clock = clock.global;
502 2357 : removeUnusedLayouts();
503 2357 : if (_dirty && _loaded) {
504 636 : Vector<FontUpdateRequest> objects;
505 636 : std::shared_lock lock(_layoutSharedMutex);
506 3838 : for (auto &it : _layouts) {
507 9606 : for (auto &iit : it.second->getFaces()) {
508 6404 : if (!iit) {
509 1177 : continue;
510 : }
511 :
512 5227 : auto lb = std::lower_bound(objects.begin(), objects.end(), iit,
513 9837 : [] (const FontUpdateRequest &l, FontFaceObject *r) {
514 9837 : return l.object.get() < r;
515 : });
516 5227 : if (lb == objects.end()) {
517 1542 : auto req = iit->getRequiredChars();
518 1542 : if (!req.empty()) {
519 1179 : objects.emplace_back(FontUpdateRequest{iit, move(req), it.second->isPersistent()});
520 : }
521 5227 : } else if (lb != objects.end() && lb->object != iit) {
522 3685 : auto req = iit->getRequiredChars();
523 3685 : if (!req.empty()) {
524 2023 : objects.emplace(lb, FontUpdateRequest{iit, move(req), it.second->isPersistent()});
525 : }
526 3685 : }
527 : }
528 : }
529 636 : if (!objects.empty()) {
530 612 : _ext->updateImage(_image, move(objects), move(_dependency));
531 612 : _dependency = nullptr;
532 : }
533 636 : _dirty = false;
534 636 : }
535 2357 : }
536 :
537 24 : void FontController::setImage(Rc<core::DynamicImage> &&image) {
538 24 : _image = move(image);
539 24 : _texture = Rc<Texture>::create(_image);
540 24 : }
541 :
542 24 : void FontController::setLoaded(bool value) {
543 24 : if (_loaded != value) {
544 24 : _loaded = value;
545 24 : onLoaded(this);
546 24 : UpdateTime t;
547 24 : t.global = platform::clock(core::ClockType::Monotonic);
548 24 : update(nullptr, t);
549 : }
550 24 : }
551 :
552 0 : void FontController::sendFontUpdatedEvent() {
553 0 : onFontSourceUpdated(this);
554 0 : }
555 :
556 24 : void FontController::setAliases(Map<String, String> &&aliases) {
557 24 : if (_aliases.empty()) {
558 24 : _aliases = move(aliases);
559 : } else {
560 0 : for (auto &it : aliases) {
561 0 : _aliases.insert_or_assign(it.first, it.second);
562 : }
563 : }
564 24 : }
565 :
566 1454 : FontSpecializationVector FontController::findSpecialization(const FamilySpec &family, const FontParameters ¶ms, Vector<Rc<FontFaceData>> *dataList) {
567 2908 : auto getFontFaceScore = [] (const FontLayoutParameters &required, const FontLayoutParameters &existed) -> uint32_t {
568 2908 : uint32_t ret = 0;
569 : // if no match - prefer normal variants
570 2908 : if (existed.fontStyle == FontStyle::Normal) { ret += 50; }
571 2908 : if (existed.fontWeight == FontWeight::Normal) { ret += 50; }
572 2908 : if (existed.fontStretch == FontStretch::Normal) { ret += 50; }
573 :
574 2908 : if ((required.fontStyle == FontStyle::Italic && existed.fontStyle == FontStyle::Italic)
575 2908 : || (required.fontStyle == FontStyle::Normal && existed.fontStyle == FontStyle::Normal)) {
576 1408 : ret += 100000;
577 1500 : } else if (existed.fontStyle == FontStyle::Italic) {
578 24 : if (required.fontStyle != FontStyle::Normal) {
579 0 : ret += ((360 << 6) - std::abs(int(required.fontStyle.get()) - int(FontStyle::Oblique.get()))) / 2;
580 : }
581 1476 : } else if (required.fontStyle == FontStyle::Italic) {
582 0 : if (existed.fontStyle != FontStyle::Normal) {
583 0 : ret += ((360 << 6) - std::abs(int(FontStyle::Oblique.get()) - int(existed.fontStyle.get()))) / 2;
584 : }
585 : } else {
586 1476 : ret += (360 << 6) - std::abs(int(required.fontStyle.get()) - int(existed.fontStyle.get()));
587 : }
588 :
589 2908 : if (existed.fontStyle == required.fontStyle && (existed.fontStyle == FontStyle::Oblique || existed.fontStyle == FontStyle::Italic)) {
590 :
591 5768 : } else if ((existed.fontStyle == FontStyle::Oblique || existed.fontStyle == FontStyle::Italic)
592 5768 : && (required.fontStyle == FontStyle::Oblique || required.fontStyle == FontStyle::Italic)) {
593 0 : ret += 75000; // Oblique-Italic replacement
594 2884 : } else if (existed.fontStyle == required.fontStyle && existed.fontStyle == FontStyle::Normal) {
595 1408 : ret += 50000;
596 : }
597 :
598 2908 : if (existed.fontGrade == required.fontGrade) {
599 2152 : ret += (400 - std::abs(int(required.fontGrade.get()) - int(existed.fontGrade.get()))) * 50;
600 : }
601 :
602 2908 : ret += (1000 - std::abs(int(required.fontWeight.get()) - int(existed.fontWeight.get()))) * 100;
603 2908 : ret += ((250 << 1) - std::abs(int(required.fontStretch.get()) - int(existed.fontStretch.get()))) * 100;
604 2908 : return ret;
605 : };
606 :
607 1454 : uint32_t score = 0;
608 1454 : FontSpecializationVector ret;
609 :
610 1454 : Vector<Pair<FontFaceData *, uint32_t>> scores;
611 :
612 1454 : uint32_t offset = family.data.size();
613 4362 : for (auto &it : family.data) {
614 2908 : auto spec = it->getSpecialization(params);
615 2908 : auto specScore = getFontFaceScore(params, spec) + offset;
616 2908 : if (dataList) {
617 1340 : scores.emplace_back(pair(it.get(), specScore));
618 : }
619 2908 : if (specScore >= score) {
620 1454 : score = specScore;
621 1454 : ret = spec;
622 : }
623 2908 : -- offset;
624 : }
625 :
626 1454 : if (dataList) {
627 670 : std::sort(scores.begin(), scores.end(), [] (const Pair<FontFaceData *, uint32_t> &l, const Pair<FontFaceData *, uint32_t> &r) {
628 1340 : if (l.second == r.second) {
629 0 : return l.first < r.first;
630 : } else {
631 1340 : return l.second > r.second;
632 : }
633 : });
634 :
635 670 : dataList->reserve(scores.size());
636 2010 : for (auto &it : scores) {
637 1340 : dataList->emplace_back(it.first);
638 : }
639 : }
640 :
641 1454 : return ret;
642 1454 : }
643 :
644 2357 : void FontController::removeUnusedLayouts() {
645 2357 : std::unique_lock lock(_layoutSharedMutex);
646 2357 : auto it = _layouts.begin();
647 15267 : while (it != _layouts.end()) {
648 12910 : if (it->second->isPersistent()) {
649 2297 : ++ it;
650 2297 : continue;
651 : }
652 :
653 10613 : if (/*_clock - it->second->getAccessTime() > _unusedInterval.toMicros() &&*/ it->second->getReferenceCount() == 1) {
654 563 : auto c = it->second->getTexturesCount();
655 563 : it = _layouts.erase(it);
656 563 : if (c > 0) {
657 428 : _dirty = true;
658 : }
659 : } else {
660 10050 : ++ it;
661 : }
662 : }
663 2357 : }
664 :
665 : }
|