2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/text/text-abstraction/font-client-impl.h>
22 #include <condition_variable>
25 #if defined(VCONF_ENABLED)
30 #include <dali/devel-api/adaptor-framework/thread-settings.h>
31 #include <dali/devel-api/common/singleton-service.h>
32 #include <dali/internal/system/common/logging.h>
33 #include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
34 #include <dali/internal/window-system/common/window-system.h>
36 #include <dali/devel-api/text-abstraction/glyph-info.h>
38 // Use this macro only if need to log messages before the log function is set.
39 #define FONT_LOG_MESSAGE(level, format, ...) \
43 int result = std::snprintf(buffer, sizeof(buffer), format, ##__VA_ARGS__); \
44 if(result >= static_cast<int>(sizeof(buffer))) \
46 std::string log("Font log message is too long to fit in the buffer.\n"); \
47 Dali::TizenPlatform::LogMessage(Dali::Integration::Log::ERROR, log); \
50 std::string log(buffer); \
51 Dali::TizenPlatform::LogMessage(level, log); \
56 namespace TextAbstraction
60 Dali::TextAbstraction::FontClient FontClient::gPreCreatedFontClient(NULL);
61 std::thread gPreCacheThread;
62 std::thread gPreLoadThread;
64 std::condition_variable gPreCacheCond;
65 std::condition_variable gPreLoadCond;
66 bool gPreCacheThreadReady;
67 bool gPreLoadThreadReady;
69 /* TODO: This is to prevent duplicate calls of font pre-cache.
70 * We may support this later, but currently we can't guarantee the behaviour
71 * if there is a pre-cache call from the user after the font client has been created. */
72 bool gFontPreCacheAvailable = true;
73 bool gFontPreLoadAvailable = true;
75 FontClient::FontClient()
82 FontClient::~FontClient()
87 Dali::TextAbstraction::FontClient FontClient::Get()
89 Dali::TextAbstraction::FontClient fontClientHandle;
91 Dali::SingletonService service(SingletonService::Get());
94 // Check whether the singleton is already created
95 Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::TextAbstraction::FontClient));
98 // If so, downcast the handle
99 FontClient* impl = dynamic_cast<Dali::TextAbstraction::Internal::FontClient*>(handle.GetObjectPtr());
100 fontClientHandle = Dali::TextAbstraction::FontClient(impl);
102 else // create and register the object
104 if(gPreCacheThread.joinable())
106 gPreCacheThread.join();
107 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreCache thread join\n");
110 if(gPreLoadThread.joinable())
112 gPreLoadThread.join();
113 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient PreLoad thread join\n");
116 if(gPreCreatedFontClient)
118 fontClientHandle = gPreCreatedFontClient;
119 gPreCreatedFontClient.Reset(); // No longer needed
123 fontClientHandle = Dali::TextAbstraction::FontClient(new FontClient);
126 fontClientHandle.InitDefaultFontDescription();
128 gFontPreCacheAvailable = false;
129 gFontPreLoadAvailable = false;
131 uint32_t horizontalDpi, verticalDpi;
132 fontClientHandle.GetDpi(horizontalDpi, verticalDpi);
133 if(horizontalDpi == 0u || verticalDpi == 0u)
135 horizontalDpi = verticalDpi = 0u;
136 Dali::Internal::Adaptor::WindowSystem::GetDpi(horizontalDpi, verticalDpi);
137 fontClientHandle.SetDpi(horizontalDpi, verticalDpi);
140 service.Register(typeid(fontClientHandle), fontClientHandle);
144 return fontClientHandle;
147 Dali::TextAbstraction::FontClient FontClient::PreInitialize()
149 // Pre-cached font client already exists or pre-cache thread already running.
150 // Font client pre-cache includes caching of the default font description.
151 if(gPreCreatedFontClient && !gFontPreCacheAvailable)
153 return gPreCreatedFontClient;
156 if(!gPreCreatedFontClient)
158 gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
161 gPreCreatedFontClient.InitDefaultFontDescription();
163 return gPreCreatedFontClient;
166 void FontClient::PreCacheRun(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool syncCreation)
168 SetThreadName("FontThread-fc");
172 std::unique_lock<std::mutex> lock(gMutex);
173 gPreCacheThreadReady = true;
174 gPreCacheCond.notify_one();
178 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_RUN\n");
179 GetImplementation(gPreCreatedFontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
180 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_RUN\n");
183 void FontClient::PreLoadRun(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool syncCreation)
185 SetThreadName("FontThread-ft");
189 std::unique_lock<std::mutex> lock(gMutex);
190 gPreLoadThreadReady = true;
191 gPreLoadCond.notify_one();
195 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_FONT_PRELOAD_RUN\n");
196 GetImplementation(gPreCreatedFontClient).FontPreLoad(fontPathList, memoryFontPathList);
197 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_FONT_PRELOAD_RUN\n");
200 void FontClient::PreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily, bool useThread, bool syncCreation)
202 if(!gFontPreCacheAvailable)
204 FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache run failed, as a pre-cached font client already exists.\n");
208 if(gPreCacheThread.joinable())
210 FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient pre-cache thread already running.\n");
213 if(!gPreCreatedFontClient)
215 gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
218 gFontPreCacheAvailable = false;
220 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache fallbackFamilyList : %zu\n", fallbackFamilyList.size());
221 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache extraFamilyList : %zu\n", extraFamilyList.size());
222 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache localeFamily : %s\n", localeFamily.c_str());
223 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient FontConfig PreCache useThread : %d\n", useThread);
229 // The main thread wakes up upon receiving a notification from the pre-cache thread.
230 // If it doesn't receive a notification within the specified time, it wakes up due to a timeout.
231 const std::chrono::milliseconds timeout(1000);
232 gPreCacheThreadReady = false;
233 std::unique_lock<std::mutex> lock(gMutex);
234 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_PRECACHE_THREAD_SYNC_CREATION\n");
235 gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily, syncCreation);
236 gPreCacheCond.wait_for(lock, timeout, []{return gPreCacheThreadReady;});
237 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_PRECACHE_THREAD_SYNC_CREATION\n");
241 gPreCacheThread = std::thread(PreCacheRun, fallbackFamilyList, extraFamilyList, localeFamily, syncCreation);
246 GetImplementation(gPreCreatedFontClient).FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
250 void FontClient::PreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList, bool useThread, bool syncCreation)
252 if(!gFontPreLoadAvailable)
254 FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load run failed, as a pre-loaded font client already exists.\n");
258 if(gPreLoadThread.joinable())
260 FONT_LOG_MESSAGE(Dali::Integration::Log::ERROR, "FontClient font pre-load thread already running.\n");
264 if(!gPreCreatedFontClient)
266 gPreCreatedFontClient = Dali::TextAbstraction::FontClient(new FontClient);
269 gFontPreLoadAvailable = false;
271 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad fontPathList : %zu\n", fontPathList.size());
272 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad memoryFontPathList : %zu\n", memoryFontPathList.size());
273 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "FontClient Font PreLoad useThread : %d\n", useThread);
279 // The main thread wakes up upon receiving a notification from the pre-load thread.
280 // If it doesn't receive a notification within the specified time, it wakes up due to a timeout.
281 const std::chrono::milliseconds timeout(1000);
282 gPreLoadThreadReady = false;
283 std::unique_lock<std::mutex> lock(gMutex);
284 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "BEGIN: DALI_TEXT_FONT_PRELOAD_THREAD_SYNC_CREATION\n");
285 gPreLoadThread = std::thread(PreLoadRun, fontPathList, memoryFontPathList, syncCreation);
286 gPreLoadCond.wait_for(lock, timeout, []{return gPreLoadThreadReady;});
287 FONT_LOG_MESSAGE(Dali::Integration::Log::INFO, "END: DALI_TEXT_FONT_PRELOAD_THREAD_SYNC_CREATION\n");
291 gPreLoadThread = std::thread(PreLoadRun, fontPathList, memoryFontPathList, syncCreation);
296 GetImplementation(gPreCreatedFontClient).FontPreLoad(fontPathList, memoryFontPathList);
300 void FontClient::ClearCache()
304 mPlugin->ClearCache();
308 void FontClient::SetDpi(unsigned int horizontalDpi, unsigned int verticalDpi)
310 mDpiHorizontal = horizontalDpi;
311 mDpiVertical = verticalDpi;
313 // Allow DPI to be set without loading plugin
316 mPlugin->SetDpi(horizontalDpi, verticalDpi);
320 void FontClient::GetDpi(unsigned int& horizontalDpi, unsigned int& verticalDpi)
322 horizontalDpi = mDpiHorizontal;
323 verticalDpi = mDpiVertical;
326 int FontClient::GetDefaultFontSize()
330 #if defined(VCONF_ENABLED)
331 vconf_get_int(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, &fontSize);
337 void FontClient::ResetSystemDefaults()
341 mPlugin->ResetSystemDefaults();
344 void FontClient::GetDefaultFonts(FontList& defaultFonts)
348 mPlugin->GetDefaultFonts(defaultFonts);
351 void FontClient::FontPreCache(const FontFamilyList& fallbackFamilyList, const FontFamilyList& extraFamilyList, const FontFamily& localeFamily)
355 mPlugin->FontPreCache(fallbackFamilyList, extraFamilyList, localeFamily);
358 void FontClient::FontPreLoad(const FontPathList& fontPathList, const FontPathList& memoryFontPathList)
362 mPlugin->FontPreLoad(fontPathList, memoryFontPathList);
365 void FontClient::InitDefaultFontDescription()
369 mPlugin->InitDefaultFontDescription();
372 void FontClient::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
376 mPlugin->GetDefaultPlatformFontDescription(fontDescription);
379 void FontClient::GetDescription(FontId fontId, FontDescription& fontDescription)
383 mPlugin->GetDescription(fontId, fontDescription);
386 PointSize26Dot6 FontClient::GetPointSize(FontId fontId)
390 return mPlugin->GetPointSize(fontId);
393 bool FontClient::IsCharacterSupportedByFont(FontId fontId, Character character)
397 return mPlugin->IsCharacterSupportedByFont(fontId, character);
400 void FontClient::GetSystemFonts(FontList& systemFonts)
404 mPlugin->GetSystemFonts(systemFonts);
407 FontId FontClient::FindDefaultFont(Character charcode,
408 PointSize26Dot6 requestedPointSize,
413 return mPlugin->FindDefaultFont(charcode,
418 FontId FontClient::FindFallbackFont(Character charcode,
419 const FontDescription& preferredFontDescription,
420 PointSize26Dot6 requestedPointSize,
425 return mPlugin->FindFallbackFont(charcode,
426 preferredFontDescription,
431 bool FontClient::IsScalable(const FontPath& path)
435 return mPlugin->IsScalable(path);
438 bool FontClient::IsScalable(const FontDescription& fontDescription)
442 return mPlugin->IsScalable(fontDescription);
445 void FontClient::GetFixedSizes(const FontPath& path, Dali::Vector<PointSize26Dot6>& sizes)
449 mPlugin->GetFixedSizes(path, sizes);
452 void FontClient::GetFixedSizes(const FontDescription& fontDescription,
453 Dali::Vector<PointSize26Dot6>& sizes)
457 mPlugin->GetFixedSizes(fontDescription, sizes);
460 bool FontClient::HasItalicStyle(FontId fontId) const
466 return mPlugin->HasItalicStyle(fontId);
469 FontId FontClient::GetFontId(const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex)
473 return mPlugin->GetFontIdByPath(path,
479 FontId FontClient::GetFontId(const FontDescription& fontDescription,
480 PointSize26Dot6 requestedPointSize,
485 return mPlugin->GetFontId(fontDescription,
490 FontId FontClient::GetFontId(const BitmapFont& bitmapFont)
494 return mPlugin->GetFontId(bitmapFont);
497 void FontClient::GetFontMetrics(FontId fontId, FontMetrics& metrics)
501 mPlugin->GetFontMetrics(fontId, metrics);
504 GlyphIndex FontClient::GetGlyphIndex(FontId fontId, Character charcode)
508 return mPlugin->GetGlyphIndex(fontId, charcode);
511 GlyphIndex FontClient::GetGlyphIndex(FontId fontId, Character charcode, Character variantSelector)
515 return mPlugin->GetGlyphIndex(fontId, charcode, variantSelector);
518 bool FontClient::GetGlyphMetrics(GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal)
522 return mPlugin->GetGlyphMetrics(array, size, type, horizontal);
525 void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth)
529 mPlugin->CreateBitmap(fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth);
532 PixelData FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth)
536 return mPlugin->CreateBitmap(fontId, glyphIndex, outlineWidth);
539 void FontClient::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
543 mPlugin->CreateVectorBlob(fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight);
546 const GlyphInfo& FontClient::GetEllipsisGlyph(PointSize26Dot6 requestedPointSize)
550 return mPlugin->GetEllipsisGlyph(requestedPointSize);
553 bool FontClient::IsColorGlyph(FontId fontId, GlyphIndex glyphIndex)
557 return mPlugin->IsColorGlyph(fontId, glyphIndex);
560 GlyphIndex FontClient::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
564 return mPlugin->CreateEmbeddedItem(description, pixelFormat);
567 void FontClient::EnableAtlasLimitation(bool enabled)
570 return mPlugin->EnableAtlasLimitation(enabled);
573 bool FontClient::IsAtlasLimitationEnabled() const
577 return mPlugin->IsAtlasLimitationEnabled();
579 return TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED;
582 Size FontClient::GetMaximumTextAtlasSize() const
586 return mPlugin->GetMaximumTextAtlasSize();
588 return TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE;
591 Size FontClient::GetDefaultTextAtlasSize() const
595 return mPlugin->GetDefaultTextAtlasSize();
597 return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE;
600 Size FontClient::GetCurrentMaximumBlockSizeFitInAtlas() const
604 return mPlugin->GetCurrentMaximumBlockSizeFitInAtlas();
606 return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE;
609 bool FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas)
612 return mPlugin->SetCurrentMaximumBlockSizeFitInAtlas(currentMaximumBlockSizeFitInAtlas);
615 uint32_t FontClient::GetNumberOfPointsPerOneUnitOfPointSize() const
619 return mPlugin->GetNumberOfPointsPerOneUnitOfPointSize();
621 return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
625 FT_FaceRec_* FontClient::GetFreetypeFace(FontId fontId)
629 return mPlugin->GetFreetypeFace(fontId);
632 FontDescription::Type FontClient::GetFontType(FontId fontId)
636 return mPlugin->GetFontType(fontId);
639 bool FontClient::AddCustomFontDirectory(const FontPath& path)
643 return mPlugin->AddCustomFontDirectory(path);
646 HarfBuzzFontHandle FontClient::GetHarfBuzzFont(FontId fontId)
650 return mPlugin->GetHarfBuzzFont(fontId);
653 void FontClient::CreatePlugin()
655 std::scoped_lock lock(gMutex);
658 mPlugin = new Plugin(mDpiHorizontal, mDpiVertical);
662 } // namespace Internal
664 } // namespace TextAbstraction