(cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
fi
- (cd build ; cmake .. -DMODULE=$1 ; make -j7 )
+ (cd build ; cmake .. -DCMAKE_VERBOSE_MAKEFILE=ON -DMODULE=$1 ; make -j7 )
}
if [ -n "$1" ] ; then
dali2-core
dali2-adaptor
ecore
+ freetype2>=9.16.3
)
+
+
ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror )
ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
-# Shouldn't have to do this!
-# But CMake's new auto-escape quote policy doesn't work right.
-CMAKE_POLICY(SET CMP0005 OLD)
-ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
-ADD_DEFINITIONS(-DADDON_LIBS_PATH=\"\\\"${CMAKE_CURRENT_BINARY_DIR}\\\"\" )
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\" )
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+ADD_DEFINITIONS(-DADDON_LIBS_PATH=\"${CMAKE_CURRENT_BINARY_DIR}\" )
FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
#include <dali-test-suite-utils.h>
#include <dali/dali.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
#include <dali/devel-api/text-abstraction/font-client.h>
-#include <dali/internal/text/text-abstraction/font-client-helper.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
+#include <iostream>
using namespace Dali;
DALI_TEST_EQUALS(numberOfPointsPerOneUnitOfPointSize, TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE, TEST_LOCATION);
END_TEST;
-}
\ No newline at end of file
+}
+
+using namespace Dali::TextAbstraction;
+
+int UtcDaliFontClientGetDefaultFonts(void)
+{
+ TestApplication application;
+ tet_infoline(" UtcDaliFontClientGetDefaultFonts ");
+
+ FontClient fontClient;
+ fontClient = FontClient::Get();
+
+ FontList fontList;
+ fontClient.GetDefaultFonts(fontList);
+
+ std::ostringstream oss;
+ oss << fontList << std::endl;
+
+ tet_printf("FontList: %s", oss.str().c_str());
+ DALI_TEST_CHECK(fontList.size() > 0);
+
+ END_TEST;
+}
+
+int UtcDaliFontClientGetSystemFonts(void)
+{
+ TestApplication application;
+ tet_infoline(" UtcDaliFontClientGetSystemFonts ");
+
+ FontClient fontClient;
+ fontClient = FontClient::Get();
+
+ FontList fontList;
+ fontClient.GetSystemFonts(fontList);
+
+ std::ostringstream oss;
+ oss << fontList << std::endl;
+
+ tet_printf("FontList: %s", oss.str().c_str());
+ DALI_TEST_CHECK(fontList.size() > 0);
+
+ const PointSize26Dot6 pointSize = fontClient.GetPointSize(fontList.size());
+ DALI_TEST_EQUALS(pointSize, FontClient::DEFAULT_POINT_SIZE, TEST_LOCATION);
+
+ END_TEST;
+}
+
+std::ostream& operator<<(std::ostream& o, const FontDescription& description)
+{
+ o << "Font path: " << description.path << " family: "
+ << " width : " << description.width << " weight : " << description.weight << " slant : " << description.slant << std::endl;
+ return o;
+}
+
+int UtcDaliFontClientGetDefaultPlatformFontDescription(void)
+{
+ TestApplication application;
+ tet_infoline(" UtcDaliFontClientGetDefaultPlatformFontDescription");
+
+ FontClient fontClient;
+ fontClient = FontClient::Get();
+
+ FontDescription fontDescription;
+ fontClient.GetDefaultPlatformFontDescription(fontDescription);
+
+ std::ostringstream oss;
+ oss << fontDescription;
+ tet_printf("%s", oss.str().c_str());
+
+ DALI_TEST_CHECK(fontDescription.path.empty() == false);
+
+ FontId fontId = fontClient.FindFallbackFont('A',
+ fontDescription,
+ FontClient::DEFAULT_POINT_SIZE,
+ true);
+
+ bool supported = fontClient.IsCharacterSupportedByFont(fontId, 'A');
+ DALI_TEST_EQUALS(supported, true, TEST_LOCATION);
+ END_TEST;
+}
+
+namespace
+{
+constexpr uint8_t U1 = 1u;
+constexpr uint8_t U2 = 2u;
+constexpr uint8_t U3 = 3u;
+constexpr uint8_t U4 = 4u;
+constexpr uint8_t U5 = 5u;
+constexpr uint8_t U6 = 6u;
+constexpr uint8_t U0 = 0u;
+constexpr uint8_t UTF8_LENGTH[256] = {
+ U1, U1, U1, U1, U1, U1, U1, U1, U1, U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, // lead byte = 0xxx xxxx (U+0000 - U+007F + some extended ascii characters)
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1,
+ U1, //
+ U1,
+ U1, //
+
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2, //
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2, // lead byte = 110x xxxx (U+0080 - U+07FF)
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2,
+ U2, //
+ U2,
+ U2, //
+
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3, // lead byte = 1110 xxxx (U+0800 - U+FFFF)
+ U3,
+ U3,
+ U3,
+ U3,
+ U3,
+ U3, //
+
+ U4,
+ U4,
+ U4,
+ U4,
+ U4,
+ U4,
+ U4,
+ U4, // lead byte = 1111 0xxx (U+10000 - U+1FFFFF)
+
+ U5,
+ U5,
+ U5,
+ U5, // lead byte = 1111 10xx (U+200000 - U+3FFFFFF)
+
+ U6,
+ U6, // lead byte = 1111 110x (U+4000000 - U+7FFFFFFF)
+
+ U0,
+ U0, // Non valid.
+};
+
+constexpr uint8_t CR = 0xd;
+constexpr uint8_t LF = 0xa;
+
+uint8_t GetUtf8Length(uint8_t utf8LeadByte)
+{
+ return UTF8_LENGTH[utf8LeadByte];
+}
+
+uint32_t Utf8ToUtf32(const uint8_t* const utf8, uint32_t length, uint32_t* utf32)
+{
+ uint32_t numberOfCharacters = 0u;
+
+ const uint8_t* begin = utf8;
+ const uint8_t* end = utf8 + length;
+
+ for(; begin < end; ++numberOfCharacters)
+ {
+ const uint8_t leadByte = *begin;
+
+ switch(UTF8_LENGTH[leadByte])
+ {
+ case U1:
+ {
+ if(CR == leadByte)
+ {
+ // Replace CR+LF or CR by LF
+ *utf32++ = LF;
+
+ // Look ahead if the next one is a LF.
+ ++begin;
+ if(begin < end)
+ {
+ if(LF == *begin)
+ {
+ ++begin;
+ }
+ }
+ }
+ else
+ {
+ *utf32++ = leadByte;
+ begin++;
+ }
+ break;
+ }
+
+ case U2:
+ {
+ uint32_t& code = *utf32++;
+ code = leadByte & 0x1fu;
+ begin++;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ break;
+ }
+
+ case U3:
+ {
+ uint32_t& code = *utf32++;
+ code = leadByte & 0x0fu;
+ begin++;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ break;
+ }
+
+ case U4:
+ {
+ uint32_t& code = *utf32++;
+ code = leadByte & 0x07u;
+ begin++;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ break;
+ }
+
+ case U5:
+ {
+ uint32_t& code = *utf32++;
+ code = leadByte & 0x03u;
+ begin++;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ break;
+ }
+
+ case U6:
+ {
+ uint32_t& code = *utf32++;
+ code = leadByte & 0x01u;
+ begin++;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ code <<= 6u;
+ code |= *begin++ & 0x3fu;
+ break;
+ }
+
+ case U0: // Invalid case
+ {
+ begin++;
+ *utf32++ = 0x20; // Use white space
+ break;
+ }
+ }
+ }
+
+ return numberOfCharacters;
+}
+
+TextAbstraction::FontId SetupBitmapFont()
+{
+ struct GlyphDesc
+ {
+ GlyphDesc()
+ {
+ }
+ GlyphDesc(const std::string& url, const std::string& utf8)
+ {
+ this->url = url;
+ std::copy(utf8.begin(), utf8.end(), this->utf8);
+ }
+ std::string url;
+ uint8_t utf8[4];
+ };
+ std::vector<GlyphDesc> glyphs;
+
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0030.png", ":"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0031.png", "0"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0032.png", "1"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0033.png", "2"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0034.png", "3"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0035.png", "4"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0036.png", "5"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0037.png", "6"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0038.png", "7"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u0039.png", "8"});
+ glyphs.push_back({TEST_RESOURCE_DIR "/fonts/bitmap/u003a.png", "9"});
+
+ TextAbstraction::BitmapFont bitmapFont;
+ bitmapFont.glyphs.reserve(glyphs.size());
+ bitmapFont.name = "Digits";
+ bitmapFont.underlinePosition = 0.f;
+ bitmapFont.underlineThickness = 0.f;
+ bitmapFont.isColorFont = true;
+
+ for(const auto& glyph : glyphs)
+ {
+ uint32_t c = 0u;
+ Utf8ToUtf32(glyph.utf8, GetUtf8Length(glyph.utf8[0u]), &c);
+ TextAbstraction::BitmapGlyph bitmapGlyph(glyph.url, c, 34.f, 0.f);
+ bitmapFont.glyphs.push_back(std::move(bitmapGlyph));
+ }
+
+ TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+ return fontClient.GetFontId(bitmapFont);
+}
+
+} // namespace
+
+int UtcDaliFontClientTestBitmapFont(void)
+{
+ TestApplication application;
+ tet_infoline(" UtcDaliFontClientTestBitmapFont");
+
+ FontClient fontClient;
+ fontClient = FontClient::Get();
+
+ auto bitmapFontId = SetupBitmapFont();
+
+ FontDescription fontDescription;
+ fontClient.GetDescription(bitmapFontId, fontDescription);
+ std::ostringstream oss;
+ oss << fontDescription;
+ tet_printf("Found: %d: %s", bitmapFontId, oss.str().c_str());
+
+ bool color = fontClient.IsColorGlyph(bitmapFontId, fontClient.GetGlyphIndex(bitmapFontId, '2'));
+ DALI_TEST_EQUALS(color, true, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(fontClient.GetPointSize(bitmapFontId), FontClient::DEFAULT_POINT_SIZE, TEST_LOCATION);
+
+ DALI_TEST_EQUALS(fontClient.IsCharacterSupportedByFont(bitmapFontId, '3'), true, TEST_LOCATION);
+ DALI_TEST_EQUALS(fontClient.IsCharacterSupportedByFont(bitmapFontId, 'a'), false, TEST_LOCATION);
+
+ END_TEST;
+}
ADD_COMPILE_OPTIONS(-O0 -ggdb --coverage -Wall -Werror)
ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
-# Shouldn't have to do this!
-# But CMake's new auto-escape quote policy doesn't work right.
-CMAKE_POLICY(SET CMP0005 OLD)
-ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\" )
FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
/**
* @brief Retrieves a unique font identifier for a given bitmap font.
+ * If the font is not present, it will cache the given font, and give it a new font id.
*
* @param[in] bitmapFont A bitmap font.
*
- * @return A valid font identifier, or zero if no bitmap font is created.
+ * @return A valid font identifier.
*/
FontId GetFontId(const BitmapFont& bitmapFont);
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeAction class is to correspond with Dali::Accessibility::Action.
+ */
class BridgeAction : public virtual BridgeBase
{
protected:
BridgeAction() = default;
+ /**
+ * @brief Registers Action functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Action object of the currently executed DBus method call.
+ *
+ * @return The Action object
+ */
Dali::Accessibility::Action* FindSelf() const;
public:
+ /**
+ * @copydoc Dali::Accessibility::Action::GetActionName()
+ */
DBus::ValueOrError<std::string> GetActionName(int32_t index);
+
+ /**
+ * @copydoc Dali::Accessibility::Action::GetLocalizedActionName()
+ */
DBus::ValueOrError<std::string> GetLocalizedActionName(int32_t index);
+
+ /**
+ * @copydoc Dali::Accessibility::Action::GetActionDescription()
+ */
DBus::ValueOrError<std::string> GetActionDescription(int32_t index);
+
+ /**
+ * @copydoc Dali::Accessibility::Action::GetActionKeyBinding()
+ */
DBus::ValueOrError<std::string> GetActionKeyBinding(int32_t index);
- DBus::ValueOrError<int32_t> GetActionCount();
- DBus::ValueOrError<bool> DoAction(int32_t index);
- DBus::ValueOrError<bool> DoActionName(std::string name);
+
+ /**
+ * @copydoc Dali::Accessibility::Action::GetActionCount()
+ */
+ DBus::ValueOrError<int32_t> GetActionCount();
+
+ /**
+ * @copydoc Dali::Accessibility::Action::DoAction()
+ */
+ DBus::ValueOrError<bool> DoAction(int32_t index);
+
+ /**
+ * @copydoc Dali::Accessibility::Action::DoAction()
+ */
+ DBus::ValueOrError<bool> DoActionName(std::string name);
};
#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
-/*
+/**
+ * @brief The BridgeApplication class is to correspond with Dali::Accessibility::Application.
+ *
* Implementation of org.a11y.atspi.Application interface
*/
-
class BridgeApplication : public virtual BridgeBase
{
protected:
BridgeApplication() = default;
+ /**
+ * @brief Registers Application functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Application object of the currently executed DBus method call.
+ *
+ * @return The Application object
+ */
Dali::Accessibility::Application* FindSelf() const;
public:
using namespace Dali::Accessibility;
+namespace
+{
+/**
+ * @brief Enumeration used for quering Accessibility objects.
+ *
+ * Refer to MatchType enumeration.
+ */
+enum class AtspiCollection
+{
+ MATCH_INVALID,
+ MATCH_ALL,
+ MATCH_ANY,
+ MATCH_NONE,
+ MATCH_EMPTY,
+ MATCH_LAST_DEFINED,
+};
+} // anonymous namespace
+
void BridgeCollection::RegisterInterfaces()
{
DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection};
return collectionInterface;
}
-enum
-{
- ATSPI_Collection_MATCH_INVALID,
- ATSPI_Collection_MATCH_ALL,
- ATSPI_Collection_MATCH_ANY,
- ATSPI_Collection_MATCH_NONE,
- ATSPI_Collection_MATCH_EMPTY,
- ATSPI_Collection_MATCH_LAST_DEFINED,
-};
-
+/**
+ * @brief The BridgeCollection::Comparer structure.
+ *
+ * Once the data is de-serialized by DBusWrapper, the data of match rule is passed
+ * to Comparer type which do the comparison against a single accessible object.
+ */
struct BridgeCollection::Comparer
{
using Mode = MatchType;
+ /**
+ * @brief Enumeration to check the object is found first.
+ */
enum class CompareFuncExit
{
FIRST_FOUND,
{
switch(mode)
{
- case ATSPI_Collection_MATCH_INVALID:
+ case static_cast<int32_t>(AtspiCollection::MATCH_INVALID):
{
return Mode::INVALID;
}
- case ATSPI_Collection_MATCH_ALL:
+ case static_cast<int32_t>(AtspiCollection::MATCH_ALL):
{
return Mode::ALL;
}
- case ATSPI_Collection_MATCH_ANY:
+ case static_cast<int32_t>(AtspiCollection::MATCH_ANY):
{
return Mode::ANY;
}
- case ATSPI_Collection_MATCH_NONE:
+ case static_cast<int32_t>(AtspiCollection::MATCH_NONE):
{
return Mode::NONE;
}
- case ATSPI_Collection_MATCH_EMPTY:
+ case static_cast<int32_t>(AtspiCollection::MATCH_EMPTY):
{
return Mode::EMPTY;
}
return Mode::INVALID;
}
+ /**
+ * @brief The ComparerInterfaces structure
+ */
struct ComparerInterfaces
{
- std::unordered_set<std::string> object;
- std::vector<std::string> requested;
- Mode mode = Mode::INVALID;
+ std::unordered_set<std::string> mObject;
+ std::vector<std::string> mRequested;
+ Mode mMode = Mode::INVALID;
ComparerInterfaces(MatchRule* rule)
- : mode(ConvertToMatchType(std::get<Index::InterfacesMatchType>(*rule)))
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::INTERFACES_MATCH_TYPE)>(*rule)))
{
- requested = {std::get<Index::Interfaces>(*rule).begin(), std::get<Index::Interfaces>(*rule).end()};
+ mRequested = {std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).begin(), std::get<static_cast<std::size_t>(Index::INTERFACES)>(*rule).end()};
}
void Update(Accessible* obj)
{
- object.clear();
+ mObject.clear();
for(auto& interface : obj->GetInterfaces())
{
- object.insert(std::move(interface));
+ mObject.insert(std::move(interface));
}
}
- bool RequestEmpty() const
+ bool IsRequestEmpty() const
{
- return requested.empty();
+ return mRequested.empty();
}
- bool ObjectEmpty() const
+ bool IsObjectEmpty() const
{
- return object.empty();
+ return mObject.empty();
}
bool Compare(CompareFuncExit exit)
{
bool foundAny = false;
- for(auto& iname : requested)
+ for(auto& iname : mRequested)
{
- bool found = (object.find(iname) != object.end());
+ bool found = (mObject.find(iname) != mObject.end());
if(found)
{
foundAny = true;
}
}; // ComparerInterfaces struct
+ /**
+ * @brief The ComparerAttributes structure
+ */
struct ComparerAttributes
{
- std::unordered_map<std::string, std::string> requested, object;
- Mode mode = Mode::INVALID;
+ std::unordered_map<std::string, std::string> mRequested;
+ std::unordered_map<std::string, std::string> mObject;
+ Mode mMode = Mode::INVALID;
ComparerAttributes(MatchRule* rule)
- : mode(ConvertToMatchType(std::get<Index::AttributesMatchType>(*rule)))
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ATTRIBUTES_MATCH_TYPE)>(*rule)))
{
- requested = std::get<Index::Attributes>(*rule);
+ mRequested = std::get<static_cast<std::size_t>(Index::ATTRIBUTES)>(*rule);
}
void Update(Accessible* obj)
{
- object = obj->GetAttributes();
+ mObject = obj->GetAttributes();
}
- bool RequestEmpty() const
+ bool IsRequestEmpty() const
{
- return requested.empty();
+ return mRequested.empty();
}
- bool ObjectEmpty() const
+ bool IsObjectEmpty() const
{
- return object.empty();
+ return mObject.empty();
}
bool Compare(CompareFuncExit exit)
{
bool foundAny = false;
- for(auto& iname : requested)
+ for(auto& iname : mRequested)
{
- auto it = object.find(iname.first);
- bool found = it != object.end() && iname.second == it->second;
+ auto it = mObject.find(iname.first);
+ bool found = it != mObject.end() && iname.second == it->second;
if(found)
{
foundAny = true;
}
}; // ComparerAttributes struct
+ /**
+ * @brief The ComparerRoles structure
+ */
struct ComparerRoles
{
using Roles = BitSets<4, Role>;
- Roles requested, object;
- Mode mode = Mode::INVALID;
+
+ Roles mRequested;
+ Roles mObject;
+ Mode mMode = Mode::INVALID;
ComparerRoles(MatchRule* rule)
- : mode(ConvertToMatchType(std::get<Index::RolesMatchType>(*rule)))
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::ROLES_MATCH_TYPE)>(*rule)))
{
- requested = Roles{std::get<Index::Roles>(*rule)};
+ mRequested = Roles{std::get<static_cast<std::size_t>(Index::ROLES)>(*rule)};
}
void Update(Accessible* obj)
{
- object = {};
- object[obj->GetRole()] = true;
- assert(object);
+ mObject = {};
+ mObject[obj->GetRole()] = true;
+ assert(mObject);
}
- bool RequestEmpty() const
+ bool IsRequestEmpty() const
{
- return !requested;
+ return !mRequested;
}
- bool ObjectEmpty() const
+ bool IsObjectEmpty() const
{
- return !object;
+ return !mObject;
}
bool Compare(CompareFuncExit exit)
{
- switch(mode)
+ switch(mMode)
{
case Mode::INVALID:
{
case Mode::EMPTY:
case Mode::ALL:
{
- return requested == (object & requested);
+ return mRequested == (mObject & mRequested);
}
case Mode::ANY:
{
- return bool(object & requested);
+ return bool(mObject & mRequested);
}
case Mode::NONE:
{
- return bool(object & requested);
+ return bool(mObject & mRequested);
}
}
return false;
}
}; // ComparerRoles struct
+ /**
+ * @brief The ComparerStates structure
+ */
struct ComparerStates
{
- States requested, object;
- Mode mode = Mode::INVALID;
+ States mRequested;
+ States mObject;
+ Mode mMode = Mode::INVALID;
ComparerStates(MatchRule* rule)
- : mode(ConvertToMatchType(std::get<Index::StatesMatchType>(*rule)))
+ : mMode(ConvertToMatchType(std::get<static_cast<std::size_t>(Index::STATES_MATCH_TYPE)>(*rule)))
{
- requested = States{std::get<Index::States>(*rule)};
+ mRequested = States{std::get<static_cast<std::size_t>(Index::STATES)>(*rule)};
}
void Update(Accessible* obj)
{
- object = obj->GetStates();
+ mObject = obj->GetStates();
}
- bool RequestEmpty() const
+ bool IsRequestEmpty() const
{
- return !requested;
+ return !mRequested;
}
- bool ObjectEmpty() const
+ bool IsObjectEmpty() const
{
- return !object;
+ return !mObject;
}
bool Compare(CompareFuncExit exit)
{
- switch(mode)
+ switch(mMode)
{
case Mode::INVALID:
{
case Mode::EMPTY:
case Mode::ALL:
{
- return requested == (object & requested);
+ return mRequested == (mObject & mRequested);
}
case Mode::ANY:
{
- return bool(object & requested);
+ return bool(mObject & mRequested);
}
case Mode::NONE:
{
- return bool(object & requested);
+ return bool(mObject & mRequested);
}
}
return false;
template<typename T>
bool CompareFunc(T& cmp, Accessible* obj)
{
- if(cmp.mode == Mode::INVALID)
+ if(cmp.mMode == Mode::INVALID)
{
return true;
}
cmp.Update(obj);
- switch(cmp.mode)
+ switch(cmp.mMode)
{
case Mode::ANY:
{
- if(cmp.RequestEmpty() || cmp.ObjectEmpty())
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
{
return false;
}
}
case Mode::ALL:
{
- if(cmp.RequestEmpty())
+ if(cmp.IsRequestEmpty())
{
return true;
}
- if(cmp.ObjectEmpty())
+ if(cmp.IsObjectEmpty())
{
return false;
}
}
case Mode::NONE:
{
- if(cmp.RequestEmpty() || cmp.ObjectEmpty())
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
{
return true;
}
}
case Mode::EMPTY:
{
- if(cmp.RequestEmpty() && cmp.ObjectEmpty())
+ if(cmp.IsRequestEmpty() && cmp.IsObjectEmpty())
{
return true;
}
- if(cmp.RequestEmpty() || cmp.ObjectEmpty())
+ if(cmp.IsRequestEmpty() || cmp.IsObjectEmpty())
{
return false;
}
}
}
- switch(cmp.mode)
+ switch(cmp.mMode)
{
case Mode::EMPTY:
case Mode::ALL:
return true;
}
}
- switch(cmp.mode)
+
+ switch(cmp.mMode)
{
case Mode::EMPTY:
case Mode::ALL:
return false;
}
- ComparerInterfaces interface;
- ComparerAttributes attribute;
- ComparerRoles role;
- ComparerStates state;
-
- Comparer(MatchRule* mr)
- : interface(mr),
- attribute(mr),
- role(mr),
- state(mr)
+ Comparer(MatchRule* rule)
+ : mInterface(rule),
+ mAttribute(rule),
+ mRole(rule),
+ mState(rule)
{
}
bool operator()(Accessible* obj)
{
- return CompareFunc(interface, obj) &&
- CompareFunc(attribute, obj) &&
- CompareFunc(role, obj) &&
- CompareFunc(state, obj);
+ return CompareFunc(mInterface, obj) &&
+ CompareFunc(mAttribute, obj) &&
+ CompareFunc(mRole, obj) &&
+ CompareFunc(mState, obj);
}
+
+ ComparerInterfaces mInterface;
+ ComparerAttributes mAttribute;
+ ComparerRoles mRole;
+ ComparerStates mState;
}; // BridgeCollection::Comparer struct
-void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& cmp, size_t maxCount)
+
+void BridgeCollection::VisitNodes(Accessible* obj, std::vector<Accessible*>& result, Comparer& comparer, size_t maxCount)
{
if(maxCount > 0 && result.size() >= maxCount)
{
return;
}
- if(cmp(obj))
+ if(comparer(obj))
{
result.emplace_back(obj);
}
for(auto i = 0u; i < obj->GetChildCount(); ++i)
{
- VisitNodes(obj->GetChildAtIndex(i), result, cmp, maxCount);
+ VisitNodes(obj->GetChildAtIndex(i), result, comparer, maxCount);
}
}
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeCollection class is to correspond with Dali::Accessibility::Collection.
+ *
+ * Collection interface is designed to allow AT-Clients to query the tree of accessibility objects
+ * exposed by an application with a single dbus call.
+ * The query takes as an input a match rule and returns zero or more matching accessibility objects as a result.
+ *
+ * A match rule can be a combination of at least one of four criteria :
+ * Interface, Attribute, Role, State
+ *
+ * If more than one criteria is specified, the matching rule combines them using "AND" semantics.
+ */
class BridgeCollection : public virtual BridgeBase
{
private:
struct Comparer;
- static void VisitNodes(Dali::Accessibility::Accessible* obj, std::vector<Dali::Accessibility::Accessible*>& result, Comparer& cmp, size_t maxCount);
+
+ /**
+ * @brief Visits all nodes of Accessible object and pushes the object to 'result' container.
+ *
+ * To query the entire tree, the BridgeCollection::Comparer is used inside this method,
+ * which traverse the tree using GetChildAtIndex().
+ * @param[in] obj The Accessible object to search
+ * @param[out] result The vector container for result
+ * @param[in] comparer BridgeCollection::Comparer which do the comparison against a single accessible object
+ * @param[in] maxCount The maximum count of containing Accessible object
+ */
+ static void VisitNodes(Dali::Accessibility::Accessible* obj, std::vector<Dali::Accessibility::Accessible*>& result, Comparer& comparer, size_t maxCount);
protected:
BridgeCollection() = default;
+ /**
+ * @brief Registers Collection functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Collection object of the currently executed DBus method call.
+ *
+ * @return The Collection object
+ */
Dali::Accessibility::Collection* FindSelf() const;
public:
+ /**
+ * MatchRule type is a tuple that only carries data of de-serialized parameter from BridgeCollection::GetMatches dbus method.
+ */
using MatchRule = std::tuple<
std::array<int32_t, 2>,
int32_t,
std::vector<std::string>,
int32_t,
bool>;
- struct Index
+
+ /**
+ * @brief Enumeration for Collection Index.
+ */
+ enum class Index
{
- enum
- {
- States,
- StatesMatchType,
- Attributes,
- AttributesMatchType,
- Roles,
- RolesMatchType,
- Interfaces,
- InterfacesMatchType,
- };
+ STATES,
+ STATES_MATCH_TYPE,
+ ATTRIBUTES,
+ ATTRIBUTES_MATCH_TYPE,
+ ROLES,
+ ROLES_MATCH_TYPE,
+ INTERFACES,
+ INTERFACES_MATCH_TYPE,
};
+ /**
+ * @brief Gets the matching Accessible objects with MatchRule.
+ *
+ * @param[in] rule BridgeCollection::MatchRule
+ * @param[in] sortBy SortOrder::CANONICAL or SortOrder::REVERSE_CANONICAL
+ * @param[in] count The maximum number of objects
+ * @param[in] traverse True if it is traverse, otherwise false.
+ * @return The matching Accessible objects
+ */
DBus::ValueOrError<std::vector<Dali::Accessibility::Accessible*> > GetMatches(MatchRule rule, uint32_t sortBy, int32_t count, bool traverse);
};
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeComponent class is to correspond with Dali::Accessibility::Component.
+ */
class BridgeComponent : public virtual BridgeBase
{
protected:
+ /**
+ * @brief Constructor.
+ */
BridgeComponent();
+ /**
+ * @brief Registers Component functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Component object of the currently executed DBus method call.
+ *
+ * @return The Component object
+ */
Dali::Accessibility::Component* FindSelf() const;
public:
- DBus::ValueOrError<bool> IsAccessibleContainingPoint(int32_t x, int32_t y, uint32_t coordType);
- DBus::ValueOrError<Dali::Accessibility::Accessible*> GetAccessibleAtPoint(int32_t x, int32_t y, uint32_t coordType);
+ /**
+ * @copydoc Dali::Accessibility::Component::IsAccessibleContainingPoint()
+ */
+ DBus::ValueOrError<bool> IsAccessibleContainingPoint(int32_t x, int32_t y, uint32_t coordType);
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GetAccessibleAtPoint()
+ */
+ DBus::ValueOrError<Dali::Accessibility::Accessible*> GetAccessibleAtPoint(int32_t x, int32_t y, uint32_t coordType);
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GetExtents()
+ */
DBus::ValueOrError<std::tuple<int32_t, int32_t, int32_t, int32_t> > GetExtents(uint32_t coordType);
- DBus::ValueOrError<int32_t, int32_t> GetPosition(uint32_t coordType);
- DBus::ValueOrError<int32_t, int32_t> GetSize(uint32_t coordType);
- DBus::ValueOrError<Dali::Accessibility::ComponentLayer> GetLayer();
- DBus::ValueOrError<double> GetAlpha();
- DBus::ValueOrError<bool> GrabFocus();
- DBus::ValueOrError<bool> GrabHighlight();
- DBus::ValueOrError<bool> ClearHighlight();
- DBus::ValueOrError<int16_t> GetMdiZOrder();
+
+ /**
+ * @brief Gets the position from the given coordinate.
+ * @param[in] coordType The enumeration with type of coordinate systems
+ * @return The X and Y position of rectangle
+ */
+ DBus::ValueOrError<int32_t, int32_t> GetPosition(uint32_t coordType);
+
+ /**
+ * @brief Gets the size from the given coordinate.
+ * @param[in] coordType The enumeration with type of coordinate systems
+ * @return The width and height of rectangle
+ */
+ DBus::ValueOrError<int32_t, int32_t> GetSize(uint32_t coordType);
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GetLayer()
+ */
+ DBus::ValueOrError<Dali::Accessibility::ComponentLayer> GetLayer();
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GetAlpha()
+ */
+ DBus::ValueOrError<double> GetAlpha();
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GrabFocus()
+ */
+ DBus::ValueOrError<bool> GrabFocus();
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GrabHighlight()
+ */
+ DBus::ValueOrError<bool> GrabHighlight();
+
+ /**
+ * @copydoc Dali::Accessibility::Component::ClearHighlight()
+ */
+ DBus::ValueOrError<bool> ClearHighlight();
+
+ /**
+ * @copydoc Dali::Accessibility::Component::GetMdiZOrder()
+ */
+ DBus::ValueOrError<int16_t> GetMdiZOrder();
};
#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H
return editableTextInterface;
}
-DBus::ValueOrError<bool> BridgeEditableText::CopyText(int32_t startPos, int32_t endPos)
+DBus::ValueOrError<bool> BridgeEditableText::CopyText(int32_t startPosition, int32_t endPosition)
{
- return FindSelf()->CopyText(startPos, endPos);
+ return FindSelf()->CopyText(startPosition, endPosition);
}
-DBus::ValueOrError<bool> BridgeEditableText::CutText(int32_t startPos, int32_t endPos)
+DBus::ValueOrError<bool> BridgeEditableText::CutText(int32_t startPosition, int32_t endPosition)
{
- return FindSelf()->CutText(startPos, endPos);
+ return FindSelf()->CutText(startPosition, endPosition);
}
-DBus::ValueOrError<bool> BridgeEditableText::DeleteText(int32_t startPos, int32_t endPos)
+DBus::ValueOrError<bool> BridgeEditableText::DeleteText(int32_t startPosition, int32_t endPosition)
{
- return FindSelf()->DeleteText(startPos, endPos);
+ return FindSelf()->DeleteText(startPosition, endPosition);
}
-DBus::ValueOrError<bool> BridgeEditableText::InsertText(int32_t startPos, std::string text, [[maybe_unused]] int32_t length)
+DBus::ValueOrError<bool> BridgeEditableText::InsertText(int32_t startPosition, std::string text, [[maybe_unused]] int32_t length)
{
- return FindSelf()->InsertText(startPos, std::move(text));
+ return FindSelf()->InsertText(startPosition, std::move(text));
}
-DBus::ValueOrError<bool> BridgeEditableText::PasteText(int32_t pos)
+DBus::ValueOrError<bool> BridgeEditableText::PasteText(int32_t position)
{
// auto imfManager = Dali::Internal::Adaptor::ImfManager::Get();
- // imfManager.SetCursorPosition( pos );
+ // imfManager.SetCursorPosition( position );
// auto clipboard = Dali::Internal::Adaptor::Clipboard::Get();
// clipboard.RequestItem();
// return true;
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeEditableText class is to correspond with Dali::Accessibility::EditableText.
+ */
class BridgeEditableText : public virtual BridgeBase
{
protected:
BridgeEditableText() = default;
+ /**
+ * @brief Registers EditableText functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the EditableText object of the currently executed DBus method call.
+ *
+ * @return The EditableText object
+ */
Dali::Accessibility::EditableText* FindSelf() const;
public:
- DBus::ValueOrError<bool> CopyText(int32_t startPos, int32_t endPos);
- DBus::ValueOrError<bool> CutText(int32_t startPos, int32_t endPos);
- DBus::ValueOrError<bool> DeleteText(int32_t startPos, int32_t endPos);
- DBus::ValueOrError<bool> InsertText(int32_t startPos, std::string text, int32_t length);
- DBus::ValueOrError<bool> PasteText(int32_t pos);
+ /**
+ * @copydoc Dali::Accessibility::EditableText::CopyText()
+ */
+ DBus::ValueOrError<bool> CopyText(int32_t startPosition, int32_t endPosition);
+
+ /**
+ * @copydoc Dali::Accessibility::EditableText::CutText()
+ */
+ DBus::ValueOrError<bool> CutText(int32_t startPosition, int32_t endPosition);
+
+ /**
+ * @copydoc Dali::Accessibility::EditableText::DeleteText()
+ */
+ DBus::ValueOrError<bool> DeleteText(int32_t startPosition, int32_t endPosition);
+
+ /**
+ * @copydoc Dali::Accessibility::EditableText::InsertText()
+ */
+ DBus::ValueOrError<bool> InsertText(int32_t startPosition, std::string text, int32_t length);
+
+ /**
+ * @brief Pastes text at position.
+ *
+ * @param[in] position The text position
+ * @return True on success, false otherwise
+ * @note Currently, this function is not implemented yet.
+ */
+ DBus::ValueOrError<bool> PasteText(int32_t position);
+
+ /**
+ * @copydoc Dali::Accessibility::EditableText::SetTextContents()
+ */
DBus::ValueOrError<bool> SetTextContents(std::string newContents);
};
void BridgeObject::RegisterInterfaces()
{
// DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject };
- // stateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
+ // mStateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
// mDbusServer.addInterface("/", desc, true);
}
{"", "root"});
}
-void BridgeObject::Emit(Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent ev)
+void BridgeObject::Emit(Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent event)
{
if(!IsUp()) return;
const char* name = nullptr;
- switch(ev)
+ switch(event)
{
case ObjectPropertyChangeEvent::NAME:
{
#include <dali/internal/accessibility/bridge/bridge-base.h>
#include <dali/public-api/math/rect.h>
+/**
+ * @brief The BridgeObject class is to correspond with Dali::Accessibility::Bridge.
+ */
class BridgeObject : public virtual BridgeBase
{
protected:
+ /**
+ * @brief Constructor.
+ */
BridgeObject();
+ /**
+ * @brief Registers Bridge functions to dbus interfaces.
+ */
void RegisterInterfaces();
- DBus::DBusInterfaceDescription::SignalId stateChanged;
-
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitActiveDescendantChanged()
+ */
void EmitActiveDescendantChanged(Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible* child) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitCursorMoved()
+ */
void EmitCursorMoved(Dali::Accessibility::Accessible* obj, unsigned int cursorPosition) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitTextChanged()
+ */
void EmitTextChanged(Dali::Accessibility::Accessible* obj, Dali::Accessibility::TextChangedState state, unsigned int position, unsigned int length, const std::string& content) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitStateChanged()
+ */
void EmitStateChanged(Dali::Accessibility::Accessible* obj, Dali::Accessibility::State state, int newValue, int reserved) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Emit()
+ */
void Emit(Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent event, unsigned int detail) override;
- void Emit(Dali::Accessibility::Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent we) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Emit()
+ */
+ void Emit(Dali::Accessibility::Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent event) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitBoundsChanged()
+ */
void EmitBoundsChanged(Dali::Accessibility::Accessible* obj, Dali::Rect<> rect) override;
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::EmitMovedOutOfScreen()
+ */
void EmitMovedOutOfScreen(Dali::Accessibility::Accessible* obj, Dali::Accessibility::ScreenRelativeMoveType type) override;
+
+protected:
+ DBus::DBusInterfaceDescription::SignalId mStateChanged;
};
#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeSelection class is to correspond with Dali::Accessibility::Selection.
+ */
class BridgeSelection : public virtual BridgeBase
{
protected:
BridgeSelection() = default;
+ /**
+ * @brief Registers Selection functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Selection object of the currently executed DBus method call.
+ *
+ * @return The Selection object
+ */
Dali::Accessibility::Selection* FindSelf() const;
public:
+ /**
+ * @copydoc Dali::Accessibility::Selection::GetSelectedChildrenCount()
+ */
DBus::ValueOrError<int32_t> GetSelectedChildrenCount();
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::GetSelectedChild()
+ */
DBus::ValueOrError<Dali::Accessibility::Accessible*> GetSelectedChild(int32_t selectedChildIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::SelectChild()
+ */
DBus::ValueOrError<bool> SelectChild(int32_t childIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::DeselectSelectedChild()
+ */
DBus::ValueOrError<bool> DeselectSelectedChild(int32_t selectedChildIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::IsChildSelected()
+ */
DBus::ValueOrError<bool> IsChildSelected(int32_t childIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::SelectAll()
+ */
DBus::ValueOrError<bool> SelectAll();
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::ClearSelection()
+ */
DBus::ValueOrError<bool> ClearSelection();
+
+ /**
+ * @copydoc Dali::Accessibility::Selection::DeselectChild()
+ */
DBus::ValueOrError<bool> DeselectChild(int32_t childIndex);
};
return {range.content, static_cast<int>(range.startOffset), static_cast<int>(range.endOffset)};
}
-DBus::ValueOrError<int, int> BridgeText::GetRangeOfSelection(int32_t selectionNum)
+DBus::ValueOrError<int, int> BridgeText::GetRangeOfSelection(int32_t selectionIndex)
{
- auto range = FindSelf()->GetRangeOfSelection(selectionNum);
+ auto range = FindSelf()->GetRangeOfSelection(selectionIndex);
return {static_cast<int>(range.startOffset), static_cast<int>(range.endOffset)};
}
-DBus::ValueOrError<bool> BridgeText::RemoveSelection(int32_t selectionNum)
+DBus::ValueOrError<bool> BridgeText::RemoveSelection(int32_t selectionIndex)
{
- return FindSelf()->RemoveSelection(selectionNum);
+ return FindSelf()->RemoveSelection(selectionIndex);
}
-DBus::ValueOrError<bool> BridgeText::SetRangeOfSelection(int32_t selectionNum, int32_t startOffset, int32_t endOffset)
+DBus::ValueOrError<bool> BridgeText::SetRangeOfSelection(int32_t selectionIndex, int32_t startOffset, int32_t endOffset)
{
- return FindSelf()->SetRangeOfSelection(selectionNum, startOffset, endOffset);
+ return FindSelf()->SetRangeOfSelection(selectionIndex, startOffset, endOffset);
}
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeText class is to correspond with Dali::Accessibility::Text.
+ */
class BridgeText : public virtual BridgeBase
{
protected:
BridgeText() = default;
+ /**
+ * @brief Registers Text functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns the Text object of the currently executed DBus method call.
+ *
+ * @return The Text object
+ */
Dali::Accessibility::Text* FindSelf() const;
public:
- DBus::ValueOrError<std::string> GetText(int startOffset, int endOffset);
- DBus::ValueOrError<int32_t> GetCharacterCount();
- DBus::ValueOrError<int32_t> GetCursorOffset();
- DBus::ValueOrError<bool> SetCursorOffset(int32_t offset);
+ /**
+ * @copydoc Dali::Accessibility::Text::GetText()
+ */
+ DBus::ValueOrError<std::string> GetText(int startOffset, int endOffset);
+
+ /**
+ * @copydoc Dali::Accessibility::Text::GetCharacterCount()
+ */
+ DBus::ValueOrError<int32_t> GetCharacterCount();
+
+ /**
+ * @copydoc Dali::Accessibility::Text::GetCursorOffset()
+ */
+ DBus::ValueOrError<int32_t> GetCursorOffset();
+
+ /**
+ * @copydoc Dali::Accessibility::Text::SetCursorOffset()
+ */
+ DBus::ValueOrError<bool> SetCursorOffset(int32_t offset);
+
+ /**
+ * @copydoc Dali::Accessibility::Text::GetTextAtOffset()
+ */
DBus::ValueOrError<std::string, int, int> GetTextAtOffset(int32_t offset, uint32_t boundary);
- DBus::ValueOrError<int, int> GetRangeOfSelection(int32_t selectionNum);
- DBus::ValueOrError<bool> RemoveSelection(int32_t selectionNum);
- DBus::ValueOrError<bool> SetRangeOfSelection(int32_t selectionNum, int32_t startOffset, int32_t endOffset);
+
+ /**
+ * @copydoc Dali::Accessibility::Text::GetRangeOfSelection()
+ */
+ DBus::ValueOrError<int, int> GetRangeOfSelection(int32_t selectionIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Text::RemoveSelection()
+ */
+ DBus::ValueOrError<bool> RemoveSelection(int32_t selectionIndex);
+
+ /**
+ * @copydoc Dali::Accessibility::Text::SetRangeOfSelection()
+ */
+ DBus::ValueOrError<bool> SetRangeOfSelection(int32_t selectionIndex, int32_t startOffset, int32_t endOffset);
};
#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H
// INTERNAL INCLUDES
#include <dali/internal/accessibility/bridge/bridge-base.h>
+/**
+ * @brief The BridgeValue class is to correspond with Dali::Accessibility::Value.
+ */
class BridgeValue : public virtual BridgeBase
{
protected:
+ /**
+ * @brief Constructor.
+ */
BridgeValue();
+ /**
+ * @brief Registers Value functions to dbus interfaces.
+ */
void RegisterInterfaces();
+ /**
+ * @brief Returns Value Action object of the currently executed DBus method call.
+ *
+ * @return The Value object
+ */
Dali::Accessibility::Value* FindSelf() const;
public:
+ /**
+ * @copydoc Dali::Accessibility::Value::GetCurrent()
+ */
double GetCurrentValue();
- void SetCurrentValue(double newValue);
+
+ /**
+ * @copydoc Dali::Accessibility::Value::SetCurrent()
+ */
+ void SetCurrentValue(double newValue);
+
+ /**
+ * @copydoc Dali::Accessibility::Value::GetMaximum()
+ */
double GetMaximumValue();
+
+ /**
+ * @copydoc Dali::Accessibility::Value::GetMinimumIncrement()
+ */
double GetMinimumIncrement();
+
+ /**
+ * @copydoc Dali::Accessibility::Value::GetMinimum()
+ */
double GetMinimumValue();
};
SET( adaptor_text_common_src_files
${adaptor_text_dir}/text-abstraction/bidirectional-support-impl.cpp
${adaptor_text_dir}/text-abstraction/cairo-renderer.cpp
- ${adaptor_text_dir}/text-abstraction/font-client-helper.cpp
${adaptor_text_dir}/text-abstraction/font-client-impl.cpp
- ${adaptor_text_dir}/text-abstraction/font-client-plugin-impl.cpp
${adaptor_text_dir}/text-abstraction/segmentation-impl.cpp
${adaptor_text_dir}/text-abstraction/shaping-impl.cpp
${adaptor_text_dir}/text-abstraction/text-renderer-impl.cpp
${adaptor_text_dir}/text-abstraction/hyphenation-impl.cpp
+ ${adaptor_text_dir}/text-abstraction/plugin/bitmap-font-cache-item.cpp
+ ${adaptor_text_dir}/text-abstraction/plugin/embedded-item.cpp
+ ${adaptor_text_dir}/text-abstraction/plugin/font-client-utils.cpp
+ ${adaptor_text_dir}/text-abstraction/plugin/font-client-plugin-impl.cpp
+ ${adaptor_text_dir}/text-abstraction/plugin/font-face-cache-item.cpp
)
-
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/text/text-abstraction/font-client-helper.h>
-
-// INTERNAL INCLUDES
-
-#include <dali/integration-api/debug.h>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT_VALUE_TO_INDEX");
-#endif
-} // namespace
-
-namespace Dali
-{
-namespace TextAbstraction
-{
-namespace Internal
-{
-int ValueToIndex(int value, const int* const table, unsigned int maxIndex)
-{
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->FontClient::Plugin::ValueToIndex value(%d)\n", value);
-
- if(NULL == table)
- {
- // Return an invalid index if there is no table.
- return -1;
- }
-
- if(value <= table[0])
- {
- return 0;
- }
-
- if(value >= table[maxIndex])
- {
- return maxIndex;
- }
-
- for(unsigned int index = 0u; index < maxIndex; ++index)
- {
- const int v1 = table[index];
- const unsigned int indexPlus = index + 1u;
- const int v2 = table[indexPlus];
- if((v1 < value) && (value <= v2))
- {
- const int result = ((v1 > 0) && ((value - v1) < (v2 - value))) ? index : indexPlus;
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex result(%d)\n", result);
- return result;
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex exit 0 <-- \n");
-
- return 0;
-}
-
-} // namespace Internal
-
-} // namespace TextAbstraction
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H
-#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H
-
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-namespace Dali
-{
-namespace TextAbstraction
-{
-namespace Internal
-{
-/**
- * @brief Retrieves a table index for a given value.
- *
- * @param[in] value The value.
- * @param[in] table The table.
- * @param[in] maxIndex The maximum valid index of the table.
- *
- * @return The index to the closest available value
- */
-int ValueToIndex(int value, const int* const table, unsigned int maxIndex);
-
-} // namespace Internal
-
-} // namespace TextAbstraction
-
-} // namespace Dali
-
-#endif // DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H
// INTERNAL INCLUDES
#include <dali/devel-api/common/singleton-service.h>
-#include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
#include <dali/devel-api/text-abstraction/glyph-info.h>
+++ /dev/null
-/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
-
-// INTERNAL INCLUDES
-#include <dali/devel-api/text-abstraction/font-list.h>
-
-#include <dali/devel-api/adaptor-framework/image-loading.h>
-#include <dali/integration-api/debug.h>
-#include <dali/integration-api/platform-abstraction.h>
-#include <dali/internal/adaptor/common/adaptor-impl.h>
-#include <dali/internal/imaging/common/image-operations.h>
-#include <dali/internal/text/text-abstraction/font-client-helper.h>
-#include <dali/public-api/common/dali-vector.h>
-#include <dali/public-api/common/vector-wrapper.h>
-
-// EXTERNAL INCLUDES
-#include <fontconfig/fontconfig.h>
-#include <algorithm>
-#include <iterator>
-
-namespace
-{
-#if defined(DEBUG_ENABLED)
-Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
-#endif
-
-/**
- * Conversion from Fractional26.6 to float
- */
-const float FROM_266 = 1.0f / 64.0f;
-const float POINTS_PER_INCH = 72.f;
-
-const std::string DEFAULT_FONT_FAMILY_NAME("Tizen");
-const int DEFAULT_FONT_WIDTH = 100; // normal
-const int DEFAULT_FONT_WEIGHT = 80; // normal
-const int DEFAULT_FONT_SLANT = 0; // normal
-
-const uint32_t ELLIPSIS_CHARACTER = 0x2026;
-
-// http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
-
-// NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
-// ULTRA_CONDENSED 50
-// EXTRA_CONDENSED 63
-// CONDENSED 75
-// SEMI_CONDENSED 87
-// NORMAL 100
-// SEMI_EXPANDED 113
-// EXPANDED 125
-// EXTRA_EXPANDED 150
-// ULTRA_EXPANDED 200
-const int FONT_WIDTH_TYPE_TO_INT[] = {-1, 50, 63, 75, 87, 100, 113, 125, 150, 200};
-const unsigned int NUM_FONT_WIDTH_TYPE = sizeof(FONT_WIDTH_TYPE_TO_INT) / sizeof(int);
-
-// NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
-// THIN 0
-// ULTRA_LIGHT, EXTRA_LIGHT 40
-// LIGHT 50
-// DEMI_LIGHT, SEMI_LIGHT 55
-// BOOK 75
-// NORMAL, REGULAR 80
-// MEDIUM 100
-// DEMI_BOLD, SEMI_BOLD 180
-// BOLD 200
-// ULTRA_BOLD, EXTRA_BOLD 205
-// BLACK, HEAVY, EXTRA_BLACK 210
-const int FONT_WEIGHT_TYPE_TO_INT[] = {-1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210};
-const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof(FONT_WEIGHT_TYPE_TO_INT) / sizeof(int);
-
-// NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
-// NORMAL, ROMAN 0
-// ITALIC 100
-// OBLIQUE 110
-const int FONT_SLANT_TYPE_TO_INT[] = {-1, 0, 100, 110};
-const unsigned int NUM_FONT_SLANT_TYPE = sizeof(FONT_SLANT_TYPE_TO_INT) / sizeof(int);
-
-} // namespace
-
-using Dali::Vector;
-using namespace std;
-
-namespace Dali
-{
-namespace TextAbstraction
-{
-namespace Internal
-{
-/**
- * @brief Returns the FontWidth's enum index for the given width value.
- *
- * @param[in] width The width value.
- *
- * @return The FontWidth's enum index.
- */
-FontWidth::Type IntToWidthType(int width)
-{
- return static_cast<FontWidth::Type>(ValueToIndex(width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u));
-}
-
-/**
- * @brief Returns the FontWeight's enum index for the given weight value.
- *
- * @param[in] weight The weight value.
- *
- * @return The FontWeight's enum index.
- */
-FontWeight::Type IntToWeightType(int weight)
-{
- return static_cast<FontWeight::Type>(ValueToIndex(weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u));
-}
-
-/**
- * @brief Returns the FontSlant's enum index for the given slant value.
- *
- * @param[in] slant The slant value.
- *
- * @return The FontSlant's enum index.
- */
-FontSlant::Type IntToSlantType(int slant)
-{
- return static_cast<FontSlant::Type>(ValueToIndex(slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u));
-}
-
-/**
- * @brief Free the resources allocated by the FcCharSet objects.
- *
- * @param[in] characterSets The vector of character sets.
- */
-void DestroyCharacterSets(CharacterSetList& characterSets)
-{
- for(auto& item : characterSets)
- {
- if(item)
- {
- FcCharSetDestroy(item);
- }
- }
-}
-
-/**
- * @brief Check if @p ftFace and @p requestedPointSize produces block that fit into atlas block
- *
- * @param[in/out] ftFace Face type object.
- * @param[in] horizontalDpi The horizontal dpi.
- * @param[in] verticalDpi The vertical dpi.
- * @param[in] maxSizeFitInAtlas The maximum size of block to fit into atlas
- * @param[in] requestedPointSize The requested point-size.
- * @return whether the ftFace's block can fit into atlas
- */
-bool IsFitIntoAtlas(FT_Face& ftFace, int& error, const unsigned int& horizontalDpi, const unsigned int& verticalDpi, const Size& maxSizeFitInAtlas, const uint32_t& requestedPointSize)
-{
- bool isFit = false;
-
- error = FT_Set_Char_Size(ftFace,
- 0,
- requestedPointSize,
- horizontalDpi,
- verticalDpi);
-
- if(error == FT_Err_Ok)
- {
- //Check width and height of block for requestedPointSize
- //If the width or height is greater than the maximum-size then decrement by one unit of point-size.
- if(static_cast<float>(ftFace->size->metrics.height) * FROM_266 <= maxSizeFitInAtlas.height && (static_cast<float>(ftFace->size->metrics.ascender) - static_cast<float>(ftFace->size->metrics.descender)) * FROM_266 <= maxSizeFitInAtlas.width)
- {
- isFit = true;
- }
- }
-
- return isFit;
-}
-
-/**
- * @brief Search on proper @p requestedPointSize that produces block that fit into atlas block considering on @p ftFace, @p horizontalDpi, and @p verticalDpi
- *
- * @param[in/out] ftFace Face type object.
- * @param[in] horizontalDpi The horizontal dpi.
- * @param[in] verticalDpi The vertical dpi.
- * @param[in] maxSizeFitInAtlas The maximum size of block to fit into atlas
- * @param[in/out] requestedPointSize The requested point-size.
- * @return FreeType error code. 0 means success when requesting the nominal size (in points).
- */
-int SearchOnProperPointSize(FT_Face& ftFace, const unsigned int& horizontalDpi, const unsigned int& verticalDpi, const Size& maxSizeFitInAtlas, uint32_t& requestedPointSize)
-{
- //To improve performance of sequential search. This code is applying Exponential search then followed by Binary search.
- const uint32_t& pointSizePerOneUnit = TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
- bool canFitInAtlas;
- int error; // FreeType error code.
-
- canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
- if(FT_Err_Ok != error)
- {
- return error;
- }
-
- if(!canFitInAtlas)
- {
- //Exponential search
- uint32_t exponentialDecrement = 1;
-
- while(!canFitInAtlas && requestedPointSize > pointSizePerOneUnit * exponentialDecrement)
- {
- requestedPointSize -= (pointSizePerOneUnit * exponentialDecrement);
- canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
- if(FT_Err_Ok != error)
- {
- return error;
- }
-
- exponentialDecrement *= 2;
- }
-
- //Binary search
- uint32_t minPointSize;
- uint32_t maxPointSize;
-
- if(canFitInAtlas)
- {
- exponentialDecrement /= 2;
- minPointSize = requestedPointSize;
- maxPointSize = requestedPointSize + (pointSizePerOneUnit * exponentialDecrement);
- }
- else
- {
- minPointSize = 0;
- maxPointSize = requestedPointSize;
- }
-
- while(minPointSize < maxPointSize)
- {
- requestedPointSize = ((maxPointSize / pointSizePerOneUnit - minPointSize / pointSizePerOneUnit) / 2) * pointSizePerOneUnit + minPointSize;
- canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
- if(FT_Err_Ok != error)
- {
- return error;
- }
-
- if(canFitInAtlas)
- {
- if(minPointSize == requestedPointSize)
- {
- //Found targeted point-size
- return error;
- }
-
- minPointSize = requestedPointSize;
- }
- else
- {
- maxPointSize = requestedPointSize;
- }
- }
- }
-
- return error;
-}
-
-FontClient::Plugin::FallbackCacheItem::FallbackCacheItem(FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets)
-: fontDescription{std::move(font)},
- fallbackFonts{fallbackFonts},
- characterSets{characterSets}
-{
-}
-
-FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(const FontDescription& fontDescription,
- FontDescriptionId index)
-: fontDescription{fontDescription},
- index{index}
-{
-}
-
-FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescription&& fontDescription,
- FontDescriptionId index)
-: fontDescription{std::move(fontDescription)},
- index{index}
-{
-}
-
-FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem(FontDescriptionId validatedFontId,
- PointSize26Dot6 requestedPointSize,
- FontId fontId)
-: validatedFontId(validatedFontId),
- requestedPointSize(requestedPointSize),
- fontId(fontId)
-{
-}
-
-FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem(FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex face,
- const FontMetrics& metrics)
-: mFreeTypeFace(ftFace),
- mPath(path),
- mRequestedPointSize(requestedPointSize),
- mFaceIndex(face),
- mMetrics(metrics),
- mCharacterSet(nullptr),
- mFixedSizeIndex(0),
- mFixedWidthPixels(0.f),
- mFixedHeightPixels(0.f),
- mVectorFontId(0u),
- mFontId(0u),
- mIsFixedSizeBitmap(false),
- mHasColorTables(false)
-{
-}
-
-FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem(FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex face,
- const FontMetrics& metrics,
- int fixedSizeIndex,
- float fixedWidth,
- float fixedHeight,
- bool hasColorTables)
-: mFreeTypeFace(ftFace),
- mPath(path),
- mRequestedPointSize(requestedPointSize),
- mFaceIndex(face),
- mMetrics(metrics),
- mCharacterSet(nullptr),
- mFixedSizeIndex(fixedSizeIndex),
- mFixedWidthPixels(fixedWidth),
- mFixedHeightPixels(fixedHeight),
- mVectorFontId(0u),
- mFontId(0u),
- mIsFixedSizeBitmap(true),
- mHasColorTables(hasColorTables)
-{
-}
-
-FontClient::Plugin::Plugin(unsigned int horizontalDpi,
- unsigned int verticalDpi)
-: mFreeTypeLibrary(nullptr),
- mDpiHorizontal(horizontalDpi),
- mDpiVertical(verticalDpi),
- mDefaultFontDescription(),
- mSystemFonts(),
- mDefaultFonts(),
- mFontIdCache(),
- mFontFaceCache(),
- mValidatedFontCache(),
- mFontDescriptionCache(),
- mCharacterSetCache(),
- mFontDescriptionSizeCache(),
- mVectorFontCache(nullptr),
- mEllipsisCache(),
- mEmbeddedItemCache(),
- mDefaultFontDescriptionCached(false),
- mIsAtlasLimitationEnabled(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED),
- mCurrentMaximumBlockSizeFitInAtlas(TextAbstraction::FontClient::MAX_SIZE_FIT_IN_ATLAS)
-
-{
- int error = FT_Init_FreeType(&mFreeTypeLibrary);
- if(FT_Err_Ok != error)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FreeType Init error: %d\n", error);
- }
-
-#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
- mVectorFontCache = new VectorFontCache(mFreeTypeLibrary);
-#endif
-}
-
-FontClient::Plugin::~Plugin()
-{
- ClearFallbackCache(mFallbackCache);
-
- // Free the resources allocated by the FcCharSet objects.
- DestroyCharacterSets(mDefaultFontCharacterSets);
- DestroyCharacterSets(mCharacterSetCache);
- ClearCharacterSetFromFontFaceCache();
-
-#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
- delete mVectorFontCache;
-#endif
- FT_Done_FreeType(mFreeTypeLibrary);
-}
-
-void FontClient::Plugin::ClearCache()
-{
- mDefaultFontDescription = FontDescription();
-
- mSystemFonts.clear();
- mDefaultFonts.clear();
-
- DestroyCharacterSets(mDefaultFontCharacterSets);
- mDefaultFontCharacterSets.Clear();
-
- ClearFallbackCache(mFallbackCache);
- mFallbackCache.clear();
-
- mFontIdCache.Clear();
-
- ClearCharacterSetFromFontFaceCache();
- mFontFaceCache.clear();
-
- mValidatedFontCache.clear();
- mFontDescriptionCache.clear();
-
- DestroyCharacterSets(mCharacterSetCache);
- mCharacterSetCache.Clear();
-
- mFontDescriptionSizeCache.clear();
-
- mEllipsisCache.Clear();
- mPixelBufferCache.clear();
- mEmbeddedItemCache.Clear();
- mBitmapFontCache.clear();
-
- mDefaultFontDescriptionCached = false;
-}
-
-void FontClient::Plugin::SetDpi(unsigned int horizontalDpi,
- unsigned int verticalDpi)
-{
- mDpiHorizontal = horizontalDpi;
- mDpiVertical = verticalDpi;
-}
-
-void FontClient::Plugin::ResetSystemDefaults()
-{
- mDefaultFontDescriptionCached = false;
-}
-
-void FontClient::Plugin::SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
-
- fontList.clear();
-
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcResult result = FcResultMatch;
-
- // Match the pattern.
- FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
- fontFamilyPattern,
- false /* don't trim */,
- nullptr,
- &result); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
-
- if(nullptr != fontSet)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont);
- // Reserve some space to avoid reallocations.
- fontList.reserve(fontSet->nfont);
-
- for(int i = 0u; i < fontSet->nfont; ++i)
- {
- FcPattern* fontPattern = fontSet->fonts[i];
-
- FontPath path;
-
- // Skip fonts with no path
- if(GetFcString(fontPattern, FC_FILE, path))
- {
- // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
- FcCharSet* characterSet = nullptr;
- FcPatternGetCharSet(fontPattern, FC_CHARSET, 0u, &characterSet);
-
- // Increase the reference counter of the character set.
- characterSetList.PushBack(FcCharSetCopy(characterSet));
-
- fontList.push_back(FontDescription());
- FontDescription& newFontDescription = fontList.back();
-
- newFontDescription.path = std::move(path);
-
- int width = 0;
- int weight = 0;
- int slant = 0;
- GetFcString(fontPattern, FC_FAMILY, newFontDescription.family);
- GetFcInt(fontPattern, FC_WIDTH, width);
- GetFcInt(fontPattern, FC_WEIGHT, weight);
- GetFcInt(fontPattern, FC_SLANT, slant);
- newFontDescription.width = IntToWidthType(width);
- newFontDescription.weight = IntToWeightType(weight);
- newFontDescription.slant = IntToSlantType(slant);
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " description; family : [%s]\n", newFontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", newFontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[newFontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[newFontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant]);
- }
- }
-
- // Destroys the font set created by FcFontSort.
- FcFontSetDestroy(fontSet);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " No fonts found.\n");
- }
-
- // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
- FcPatternDestroy(fontFamilyPattern);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n");
-}
-
-void FontClient::Plugin::GetDefaultFonts(FontList& defaultFonts)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n");
-
- if(mDefaultFonts.empty())
- {
- FontDescription fontDescription;
- fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
- fontDescription.width = IntToWidthType(DEFAULT_FONT_WIDTH);
- fontDescription.weight = IntToWeightType(DEFAULT_FONT_WEIGHT);
- fontDescription.slant = IntToSlantType(DEFAULT_FONT_SLANT);
- SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
- }
-
- defaultFonts = mDefaultFonts;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size());
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n");
-}
-
-void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
-
- if(!mDefaultFontDescriptionCached)
- {
- // Clear any font config stored info in the caches.
-
- // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
- DestroyCharacterSets(mDefaultFontCharacterSets);
- DestroyCharacterSets(mCharacterSetCache);
- mDefaultFontCharacterSets.Clear();
- mCharacterSetCache.Clear();
-
- for(auto& item : mFallbackCache)
- {
- // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
- DestroyCharacterSets(*item.characterSets);
-
- delete item.characterSets;
- item.characterSets = nullptr;
- }
-
- // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
- ClearCharacterSetFromFontFaceCache();
-
- // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
- FcInitReinitialize();
-
- FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
-
- if(nullptr != matchPattern)
- {
- FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
- FcDefaultSubstitute(matchPattern);
-
- FcCharSet* characterSet = nullptr;
- MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
- // Decrease the reference counter of the character set as it's not stored.
- FcCharSetDestroy(characterSet);
-
- // Destroys the pattern created.
- FcPatternDestroy(matchPattern);
- }
-
- // Create again the character sets as they are not valid after FcInitReinitialize()
-
- for(const auto& description : mDefaultFonts)
- {
- mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
- }
-
- for(const auto& description : mFontDescriptionCache)
- {
- mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
- }
-
- for(auto& item : mFallbackCache)
- {
- if(nullptr != item.fallbackFonts)
- {
- if(nullptr == item.characterSets)
- {
- item.characterSets = new CharacterSetList;
- }
-
- for(const auto& description : *(item.fallbackFonts))
- {
- item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
- }
- }
- }
-
- mDefaultFontDescriptionCached = true;
- }
-
- fontDescription.path = mDefaultFontDescription.path;
- fontDescription.family = mDefaultFontDescription.family;
- fontDescription.width = mDefaultFontDescription.width;
- fontDescription.weight = mDefaultFontDescription.weight;
- fontDescription.slant = mDefaultFontDescription.slant;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
-}
-
-void FontClient::Plugin::GetSystemFonts(FontList& systemFonts)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
-
- if(mSystemFonts.empty())
- {
- InitSystemFonts();
- }
-
- systemFonts = mSystemFonts;
- DALI_LOG_INFO(gLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size());
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
-}
-
-void FontClient::Plugin::GetDescription(FontId id,
- FontDescription& fontDescription) const
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", id);
- const FontId index = id - 1u;
-
- if((id > 0u) && (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- for(const auto& item : mFontDescriptionSizeCache)
- {
- if(item.fontId == fontIdCacheItem.id)
- {
- fontDescription = *(mFontDescriptionCache.begin() + item.validatedFontId - 1u);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
- return;
- }
- }
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- fontDescription.type = FontDescription::BITMAP_FONT;
- fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- fontDescription.type = FontDescription::INVALID;
- fontDescription.family.clear();
- }
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " No description found for the font ID %d\n", id);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
-}
-
-PointSize26Dot6 FontClient::Plugin::GetPointSize(FontId id)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", id);
- const FontId index = id - 1u;
-
- if((id > 0u) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " point size : %d\n", (*(mFontFaceCache.begin() + fontIdCacheItem.id)).mRequestedPointSize);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
- return (*(mFontFaceCache.begin() + fontIdCacheItem.id)).mRequestedPointSize;
- }
- case FontDescription::BITMAP_FONT:
- {
- return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid font ID %d\n", id);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
- return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
-}
-
-bool FontClient::Plugin::IsCharacterSupportedByFont(FontId fontId, Character character)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, " character : %p\n", character);
-
- if((fontId < 1u) || (fontId > mFontIdCache.Count()))
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n", mFontIdCache.Count());
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
- return false;
- }
-
- --fontId;
-
- bool isSupported = false;
-
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- if(fontIdCacheItem.id < mFontFaceCache.size())
- {
- FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
-
- if(nullptr == cacheItem.mCharacterSet)
- {
- // Create again the character set.
- // It can be null if the ResetSystemDefaults() method has been called.
-
- FontDescription description;
- description.path = cacheItem.mPath;
- description.family = std::move(FontFamily(cacheItem.mFreeTypeFace->family_name));
- description.weight = FontWeight::NONE;
- description.width = FontWidth::NONE;
- description.slant = FontSlant::NONE;
-
- // Note FreeType doesn't give too much info to build a proper font style.
- if(cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC)
- {
- description.slant = FontSlant::ITALIC;
- }
- if(cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD)
- {
- description.weight = FontWeight::BOLD;
- }
-
- cacheItem.mCharacterSet = FcCharSetCopy(CreateCharacterSetFromDescription(description));
- }
-
- isSupported = FcCharSetHasChar(cacheItem.mCharacterSet, character);
- }
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
-
- for(const auto& glyph : bitmapFont.glyphs)
- {
- if(glyph.utf32 == character)
- {
- isSupported = true;
- break;
- }
- }
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false"));
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
- return isSupported;
-}
-
-FontId FontClient::Plugin::FindFontForCharacter(const FontList& fontList,
- const CharacterSetList& characterSetList,
- Character character,
- PointSize26Dot6 requestedPointSize,
- bool preferColor)
-{
- DALI_ASSERT_DEBUG((fontList.size() == characterSetList.Count()) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets.");
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " character : %p\n", character);
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
- DALI_LOG_INFO(gLogFilter, Debug::General, " preferColor : %s\n", (preferColor ? "true" : "false"));
-
- FontId fontId = 0u;
- bool foundColor = false;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " number of fonts : %d\n", fontList.size());
-
- // Traverse the list of fonts.
- // Check for each font if supports the character.
- for(unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index)
- {
- const FontDescription& description = fontList[index];
- const FcCharSet* const characterSet = characterSetList[index];
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " description; family : [%s]\n", description.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant]);
-
- bool foundInRanges = false;
- if(nullptr != characterSet)
- {
- foundInRanges = FcCharSetHasChar(characterSet, character);
- }
-
- if(foundInRanges)
- {
- fontId = GetFontId(description,
- requestedPointSize,
- 0u);
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " font id : %d\n", fontId);
-
- if(preferColor)
- {
- if((fontId > 0) &&
- (fontId - 1u < mFontIdCache.Count()))
- {
- const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
-
- foundColor = item.mHasColorTables;
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " foundColor : %s\n", (foundColor ? "true" : "false"));
- }
-
- // Keep going unless we prefer a different (color) font.
- if(!preferColor || foundColor)
- {
- break;
- }
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n");
- return fontId;
-}
-
-FontId FontClient::Plugin::FindDefaultFont(Character charcode,
- PointSize26Dot6 requestedPointSize,
- bool preferColor)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " character : %p\n", charcode);
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
- DALI_LOG_INFO(gLogFilter, Debug::General, " preferColor : %s\n", (preferColor ? "true" : "false"));
-
- FontId fontId(0);
-
- // Create the list of default fonts if it has not been created.
- if(mDefaultFonts.empty())
- {
- FontDescription fontDescription;
- fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
- fontDescription.width = IntToWidthType(DEFAULT_FONT_WIDTH);
- fontDescription.weight = IntToWeightType(DEFAULT_FONT_WEIGHT);
- fontDescription.slant = IntToSlantType(DEFAULT_FONT_SLANT);
-
- SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
- }
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size());
-
- // Traverse the list of default fonts.
- // Check for each default font if supports the character.
- fontId = FindFontForCharacter(mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n");
-
- return fontId;
-}
-
-FontId FontClient::Plugin::FindFallbackFont(Character charcode,
- const FontDescription& preferredFontDescription,
- PointSize26Dot6 requestedPointSize,
- bool preferColor)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " character : %p\n", charcode);
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
- DALI_LOG_INFO(gLogFilter, Debug::General, " preferColor : %s\n", (preferColor ? "true" : "false"));
-
- // The font id to be returned.
- FontId fontId = 0u;
-
- FontDescription fontDescription;
-
- // Fill the font description with the preferred font description and complete with the defaults.
- fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
- fontDescription.weight = ((FontWeight::NONE == preferredFontDescription.weight) ? IntToWeightType(DEFAULT_FONT_WEIGHT) : preferredFontDescription.weight);
- fontDescription.width = ((FontWidth::NONE == preferredFontDescription.width) ? IntToWidthType(DEFAULT_FONT_WIDTH) : preferredFontDescription.width);
- fontDescription.slant = ((FontSlant::NONE == preferredFontDescription.slant) ? IntToSlantType(DEFAULT_FONT_SLANT) : preferredFontDescription.slant);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant]);
-
- // Check first if the font's description has been queried before.
- FontList* fontList = nullptr;
- CharacterSetList* characterSetList = nullptr;
-
- if(!FindFallbackFontList(fontDescription, fontList, characterSetList))
- {
- fontList = new FontList;
- characterSetList = new CharacterSetList;
-
- SetFontList(fontDescription, *fontList, *characterSetList);
-#ifdef __APPLE__
- FontDescription appleColorEmoji;
- appleColorEmoji.family = "Apple Color Emoji";
- appleColorEmoji.width = fontDescription.width;
- appleColorEmoji.weight = fontDescription.weight;
- appleColorEmoji.slant = fontDescription.slant;
- FontList emojiFontList;
- CharacterSetList emojiCharSetList;
- SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
-
- std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
- emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
- *fontList = std::move(emojiFontList);
- *characterSetList = std::move(emojiCharSetList);
-#endif
-
- // Add the font-list to the cache.
- mFallbackCache.push_back(std::move(FallbackCacheItem(std::move(fontDescription), fontList, characterSetList)));
- }
-
- if(fontList && characterSetList)
- {
- fontId = FindFontForCharacter(*fontList, *characterSetList, charcode, requestedPointSize, preferColor);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
- return fontId;
-}
-
-FontId FontClient::Plugin::GetFontId(const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex faceIndex,
- bool cacheDescription)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " path : [%s]\n", path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
-
- FontId id = 0u;
-
- if(nullptr != mFreeTypeLibrary)
- {
- FontId foundId = 0u;
- if(FindFont(path, requestedPointSize, faceIndex, foundId))
- {
- id = foundId;
- }
- else
- {
- id = CreateFont(path, requestedPointSize, faceIndex, cacheDescription);
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", id);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n");
-
- return id;
-}
-
-FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
- PointSize26Dot6 requestedPointSize,
- FaceIndex faceIndex)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
-
- // This method uses three vectors which caches:
- // * The bitmap font cache
- // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
- // * The path to font file names.
- // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
-
- // 1) Checks if the font description matches with a previously loaded bitmap font.
- // Returns if a font is found.
- // 2) Checks in the cache if the font's description has been validated before.
- // If it was it gets an index to the vector with paths to font file names. Otherwise,
- // retrieves using font config a path to a font file name which matches with the
- // font's description. The path is stored in the cache.
- //
- // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
- // font file names' exists. If exists, it gets the font id. If it doesn't it calls
- // the GetFontId() method with the path to the font file name and the point size to
- // get the font id.
-
- // The font id to be returned.
- FontId fontId = 0u;
-
- // Check first if the font description matches with a previously loaded bitmap font.
- if(FindBitmapFont(fontDescription.family, fontId))
- {
- return fontId;
- }
-
- // Check if the font's description have been validated before.
- FontDescriptionId validatedFontId = 0u;
-
- if(!FindValidatedFont(fontDescription,
- validatedFontId))
- {
- // Use font config to validate the font's description.
- ValidateFont(fontDescription,
- validatedFontId);
- }
-
- FontId fontFaceId = 0u;
- // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
- if(!FindFont(validatedFontId, requestedPointSize, fontFaceId))
- {
- // Retrieve the font file name path.
- const FontDescription& description = *(mFontDescriptionCache.begin() + validatedFontId - 1u);
-
- // Retrieve the font id. Do not cache the description as it has been already cached.
- fontId = GetFontId(description.path,
- requestedPointSize,
- faceIndex,
- false);
-
- fontFaceId = mFontIdCache[fontId - 1u].id;
- mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(mCharacterSetCache[validatedFontId - 1u]);
-
- // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
- mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
- requestedPointSize,
- fontFaceId));
- }
- else
- {
- fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n");
-
- return fontId;
-}
-
-FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
-{
- for(const auto& item : mBitmapFontCache)
- {
- if(bitmapFont.name == item.font.name)
- {
- return item.id + 1u;
- }
- }
-
- BitmapFontCacheItem bitmapFontCacheItem;
- bitmapFontCacheItem.font = bitmapFont;
- bitmapFontCacheItem.id = mFontIdCache.Count();
-
- // Resize the vector with the pixel buffers.
- bitmapFontCacheItem.pixelBuffers.resize(bitmapFont.glyphs.size());
-
- // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
- unsigned int index = 0u;
- for(auto& glyph : bitmapFontCacheItem.font.glyphs)
- {
- Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
-
- if(EqualsZero(glyph.ascender) && EqualsZero(glyph.descender))
- {
- // Load the glyph.
- pixelBuffer = LoadImageFromFile(glyph.url);
-
- if(pixelBuffer)
- {
- glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
- }
- }
-
- bitmapFontCacheItem.font.ascender = std::max(glyph.ascender, bitmapFontCacheItem.font.ascender);
- bitmapFontCacheItem.font.descender = std::min(glyph.descender, bitmapFontCacheItem.font.descender);
-
- ++index;
- }
-
- FontIdCacheItem fontIdCacheItem;
- fontIdCacheItem.type = FontDescription::BITMAP_FONT;
- fontIdCacheItem.id = mBitmapFontCache.size();
-
- mBitmapFontCache.push_back(std::move(bitmapFontCacheItem));
- mFontIdCache.PushBack(fontIdCacheItem);
-
- return bitmapFontCacheItem.id + 1u;
-}
-
-void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
- FontDescriptionId& validatedFontId)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
-
- // Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
-
- FontDescription description;
-
- FcCharSet* characterSet = nullptr;
- bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
- FcPatternDestroy(fontFamilyPattern);
-
- if(matched && (nullptr != characterSet))
- {
- // Add the path to the cache.
- description.type = FontDescription::FACE_FONT;
- mFontDescriptionCache.push_back(description);
-
- // Set the index to the vector of paths to font file names.
- validatedFontId = mFontDescriptionCache.size();
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " matched description; family : [%s]\n", description.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", description.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[description.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[description.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[description.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId);
-
- // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
- mCharacterSetCache.PushBack(characterSet);
-
- // Cache the index and the matched font's description.
- FontDescriptionCacheItem item(description,
- validatedFontId);
-
- mValidatedFontCache.push_back(std::move(item));
-
- if((fontDescription.family != description.family) ||
- (fontDescription.width != description.width) ||
- (fontDescription.weight != description.weight) ||
- (fontDescription.slant != description.slant))
- {
- // Cache the given font's description if it's different than the matched.
- FontDescriptionCacheItem item(fontDescription,
- validatedFontId);
-
- mValidatedFontCache.push_back(std::move(item));
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str());
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n");
-}
-
-void FontClient::Plugin::GetFontMetrics(FontId fontId,
- FontMetrics& metrics)
-{
- const FontId index = fontId - 1u;
-
- if((fontId > 0) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
-
- metrics = font.mMetrics;
-
- // Adjust the metrics if the fixed-size font should be down-scaled
- if(font.mIsFixedSizeBitmap)
- {
- const float desiredFixedSize = static_cast<float>(font.mRequestedPointSize) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
-
- if(desiredFixedSize > 0.f)
- {
- const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
-
- metrics.ascender = metrics.ascender * scaleFactor;
- metrics.descender = metrics.descender * scaleFactor;
- metrics.height = metrics.height * scaleFactor;
- metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
- metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
- }
- }
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
-
- metrics.ascender = bitmapFontCacheItem.font.ascender;
- metrics.descender = bitmapFontCacheItem.font.descender;
- metrics.height = metrics.ascender - metrics.descender;
- metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
- metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId);
- }
-}
-
-GlyphIndex FontClient::Plugin::GetGlyphIndex(FontId fontId,
- Character charcode)
-{
- GlyphIndex glyphIndex = 0u;
- const FontId index = fontId - 1u;
-
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- if(FontDescription::FACE_FONT == fontIdCacheItem.type)
- {
- FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
-
- glyphIndex = FT_Get_Char_Index(ftFace, charcode);
- }
- }
-
- return glyphIndex;
-}
-
-bool FontClient::Plugin::GetGlyphMetrics(GlyphInfo* array,
- uint32_t size,
- GlyphType type,
- bool horizontal)
-{
- if(VECTOR_GLYPH == type)
- {
- return GetVectorMetrics(array, size, horizontal);
- }
-
- return GetBitmapMetrics(array, size, horizontal);
-}
-
-bool FontClient::Plugin::GetBitmapMetrics(GlyphInfo* array,
- uint32_t size,
- bool horizontal)
-{
- bool success(true);
-
- for(unsigned int i = 0; i < size; ++i)
- {
- GlyphInfo& glyph = array[i];
-
- FontId index = glyph.fontId - 1u;
-
- if((glyph.fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
-
- FT_Face ftFace = font.mFreeTypeFace;
-
-#ifdef FREETYPE_BITMAP_SUPPORT
- // Check to see if we should be loading a Fixed Size bitmap?
- if(font.mIsFixedSizeBitmap)
- {
- FT_Select_Size(ftFace, font.mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
- int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_COLOR);
- if(FT_Err_Ok == error)
- {
- glyph.width = font.mFixedWidthPixels;
- glyph.height = font.mFixedHeightPixels;
- glyph.advance = font.mFixedWidthPixels;
- glyph.xBearing = 0.0f;
- glyph.yBearing = font.mFixedHeightPixels;
-
- // Adjust the metrics if the fixed-size font should be down-scaled
- const float desiredFixedSize = static_cast<float>(font.mRequestedPointSize) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
-
- if(desiredFixedSize > 0.f)
- {
- const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
-
- glyph.width = glyph.width * scaleFactor;
- glyph.height = glyph.height * scaleFactor;
- glyph.advance = glyph.advance * scaleFactor;
- glyph.xBearing = glyph.xBearing * scaleFactor;
- glyph.yBearing = glyph.yBearing * scaleFactor;
-
- glyph.scaleFactor = scaleFactor;
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error);
- success = false;
- }
- }
- else
-#endif
- {
- // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
- // i.e. with the SNum-3R font.
- // @todo: add an option to use the FT_LOAD_DEFAULT if required?
- int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_NO_AUTOHINT);
-
- // Keep the width of the glyph before doing the software emboldening.
- // It will be used to calculate a scale factor to be applied to the
- // advance as Harfbuzz doesn't apply any SW emboldening to calculate
- // the advance of the glyph.
- const float width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
-
- if(FT_Err_Ok == error)
- {
- const bool isEmboldeningRequired = glyph.isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD);
- if(isEmboldeningRequired)
- {
- // Does the software bold.
- FT_GlyphSlot_Embolden(ftFace->glyph);
- }
-
- glyph.width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
- glyph.height = static_cast<float>(ftFace->glyph->metrics.height) * FROM_266;
- if(horizontal)
- {
- glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingX) * FROM_266;
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
- }
- else
- {
- glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingX) * FROM_266;
- glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
- }
-
- if(isEmboldeningRequired && !Dali::EqualsZero(width))
- {
- // If the glyph is emboldened by software, the advance is multiplied by a
- // scale factor to make it slightly bigger.
- glyph.advance *= (glyph.width / width);
- }
-
- // Use the bounding box of the bitmap to correct the metrics.
- // For some fonts i.e the SNum-3R the metrics need to be corrected,
- // otherwise the glyphs 'dance' up and down depending on the
- // font's point size.
-
- FT_Glyph ftGlyph;
- error = FT_Get_Glyph(ftFace->glyph, &ftGlyph);
-
- FT_BBox bbox;
- FT_Glyph_Get_CBox(ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
-
- const float descender = glyph.height - glyph.yBearing;
- glyph.height = (bbox.yMax - bbox.yMin) * FROM_266;
- glyph.yBearing = glyph.height - round(descender);
-
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(ftGlyph);
- }
- else
- {
- success = false;
- }
- }
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
-
- unsigned int index = 0u;
- for(auto& item : bitmapFontCacheItem.font.glyphs)
- {
- if(item.utf32 == glyph.index)
- {
- Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
- if(!pixelBuffer)
- {
- pixelBuffer = LoadImageFromFile(item.url);
- }
-
- glyph.width = static_cast<float>(pixelBuffer.GetWidth());
- glyph.height = static_cast<float>(pixelBuffer.GetHeight());
- glyph.xBearing = 0.f;
- glyph.yBearing = glyph.height + item.descender;
- glyph.advance = glyph.width;
- glyph.scaleFactor = 1.f;
- break;
- }
- ++index;
- }
-
- success = true;
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
- {
- // Check if it's an embedded image.
- if((0u == glyph.fontId) && (0u != glyph.index) && (glyph.index <= mEmbeddedItemCache.Count()))
- {
- const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
-
- glyph.width = static_cast<float>(item.width);
- glyph.height = static_cast<float>(item.height);
- glyph.xBearing = 0.f;
- glyph.yBearing = glyph.height;
- glyph.advance = glyph.width;
- glyph.scaleFactor = 1.f;
- }
- else
- {
- success = false;
- }
- }
- }
-
- return success;
-}
-
-bool FontClient::Plugin::GetVectorMetrics(GlyphInfo* array,
- uint32_t size,
- bool horizontal)
-{
-#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
- bool success(true);
-
- for(unsigned int i = 0u; i < size; ++i)
- {
- FontId fontId = array[i].fontId;
-
- if((fontId > 0u) &&
- (fontId - 1u) < mFontIdCache.Count())
- {
- FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
-
- if(!font.mVectorFontId)
- {
- font.mVectorFontId = mVectorFontCache->GetFontId(font.mPath);
- }
-
- mVectorFontCache->GetGlyphMetrics(font.mVectorFontId, array[i]);
-
- // Vector metrics are in EMs, convert to pixels
- const float scale = (static_cast<float>(font.mRequestedPointSize) * FROM_266) * static_cast<float>(mDpiVertical) / POINTS_PER_INCH;
- array[i].width *= scale;
- array[i].height *= scale;
- array[i].xBearing *= scale;
- array[i].yBearing *= scale;
- array[i].advance *= scale;
- }
- else
- {
- success = false;
- }
- }
-
- return success;
-#else
- return false;
-#endif
-}
-
-void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth)
-{
- const FontId index = fontId - 1u;
-
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- data.isColorBitmap = false;
- data.isColorEmoji = false;
-
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- // For the software italics.
- bool isShearRequired = false;
-
- const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
- FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
-
- FT_Error error;
-
-#ifdef FREETYPE_BITMAP_SUPPORT
- // Check to see if this is fixed size bitmap
- if(fontFaceCacheItem.mIsFixedSizeBitmap)
- {
- error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_COLOR);
- }
- else
-#endif
- {
- // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
- // i.e. with the SNum-3R font.
- // @todo: add an option to use the FT_LOAD_DEFAULT if required?
- error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT);
- }
- if(FT_Err_Ok == error)
- {
- if(isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD))
- {
- // Does the software bold.
- FT_GlyphSlot_Embolden(ftFace->glyph);
- }
-
- if(isItalicRequired && !(ftFace->style_flags & FT_STYLE_FLAG_ITALIC))
- {
- // Will do the software italic.
- isShearRequired = true;
- }
-
- FT_Glyph glyph;
- error = FT_Get_Glyph(ftFace->glyph, &glyph);
-
- // Convert to bitmap if necessary
- if(FT_Err_Ok == error)
- {
- if(glyph->format != FT_GLYPH_FORMAT_BITMAP)
- {
- int offsetX = 0, offsetY = 0;
- bool isOutlineGlyph = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
-
- // Create a bitmap for the outline
- if(isOutlineGlyph)
- {
- // Retrieve the horizontal and vertical distance from the current pen position to the
- // left and top border of the glyph bitmap for a normal glyph before applying the outline.
- if(FT_Err_Ok == error)
- {
- FT_Glyph normalGlyph;
- error = FT_Get_Glyph(ftFace->glyph, &normalGlyph);
-
- error = FT_Glyph_To_Bitmap(&normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
- if(FT_Err_Ok == error)
- {
- FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(normalGlyph);
-
- offsetX = bitmapGlyph->left;
- offsetY = bitmapGlyph->top;
- }
-
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(normalGlyph);
- }
-
- // Now apply the outline
-
- // Set up a stroker
- FT_Stroker stroker;
- error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
-
- if(FT_Err_Ok == error)
- {
- FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
- error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
-
- if(FT_Err_Ok == error)
- {
- FT_Stroker_Done(stroker);
- }
- else
- {
- DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
- }
- }
- else
- {
- DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
- }
- }
-
- error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
- if(FT_Err_Ok == error)
- {
- FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
-
- if(isOutlineGlyph)
- {
- // Calculate the additional horizontal and vertical offsets needed for the position of the outline glyph
- data.outlineOffsetX = offsetX - bitmapGlyph->left - outlineWidth;
- data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
- }
-
- ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error);
- }
- }
- else
- {
- ConvertBitmap(data, ftFace->glyph->bitmap, isShearRequired);
- }
-
- data.isColorEmoji = fontFaceCacheItem.mIsFixedSizeBitmap;
-
- // Created FT_Glyph object must be released with FT_Done_Glyph
- FT_Done_Glyph(glyph);
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error);
- }
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
-
- unsigned int index = 0u;
- for(auto& item : bitmapFontCacheItem.font.glyphs)
- {
- if(item.utf32 == glyphIndex)
- {
- Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
- if(!pixelBuffer)
- {
- pixelBuffer = LoadImageFromFile(item.url);
- }
-
- data.width = pixelBuffer.GetWidth();
- data.height = pixelBuffer.GetHeight();
-
- data.isColorBitmap = bitmapFontCacheItem.font.isColorFont;
-
- ConvertBitmap(data, data.width, data.height, pixelBuffer.GetBuffer());
-
- // Sets the pixel format.
- data.format = pixelBuffer.GetPixelFormat();
- break;
- }
- ++index;
- }
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
- {
- if((0u != glyphIndex) && (glyphIndex <= mEmbeddedItemCache.Count()))
- {
- // It's an embedded item.
- const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
-
- data.width = item.width;
- data.height = item.height;
- if(0u != item.pixelBufferId)
- {
- Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId - 1u].pixelBuffer;
- if(pixelBuffer)
- {
- ConvertBitmap(data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer());
-
- // Sets the pixel format.
- data.format = pixelBuffer.GetPixelFormat();
- }
- }
- else
- {
- // Creates the output buffer
- const unsigned int bufferSize = data.width * data.height * 4u;
- data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
-
- memset(data.buffer, 0u, bufferSize);
-
- // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
- }
- }
- }
-}
-
-PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth)
-{
- TextAbstraction::FontClient::GlyphBufferData data;
-
- CreateBitmap(fontId, glyphIndex, false, false, data, outlineWidth);
-
- return PixelData::New(data.buffer,
- data.width * data.height * Pixel::GetBytesPerPixel(data.format),
- data.width,
- data.height,
- data.format,
- PixelData::DELETE_ARRAY);
-}
-
-void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
-{
- blob = nullptr;
- blobLength = 0;
-
-#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
- if((fontId > 0u) &&
- (fontId - 1u < mFontIdCache.Count()))
- {
- const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
- FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
-
- if(!font.mVectorFontId)
- {
- font.mVectorFontId = mVectorFontCache->GetFontId(font.mPath);
- }
-
- mVectorFontCache->GetVectorBlob(font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight);
- }
-#endif
-}
-
-const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph(PointSize26Dot6 requestedPointSize)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize);
-
- // First look into the cache if there is an ellipsis glyph for the requested point size.
- for(const auto& item : mEllipsisCache)
- {
- if(item.requestedPointSize == requestedPointSize)
- {
- // Use the glyph in the cache.
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
- DALI_LOG_INFO(gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n");
-
- return item.glyph;
- }
- }
-
- // No glyph has been found. Create one.
- mEllipsisCache.PushBack(EllipsisItem());
- EllipsisItem& item = *(mEllipsisCache.End() - 1u);
-
- item.requestedPointSize = requestedPointSize;
-
- // Find a font for the ellipsis glyph.
- item.glyph.fontId = FindDefaultFont(ELLIPSIS_CHARACTER,
- requestedPointSize,
- false);
-
- // Set the character index to access the glyph inside the font.
- item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].id].mFreeTypeFace,
- ELLIPSIS_CHARACTER);
-
- GetBitmapMetrics(&item.glyph, 1u, true);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
- DALI_LOG_INFO(gLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n");
-
- return item.glyph;
-}
-
-bool FontClient::Plugin::IsColorGlyph(FontId fontId, GlyphIndex glyphIndex)
-{
- FT_Error error = -1;
-
- const FontId index = fontId - 1u;
-
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
-#ifdef FREETYPE_BITMAP_SUPPORT
- const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
- FT_Face ftFace = item.mFreeTypeFace;
-
- // Check to see if this is fixed size bitmap
- if(item.mHasColorTables)
- {
- error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_COLOR);
- }
-#endif
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- error = FT_Err_Ok; // Will return true;
- break;
- }
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
-
- return FT_Err_Ok == error;
-}
-
-FT_FaceRec_* FontClient::Plugin::GetFreetypeFace(FontId fontId)
-{
- FT_Face fontFace = nullptr;
-
- const FontId index = fontId - 1u;
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- if(FontDescription::FACE_FONT == fontIdCacheItem.type)
- {
- fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
- }
- }
- return fontFace;
-}
-
-FontDescription::Type FontClient::Plugin::GetFontType(FontId fontId)
-{
- const FontId index = fontId - 1u;
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
- {
- return mFontIdCache[index].type;
- }
- return FontDescription::INVALID;
-}
-
-bool FontClient::Plugin::AddCustomFontDirectory(const FontPath& path)
-{
- // nullptr as first parameter means the current configuration is used.
- return FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
-}
-
-GlyphIndex FontClient::Plugin::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
-{
- EmbeddedItem embeddedItem;
-
- embeddedItem.pixelBufferId = 0u;
- embeddedItem.width = description.width;
- embeddedItem.height = description.height;
-
- pixelFormat = Pixel::A8;
-
- if(!description.url.empty())
- {
- // Check if the url is in the cache.
- PixelBufferId index = 0u;
-
- for(const auto& cacheItem : mPixelBufferCache)
- {
- ++index;
- if(cacheItem.url == description.url)
- {
- // The url is in the pixel buffer cache.
- // Set the index +1 to the vector.
- embeddedItem.pixelBufferId = index;
- break;
- }
- }
-
- Devel::PixelBuffer pixelBuffer;
- if(0u == embeddedItem.pixelBufferId)
- {
- // The pixel buffer is not in the cache. Create one and cache it.
-
- // Load the image from the url.
- pixelBuffer = LoadImageFromFile(description.url);
-
- // Create the cache item.
- PixelBufferCacheItem pixelBufferCacheItem;
- pixelBufferCacheItem.pixelBuffer = pixelBuffer;
- pixelBufferCacheItem.url = description.url;
-
- // Store the cache item in the cache.
- mPixelBufferCache.push_back(std::move(pixelBufferCacheItem));
-
- // Set the pixel buffer id to the embedded item.
- embeddedItem.pixelBufferId = mPixelBufferCache.size();
- }
- else
- {
- // Retrieve the pixel buffer from the cache to set the pixel format.
- pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId - 1u].pixelBuffer;
- }
-
- if(pixelBuffer)
- {
- // Set the size of the embedded item if it has not been set.
- if(0u == embeddedItem.width)
- {
- embeddedItem.width = static_cast<unsigned int>(pixelBuffer.GetWidth());
- }
-
- if(0u == embeddedItem.height)
- {
- embeddedItem.height = static_cast<unsigned int>(pixelBuffer.GetHeight());
- }
-
- // Set the pixel format.
- pixelFormat = pixelBuffer.GetPixelFormat();
- }
- }
-
- // Find if the same embeddedItem has already been created.
- unsigned int index = 0u;
- for(const auto& item : mEmbeddedItemCache)
- {
- ++index;
- if((item.pixelBufferId == embeddedItem.pixelBufferId) &&
- (item.width == embeddedItem.width) &&
- (item.height == embeddedItem.height))
- {
- return index;
- }
- }
-
- // Cache the embedded item.
- mEmbeddedItemCache.PushBack(embeddedItem);
-
- return mEmbeddedItemCache.Count();
-}
-//SHS
-
-void FontClient::Plugin::EnableAtlasLimitation(bool enabled)
-{
- mIsAtlasLimitationEnabled = enabled;
-}
-
-bool FontClient::Plugin::IsAtlasLimitationEnabled() const
-{
- return mIsAtlasLimitationEnabled;
-}
-
-Size FontClient::Plugin::GetMaximumTextAtlasSize() const
-{
- return TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE;
-}
-
-Size FontClient::Plugin::GetDefaultTextAtlasSize() const
-{
- return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE;
-}
-
-Size FontClient::Plugin::GetCurrentMaximumBlockSizeFitInAtlas() const
-{
- return mCurrentMaximumBlockSizeFitInAtlas;
-}
-
-bool FontClient::Plugin::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas)
-{
- bool isChanged = false;
- const Size& maxTextAtlasSize = TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE;
- const uint16_t& padding = TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK;
-
- if(currentMaximumBlockSizeFitInAtlas.width <= maxTextAtlasSize.width - padding && currentMaximumBlockSizeFitInAtlas.height <= maxTextAtlasSize.height - padding)
- {
- mCurrentMaximumBlockSizeFitInAtlas = currentMaximumBlockSizeFitInAtlas;
- isChanged = true;
- }
-
- return isChanged;
-}
-
-uint32_t FontClient::Plugin::GetNumberOfPointsPerOneUnitOfPointSize() const
-{
- return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
- ;
-}
-
-void FontClient::Plugin::InitSystemFonts()
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n");
-
- FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
-
- if(fontSet)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont);
-
- // Reserve some space to avoid reallocations.
- mSystemFonts.reserve(fontSet->nfont);
-
- for(int i = 0u; i < fontSet->nfont; ++i)
- {
- FcPattern* fontPattern = fontSet->fonts[i];
-
- FontPath path;
-
- // Skip fonts with no path
- if(GetFcString(fontPattern, FC_FILE, path))
- {
- mSystemFonts.push_back(FontDescription());
- FontDescription& fontDescription = mSystemFonts.back();
-
- fontDescription.path = std::move(path);
-
- int width = 0;
- int weight = 0;
- int slant = 0;
- GetFcString(fontPattern, FC_FAMILY, fontDescription.family);
- GetFcInt(fontPattern, FC_WIDTH, width);
- GetFcInt(fontPattern, FC_WEIGHT, weight);
- GetFcInt(fontPattern, FC_SLANT, slant);
- fontDescription.width = IntToWidthType(width);
- fontDescription.weight = IntToWeightType(weight);
- fontDescription.slant = IntToSlantType(slant);
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- }
- }
-
- // Destroys the font set created.
- FcFontSetDestroy(fontSet);
- }
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n");
-}
-
-bool FontClient::Plugin::MatchFontDescriptionToPattern(FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n");
-
- FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, pattern, &result); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
-
- const bool matched = nullptr != match;
- DALI_LOG_INFO(gLogFilter, Debug::General, " pattern matched : %s\n", (matched ? "true" : "false"));
-
- if(matched)
- {
- int width = 0;
- int weight = 0;
- int slant = 0;
- GetFcString(match, FC_FILE, fontDescription.path);
- GetFcString(match, FC_FAMILY, fontDescription.family);
- GetFcInt(match, FC_WIDTH, width);
- GetFcInt(match, FC_WEIGHT, weight);
- GetFcInt(match, FC_SLANT, slant);
- fontDescription.width = IntToWidthType(width);
- fontDescription.weight = IntToWeightType(weight);
- fontDescription.slant = IntToSlantType(slant);
-
- // Retrieve the character set and increase the reference counter.
- FcPatternGetCharSet(match, FC_CHARSET, 0u, characterSet);
- *characterSet = FcCharSetCopy(*characterSet);
-
- // destroyed the matched pattern
- FcPatternDestroy(match);
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n");
- return matched;
-}
-
-FcPattern* FontClient::Plugin::CreateFontFamilyPattern(const FontDescription& fontDescription) const
-{
- // create the cached font family lookup pattern
- // a pattern holds a set of names, each name refers to a property of the font
- FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
-
- if(!fontFamilyPattern)
- {
- return nullptr;
- }
-
- // add a property to the pattern for the font family
- FcPatternAddString(fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fontDescription.family.c_str()));
-
- // add a property to the pattern for local setting.
- const char* locale = setlocale(LC_MESSAGES, nullptr);
- if(locale != nullptr)
- {
- FcPatternAddString(fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>(locale));
- }
-
- int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
- if(width < 0)
- {
- // Use default.
- width = DEFAULT_FONT_WIDTH;
- }
-
- int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
- if(weight < 0)
- {
- // Use default.
- weight = DEFAULT_FONT_WEIGHT;
- }
-
- int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
- if(slant < 0)
- {
- // Use default.
- slant = DEFAULT_FONT_SLANT;
- }
-
- FcPatternAddInteger(fontFamilyPattern, FC_WIDTH, width);
- FcPatternAddInteger(fontFamilyPattern, FC_WEIGHT, weight);
- FcPatternAddInteger(fontFamilyPattern, FC_SLANT, slant);
-
- // modify the config, with the mFontFamilyPatterm
- FcConfigSubstitute(nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern);
-
- // provide default values for unspecified properties in the font pattern
- // e.g. patterns without a specified style or weight are set to Medium
- FcDefaultSubstitute(fontFamilyPattern);
-
- return fontFamilyPattern;
-}
-
-_FcFontSet* FontClient::Plugin::GetFcFontSet() const
-{
- FcFontSet* fontset = nullptr;
-
- // create a new pattern.
- // a pattern holds a set of names, each name refers to a property of the font
- FcPattern* pattern = FcPatternCreate();
-
- if(nullptr != pattern)
- {
- // create an object set used to define which properties are to be returned in the patterns from FcFontList.
- FcObjectSet* objectSet = FcObjectSetCreate();
-
- if(nullptr != objectSet)
- {
- // build an object set from a list of property names
- FcObjectSetAdd(objectSet, FC_FILE);
- FcObjectSetAdd(objectSet, FC_FAMILY);
- FcObjectSetAdd(objectSet, FC_WIDTH);
- FcObjectSetAdd(objectSet, FC_WEIGHT);
- FcObjectSetAdd(objectSet, FC_SLANT);
-
- // get a list of fonts
- // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
- fontset = FcFontList(nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
-
- // clear up the object set
- FcObjectSetDestroy(objectSet);
- }
-
- // clear up the pattern
- FcPatternDestroy(pattern);
- }
-
- return fontset;
-}
-
-bool FontClient::Plugin::GetFcString(const FcPattern* const pattern,
- const char* const n,
- std::string& string)
-{
- FcChar8* file = nullptr;
- const FcResult retVal = FcPatternGetString(pattern, n, 0u, &file);
-
- if(FcResultMatch == retVal)
- {
- // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
- string.assign(reinterpret_cast<const char*>(file));
-
- return true;
- }
-
- return false;
-}
-
-bool FontClient::Plugin::GetFcInt(const _FcPattern* const pattern, const char* const n, int& intVal)
-{
- const FcResult retVal = FcPatternGetInteger(pattern, n, 0u, &intVal);
-
- if(FcResultMatch == retVal)
- {
- return true;
- }
-
- return false;
-}
-
-FontId FontClient::Plugin::CreateFont(const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex faceIndex,
- bool cacheDescription)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " path : [%s]\n", path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
-
- FontId id = 0u;
-
- // Create & cache new font face
- FT_Face ftFace;
- int error = FT_New_Face(mFreeTypeLibrary,
- path.c_str(),
- 0,
- &ftFace);
-
- if(FT_Err_Ok == error)
- {
- // Check if a font is scalable.
- const bool isScalable = (0 != (ftFace->face_flags & FT_FACE_FLAG_SCALABLE));
- const bool hasFixedSizedBitmaps = (0 != (ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES)) && (0 != ftFace->num_fixed_sizes);
- const bool hasColorTables = (0 != (ftFace->face_flags & FT_FACE_FLAG_COLOR));
- FontId fontFaceId = 0u;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " isScalable : [%s]\n", (isScalable ? "true" : "false"));
- DALI_LOG_INFO(gLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", (hasFixedSizedBitmaps ? "true" : "false"));
- DALI_LOG_INFO(gLogFilter, Debug::General, " hasColorTables : [%s]\n", (hasColorTables ? "true" : "false"));
-
- // Check to see if the font contains fixed sizes?
- if(!isScalable && hasFixedSizedBitmaps)
- {
- PointSize26Dot6 actualPointSize = 0u;
- int fixedSizeIndex = 0;
- for(; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex)
- {
- const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize);
-
- if(fixedSize >= requestedPointSize)
- {
- actualPointSize = fixedSize;
- break;
- }
- }
-
- if(0u == actualPointSize)
- {
- // The requested point size is bigger than the bigest fixed size.
- fixedSizeIndex = ftFace->num_fixed_sizes - 1;
- actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize);
-
- // Tell Freetype to use this size
- error = FT_Select_Size(ftFace, fixedSizeIndex);
- if(FT_Err_Ok != error)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error);
- }
- else
- {
- const float fixedWidth = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].width);
- const float fixedHeight = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].height);
-
- // Indicate that the font is a fixed sized bitmap
- FontMetrics metrics(fixedHeight, // The ascender in pixels.
- 0.0f,
- fixedHeight, // The height in pixels.
- 0.0f,
- 0.0f);
-
- // Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
-
- // Set the index to the font's id cache.
- fontFaceCacheItem.mFontId = mFontIdCache.Count();
-
- // Create the font id item to cache.
- FontIdCacheItem fontIdCacheItem;
- fontIdCacheItem.type = FontDescription::FACE_FONT;
-
- // Set the index to the FreeType font face cache.
- fontIdCacheItem.id = mFontFaceCache.size();
- fontFaceId = fontIdCacheItem.id + 1u;
-
- // Cache the items.
- mFontFaceCache.push_back(fontFaceCacheItem);
- mFontIdCache.PushBack(fontIdCacheItem);
-
- // Set the font id to be returned.
- id = mFontIdCache.Count();
- }
- }
- else
- {
- if(mIsAtlasLimitationEnabled)
- {
- //There is limitation on block size to fit in predefined atlas size.
- //If the block size cannot fit into atlas size, then the system cannot draw block.
- //This is workaround to avoid issue in advance
- //Decrementing point-size until arriving to maximum allowed block size.
- auto requestedPointSizeBackup = requestedPointSize;
- const Size& maxSizeFitInAtlas = GetCurrentMaximumBlockSizeFitInAtlas();
- error = SearchOnProperPointSize(ftFace, mDpiHorizontal, mDpiVertical, maxSizeFitInAtlas, requestedPointSize);
-
- if(requestedPointSize != requestedPointSizeBackup)
- {
- DALI_LOG_WARNING(" The requested-point-size : %d, is reduced to point-size : %d\n", requestedPointSizeBackup, requestedPointSize);
- }
- }
- else
- {
- error = FT_Set_Char_Size(ftFace,
- 0,
- requestedPointSize,
- mDpiHorizontal,
- mDpiVertical);
- }
-
- if(FT_Err_Ok == error)
- {
- FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
-
- FontMetrics metrics(static_cast<float>(ftMetrics.ascender) * FROM_266,
- static_cast<float>(ftMetrics.descender) * FROM_266,
- static_cast<float>(ftMetrics.height) * FROM_266,
- static_cast<float>(ftFace->underline_position) * FROM_266,
- static_cast<float>(ftFace->underline_thickness) * FROM_266);
-
- // Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(ftFace, path, requestedPointSize, faceIndex, metrics);
-
- // Set the index to the font's id cache.
- fontFaceCacheItem.mFontId = mFontIdCache.Count();
-
- // Create the font id item to cache.
- FontIdCacheItem fontIdCacheItem;
- fontIdCacheItem.type = FontDescription::FACE_FONT;
-
- // Set the index to the FreeType font face cache.
- fontIdCacheItem.id = mFontFaceCache.size();
- fontFaceId = fontIdCacheItem.id + 1u;
-
- // Cache the items.
- mFontFaceCache.push_back(fontFaceCacheItem);
- mFontIdCache.PushBack(fontIdCacheItem);
-
- // Set the font id to be returned.
- id = mFontIdCache.Count();
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize);
- }
- }
-
- if(0u != fontFaceId)
- {
- if(cacheDescription)
- {
- CacheFontPath(ftFace, fontFaceId, requestedPointSize, path);
- }
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str());
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font id : %d\n", id);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n");
-
- return id;
-}
-
-void FontClient::Plugin::ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer)
-{
- // Set the input dimensions.
- const ImageDimensions inputDimensions(srcWidth, srcHeight);
-
- // Set the output dimensions.
- // If the output dimension is not given, the input dimension is set
- // and won't be downscaling.
- data.width = (data.width == 0) ? srcWidth : data.width;
- data.height = (data.height == 0) ? srcHeight : data.height;
- const ImageDimensions desiredDimensions(data.width, data.height);
-
- // Creates the output buffer
- const unsigned int bufferSize = data.width * data.height * 4u;
- data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
-
- if(inputDimensions == desiredDimensions)
- {
- // There isn't downscaling.
- memcpy(data.buffer, srcBuffer, bufferSize);
- }
- else
- {
- Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
- inputDimensions,
- data.buffer,
- desiredDimensions);
- }
-}
-
-void FontClient::Plugin::ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired)
-{
- if(srcBitmap.width * srcBitmap.rows > 0)
- {
- switch(srcBitmap.pixel_mode)
- {
- case FT_PIXEL_MODE_GRAY:
- {
- if(srcBitmap.pitch == static_cast<int>(srcBitmap.width))
- {
- uint8_t* pixelsIn = srcBitmap.buffer;
- unsigned int width = srcBitmap.width;
- unsigned height = srcBitmap.rows;
-
- std::unique_ptr<uint8_t, void (*)(void*)> pixelsOutPtr(nullptr, free);
-
- if(isShearRequired)
- {
- /**
- * Glyphs' bitmaps with no slant retrieved from FreeType:
- * __________ ____
- * |XXXXXXXX| |XX|
- * | XX | |XX|
- * | XX | |XX|
- * | XX | |XX|
- * | XX | |XX|
- * | XX | |XX|
- * ---------- ----
- *
- * Expected glyphs' bitmaps with italic slant:
- * ____________ ______
- * | XXXXXXXX| | XX|
- * | XX | | XX|
- * | XX | | XX |
- * | XX | | XX |
- * | XX | |XX |
- * | XX | |XX |
- * ------------ ------
- *
- * Glyphs' bitmaps with software italic slant retrieved from FreeType:
- * __________ ______
- * |XXXXXXXX| | XX|
- * | XX | | XX|
- * | XX | | XX |
- * | XX | | XX |
- * | XX | |XX |
- * | XX | |XX |
- * ---------- ------
- *
- * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
- */
- unsigned int widthOut = 0u;
- unsigned int heightOut = 0u;
- uint8_t* pixelsOut = nullptr;
-
- Dali::Internal::Platform::HorizontalShear(pixelsIn,
- width,
- height,
- 1u,
- -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
- pixelsOut,
- widthOut,
- heightOut);
-
- width = widthOut;
- height = heightOut;
- pixelsIn = pixelsOut;
- pixelsOutPtr.reset(pixelsOut);
- }
-
- const unsigned int bufferSize = width * height;
- data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
- data.width = width;
- data.height = height;
- data.format = Pixel::L8; // Sets the pixel format.
- memcpy(data.buffer, pixelsIn, bufferSize);
- }
- break;
- }
-
-#ifdef FREETYPE_BITMAP_SUPPORT
- case FT_PIXEL_MODE_BGRA:
- {
- if(srcBitmap.pitch == static_cast<int>(srcBitmap.width << 2u))
- {
- ConvertBitmap(data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer);
-
- // Sets the pixel format.
- data.format = Pixel::BGRA8888;
- }
- break;
- }
-#endif
- default:
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n");
- break;
- }
- }
- }
-}
-
-bool FontClient::Plugin::FindFont(const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex faceIndex,
- FontId& fontId) const
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " path : [%s]\n", path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size());
-
- fontId = 0u;
- for(const auto& cacheItem : mFontFaceCache)
- {
- if(cacheItem.mRequestedPointSize == requestedPointSize &&
- cacheItem.mFaceIndex == faceIndex &&
- cacheItem.mPath == path)
- {
- fontId = cacheItem.mFontId + 1u;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font found, id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n");
-
- return true;
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font not found\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n");
-
- return false;
-}
-
-bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescription,
- FontDescriptionId& validatedFontId)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size());
-
- validatedFontId = 0u;
-
- for(const auto& item : mValidatedFontCache)
- {
- if(!fontDescription.family.empty() &&
- (fontDescription.family == item.fontDescription.family) &&
- (fontDescription.width == item.fontDescription.width) &&
- (fontDescription.weight == item.fontDescription.weight) &&
- (fontDescription.slant == item.fontDescription.slant))
- {
- validatedFontId = item.index;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n");
- return true;
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " validated font not found\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n");
- return false;
-}
-
-bool FontClient::Plugin::FindFallbackFontList(const FontDescription& fontDescription,
- FontList*& fontList,
- CharacterSetList*& characterSetList)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " description; family : [%s]\n", fontDescription.family.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " path : [%s]\n", fontDescription.path.c_str());
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " width : [%s]\n", FontWidth::Name[fontDescription.width]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " weight : [%s]\n", FontWeight::Name[fontDescription.weight]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " slant : [%s]\n\n", FontSlant::Name[fontDescription.slant]);
- DALI_LOG_INFO(gLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size());
-
- fontList = nullptr;
-
- for(const auto& item : mFallbackCache)
- {
- if(!fontDescription.family.empty() &&
- (fontDescription.family == item.fontDescription.family) &&
- (fontDescription.width == item.fontDescription.width) &&
- (fontDescription.weight == item.fontDescription.weight) &&
- (fontDescription.slant == item.fontDescription.slant))
- {
- fontList = item.fallbackFonts;
- characterSetList = item.characterSets;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " fallback font list found.\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n");
- return true;
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " fallback font list not found.\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n");
- return false;
-}
-
-bool FontClient::Plugin::FindFont(FontDescriptionId validatedFontId,
- PointSize26Dot6 requestedPointSize,
- FontId& fontId)
-{
- DALI_LOG_INFO(gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
-
- fontId = 0u;
-
- for(const auto& item : mFontDescriptionSizeCache)
- {
- if((validatedFontId == item.validatedFontId) &&
- (requestedPointSize == item.requestedPointSize))
- {
- fontId = item.fontId;
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font found, id : %d\n", fontId);
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n");
- return true;
- }
- }
-
- DALI_LOG_INFO(gLogFilter, Debug::General, " font not found.\n");
- DALI_LOG_INFO(gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n");
- return false;
-}
-
-bool FontClient::Plugin::FindBitmapFont(const FontFamily& bitmapFont, FontId& fontId) const
-{
- fontId = 0u;
-
- for(const auto& item : mBitmapFontCache)
- {
- if(bitmapFont == item.font.name)
- {
- fontId = item.id + 1u;
- return true;
- }
- }
-
- return false;
-}
-
-bool FontClient::Plugin::IsScalable(const FontPath& path)
-{
- bool isScalable = false;
-
- FT_Face ftFace;
- int error = FT_New_Face(mFreeTypeLibrary,
- path.c_str(),
- 0,
- &ftFace);
- if(FT_Err_Ok != error)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str());
- }
- else
- {
- isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
- }
-
- return isScalable;
-}
-
-bool FontClient::Plugin::IsScalable(const FontDescription& fontDescription)
-{
- // Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcResult result = FcResultMatch;
-
- // match the pattern
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
- bool isScalable = false;
-
- if(match)
- {
- // Get the path to the font file name.
- FontPath path;
- GetFcString(match, FC_FILE, path);
- isScalable = IsScalable(path);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str());
- }
-
- // Destroys the created patterns.
- FcPatternDestroy(match);
- FcPatternDestroy(fontFamilyPattern);
-
- return isScalable;
-}
-
-void FontClient::Plugin::GetFixedSizes(const FontPath& path, Vector<PointSize26Dot6>& sizes)
-{
- // Empty the caller container
- sizes.Clear();
-
- FT_Face ftFace;
- int error = FT_New_Face(mFreeTypeLibrary,
- path.c_str(),
- 0,
- &ftFace);
- if(FT_Err_Ok != error)
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str());
- }
-
- // Fetch the number of fixed sizes available
- if(ftFace->num_fixed_sizes && ftFace->available_sizes)
- {
- for(int i = 0; i < ftFace->num_fixed_sizes; ++i)
- {
- sizes.PushBack(ftFace->available_sizes[i].size);
- }
- }
-}
-
-void FontClient::Plugin::GetFixedSizes(const FontDescription& fontDescription,
- Vector<PointSize26Dot6>& sizes)
-{
- // Create a font pattern.
- FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcResult result = FcResultMatch;
-
- // match the pattern
- FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
-
- if(match)
- {
- // Get the path to the font file name.
- FontPath path;
- GetFcString(match, FC_FILE, path);
- GetFixedSizes(path, sizes);
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str());
- }
-
- // Destroys the created patterns.
- FcPatternDestroy(match);
- FcPatternDestroy(fontFamilyPattern);
-}
-
-bool FontClient::Plugin::HasItalicStyle(FontId fontId) const
-{
- bool hasItalicStyle = false;
-
- const FontId index = fontId - 1u;
-
- if((fontId > 0) &&
- (index < mFontIdCache.Count()))
- {
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- if(FontDescription::FACE_FONT == fontIdCacheItem.type)
- {
- const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
-
- hasItalicStyle = 0u != (font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC);
- }
- }
- else
- {
- DALI_LOG_INFO(gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId);
- }
-
- return hasItalicStyle;
-}
-
-void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path)
-{
- FontDescription description;
- description.path = path;
- description.family = std::move(FontFamily(ftFace->family_name));
- description.weight = FontWeight::NONE;
- description.width = FontWidth::NONE;
- description.slant = FontSlant::NONE;
-
- // Note FreeType doesn't give too much info to build a proper font style.
- if(ftFace->style_flags & FT_STYLE_FLAG_ITALIC)
- {
- description.slant = FontSlant::ITALIC;
- }
- if(ftFace->style_flags & FT_STYLE_FLAG_BOLD)
- {
- description.weight = FontWeight::BOLD;
- }
-
- FontDescriptionId validatedFontId = 0u;
- if(!FindValidatedFont(description,
- validatedFontId))
- {
- FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcCharSet* characterSet = nullptr;
- FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
-
- const FontId fontFaceId = id - 1u;
- mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(characterSet); // Increases the reference counter.
-
- // Destroys the created patterns.
- FcPatternDestroy(match);
- FcPatternDestroy(pattern);
-
- // Add the path to the cache.
- description.type = FontDescription::FACE_FONT;
- mFontDescriptionCache.push_back(description);
-
- // Set the index to the vector of paths to font file names.
- validatedFontId = mFontDescriptionCache.size();
-
- // Increase the reference counter and add the character set to the cache.
- mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
-
- // Cache the index and the font's description.
- mValidatedFontCache.push_back(std::move(FontDescriptionCacheItem(std::move(description),
- validatedFontId)));
-
- // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
- mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
- requestedPointSize,
- fontFaceId));
- }
-}
-
-FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription(const FontDescription& description)
-{
- FcCharSet* characterSet = nullptr;
-
- FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
-
- if(nullptr != pattern)
- {
- FcResult result = FcResultMatch;
- FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
-
- FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
-
- // Destroys the created patterns.
- FcPatternDestroy(match);
- FcPatternDestroy(pattern);
- }
-
- return characterSet;
-}
-
-void FontClient::Plugin::ClearFallbackCache(std::vector<FallbackCacheItem>& fallbackCache)
-{
- for(auto& item : fallbackCache)
- {
- if(nullptr != item.fallbackFonts)
- {
- delete item.fallbackFonts;
- }
-
- if(nullptr != item.characterSets)
- {
- // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
- DestroyCharacterSets(*item.characterSets);
- delete item.characterSets;
- }
- }
-}
-
-void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
-{
- for(auto& item : mFontFaceCache)
- {
- FcCharSetDestroy(item.mCharacterSet);
- item.mCharacterSet = nullptr;
- }
-}
-
-} // namespace Internal
-
-} // namespace TextAbstraction
-
-} // namespace Dali
--- /dev/null
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h>
+
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+BitmapFontCacheItem::BitmapFontCacheItem(const BitmapFont& bitmapFont, FontId fontId)
+: font(bitmapFont),
+ id(fontId)
+{
+ // Resize the vector with the pixel buffers.
+ pixelBuffers.resize(bitmapFont.glyphs.size());
+
+ // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
+ unsigned int index = 0u;
+ for(auto& glyph : font.glyphs)
+ {
+ Devel::PixelBuffer& pixelBuffer = pixelBuffers[index];
+
+ if(EqualsZero(glyph.ascender) && EqualsZero(glyph.descender))
+ {
+ // Load the glyph.
+ pixelBuffer = LoadImageFromFile(glyph.url);
+
+ if(pixelBuffer)
+ {
+ glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
+ }
+ }
+
+ font.ascender = std::max(glyph.ascender, font.ascender);
+ font.descender = std::min(glyph.descender, font.descender);
+
+ ++index;
+ }
+}
+
+void BitmapFontCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const
+{
+ metrics.ascender = font.ascender;
+ metrics.descender = font.descender;
+ metrics.height = metrics.ascender - metrics.descender;
+ metrics.underlinePosition = font.underlinePosition;
+ metrics.underlineThickness = font.underlineThickness;
+}
+
+bool BitmapFontCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const
+{
+ bool success(false);
+
+ unsigned int index = 0u;
+ for(auto& item : font.glyphs)
+ {
+ if(item.utf32 == glyph.index)
+ {
+ Devel::PixelBuffer& pixelBuffer = const_cast<Devel::PixelBuffer&>(pixelBuffers[index]);
+ if(!pixelBuffer)
+ {
+ pixelBuffer = LoadImageFromFile(item.url);
+ }
+
+ glyph.width = static_cast<float>(pixelBuffer.GetWidth());
+ glyph.height = static_cast<float>(pixelBuffer.GetHeight());
+ glyph.xBearing = 0.f;
+ glyph.yBearing = glyph.height + item.descender;
+ glyph.advance = glyph.width;
+ glyph.scaleFactor = 1.f;
+ success = true;
+ break;
+ }
+ ++index;
+ }
+ return success;
+}
+
+void BitmapFontCacheItem::CreateBitmap(
+ GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+{
+ unsigned int index = 0u;
+ for(auto& item : font.glyphs)
+ {
+ if(item.utf32 == glyphIndex)
+ {
+ Devel::PixelBuffer& pixelBuffer = const_cast<Devel::PixelBuffer&>(pixelBuffers[index]);
+ if(!pixelBuffer)
+ {
+ pixelBuffer = LoadImageFromFile(item.url);
+ }
+
+ data.width = pixelBuffer.GetWidth();
+ data.height = pixelBuffer.GetHeight();
+
+ data.isColorBitmap = font.isColorFont;
+
+ ConvertBitmap(data, data.width, data.height, pixelBuffer.GetBuffer());
+
+ // Sets the pixel format.
+ data.format = pixelBuffer.GetPixelFormat();
+ break;
+ }
+ ++index;
+ }
+}
+
+bool BitmapFontCacheItem::IsCharacterSupported(Character character)
+{
+ for(const auto& glyph : font.glyphs)
+ {
+ if(glyph.utf32 == character)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace Dali::TextAbstraction::Internal
--- /dev/null
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_BITMAP_FONT_CACHE_ITEM_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_BITMAP_FONT_CACHE_ITEM_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+#include <dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Stores a bitmap font and its pixel buffers per glyph.
+ */
+struct BitmapFontCacheItem : public FontCacheItemInterface
+{
+ /**
+ * Constructor
+ *
+ * @param[in] bitmapFont The font to cache
+ * @param[in] fontId The id of the font
+ */
+ BitmapFontCacheItem(const BitmapFont& bitmapFont, FontId fontId);
+
+ /**
+ * @copydoc FontCacheItemInterface::GetFontMetrics()
+ */
+ void GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::GetGlyphMetrics()
+ */
+ bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::CreateBitmap()
+ */
+ void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::IsColorGlyph()
+ */
+ bool IsColorGlyph(GlyphIndex glyphIndex) const override
+ {
+ return true;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::IsCharacterSupported()
+ */
+ bool IsCharacterSupported(Character character) override;
+
+ /**
+ * @copydoc FontCacheItemInterface::GetPointSize()
+ */
+ PointSize26Dot6 GetPointSize() const override
+ {
+ return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::GetGlyphIndex()
+ */
+ GlyphIndex GetGlyphIndex(Character character) const override
+ {
+ return 0u;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::GetTypeface()
+ */
+ FT_Face GetTypeface() const override
+ {
+ return nullptr;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::HasItalicStyle()
+ */
+ bool HasItalicStyle() const override
+ {
+ return false;
+ }
+
+ BitmapFont font; ///< The bitmap font.
+ std::vector<Devel::PixelBuffer> pixelBuffers; ///< The pixel buffers of the glyphs.
+ FontId id; ///< Index to the vector with the cache of font's ids.
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_INTERNAL_TEXT_ABSTRACTION_BITMAP_FONT_CACHE_ITEM_H
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/internal/text/text-abstraction/plugin/embedded-item.h>
+
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+
+namespace Dali::TextAbstraction::Internal
+{
+void EmbeddedItem::GetGlyphMetrics(GlyphInfo& glyph)
+{
+ glyph.width = static_cast<float>(width);
+ glyph.height = static_cast<float>(height);
+ glyph.xBearing = 0.f;
+ glyph.yBearing = glyph.height;
+ glyph.advance = glyph.width;
+ glyph.scaleFactor = 1.f;
+}
+
+void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+ Dali::TextAbstraction::FontClient::GlyphBufferData& data)
+{
+ data.width = width;
+ data.height = height;
+ if(0u != pixelBufferId)
+ {
+ Devel::PixelBuffer pixelBuffer = pixelBufferCache[pixelBufferId - 1u].pixelBuffer;
+ if(pixelBuffer)
+ {
+ ConvertBitmap(data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer());
+
+ // Sets the pixel format.
+ data.format = pixelBuffer.GetPixelFormat();
+ }
+ }
+ else
+ {
+ // Creates the output buffer
+ const unsigned int bufferSize = data.width * data.height * 4u;
+ data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+ memset(data.buffer, 0u, bufferSize);
+
+ // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
+ }
+}
+
+} // namespace Dali::TextAbstraction::Internal
--- /dev/null
+#ifndef DALI_INTERNAL_TEXTABSTRACTION_PLUGIN_EMBEDDED_ITEM_H
+#define DALI_INTERNAL_TEXTABSTRACTION_PLUGIN_EMBEDDED_ITEM_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/internal/text/text-abstraction/plugin/pixel-buffer-cache-item.h>
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Caches embedded items.
+ */
+struct EmbeddedItem
+{
+ /**
+ * Get metrics for glyph from image
+ * @param[in] item The embedded image
+ * @param[in,out] glyph The glyph to get metrics for
+ */
+ void GetGlyphMetrics(GlyphInfo& glyph);
+
+ /**
+ * @brief Create a glyph bitmap from an embedded item if present in the cache
+ *
+ * @param[in] pixelBufferCache The pixel buffer cache
+ * @param[out] data The bitmap data.
+ */
+ void CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+ Dali::TextAbstraction::FontClient::GlyphBufferData& data);
+
+ PixelBufferId pixelBufferId; ///< Index to the vector of pixel buffers
+ unsigned int width; ///< The desired width.
+ unsigned int height; ///< The desired height.
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_INTERNAL_TEXTABSTRACTION_PLUGIN_EMBEDDED_ITEM_H
--- /dev/null
+#ifndef DALI_TEST_ABSTRACTION_INTERNAL_FONT_CACHE_ITEM_INTERFACE_H
+#define DALI_TEST_ABSTRACTION_INTERNAL_FONT_CACHE_ITEM_INTERFACE_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace Dali::TextAbstraction::Internal
+{
+struct FontCacheItemInterface
+{
+ /**
+ * Get the font metrics
+ *
+ * @param[out] metrics The metrics struct to fill out
+ */
+ virtual void GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const = 0;
+
+ /**
+ * Get glyph metrics
+ *
+ * @param[in,out] glyph The glyph to fill
+ */
+ virtual bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const = 0;
+
+ /**
+ * Create a bitmap for the given glyph
+ *
+ * @param[in] glyphIndex The index of the glyph
+ * @param[out] data The bitmap data for the glyph
+ * @param[in] outlineWidth
+ * @param[in] isItalicRequired
+ * @param[in] isBoldRequired
+ */
+ virtual void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const = 0;
+
+ /**
+ * Return true if the glyph is colored
+ *
+ * @param[in] glyphIndex The index of the glyph
+ * @return true if the glyph is colored
+ */
+ virtual bool IsColorGlyph(GlyphIndex glyphIndex) const = 0;
+
+ /**
+ * Check if the character is supported by this font
+ * @param[in] character The character to test
+ */
+ virtual bool IsCharacterSupported(Character character) = 0;
+
+ /**
+ * Get the point size of this font
+ * @return the point size
+ */
+ virtual PointSize26Dot6 GetPointSize() const = 0;
+
+ /**
+ * Get the index into this font's glyph table of the character
+ *
+ * @param[in] character to look up
+ * @return the glyph index of this character
+ */
+ virtual GlyphIndex GetGlyphIndex(Character character) const = 0;
+
+ /**
+ * Get the freetype typeface for this font.
+ */
+ virtual FT_Face GetTypeface() const = 0;
+
+ /**
+ * @return true if this font has an italic style
+ */
+ virtual bool HasItalicStyle() const = 0;
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif // DALI_TEST_ABSTRACTION_INTERNAL_FONT_CACHE_ITEM_INTERFACE_H
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text/text-abstraction/plugin/font-client-plugin-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-list.h>
+
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h>
+#include <dali/internal/text/text-abstraction/plugin/embedded-item.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+#include <dali/internal/text/text-abstraction/plugin/font-face-cache-item.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+#include <algorithm>
+#include <iterator>
+
+#if defined(DEBUG_ENABLED)
+
+// Note, to turn on trace and verbose logging, use "export LOG_FONT_CLIENT=3,true"
+// Or re-define the following filter using Verbose,true instead of NoLogging,false,
+// Or, add DALI_LOG_FILTER_ENABLE_TRACE(gFontClientLogFilter) in the code below.
+
+Dali::Integration::Log::Filter* gFontClientLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+
+#define FONT_LOG_DESCRIPTION(fontDescription, prefix) \
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, #prefix " description; family : [%s]\n", fontDescription.family.c_str()); \
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, \
+ " path : [%s]\n" \
+ " width : [%s]\n" \
+ " weight : [%s]\n" \
+ " slant : [%s]\n\n", \
+ fontDescription.path.c_str(), \
+ FontWidth::Name[fontDescription.width], \
+ FontWeight::Name[fontDescription.weight], \
+ FontSlant::Name[fontDescription.slant])
+
+#define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor) \
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, \
+ " character : %p\n" \
+ " requestedPointSize : %d\n" \
+ " preferColor : %s\n", \
+ charcode, \
+ requestedPointSize, \
+ (preferColor ? "true" : "false"))
+
+#else
+
+#define FONT_LOG_DESCRIPTION(fontDescription, prefix)
+#define FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor)
+
+#endif
+
+namespace
+{
+/**
+ * Conversion from Fractional26.6 to float
+ */
+const float FROM_266 = 1.0f / 64.0f;
+const float POINTS_PER_INCH = 72.f;
+
+const std::string DEFAULT_FONT_FAMILY_NAME("Tizen");
+
+const uint32_t ELLIPSIS_CHARACTER = 0x2026;
+
+} // namespace
+
+using Dali::Vector;
+using namespace std;
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Free the resources allocated by the FcCharSet objects.
+ *
+ * @param[in] characterSets The vector of character sets.
+ */
+void DestroyCharacterSets(CharacterSetList& characterSets)
+{
+ for(auto& item : characterSets)
+ {
+ if(item)
+ {
+ FcCharSetDestroy(item);
+ }
+ }
+}
+
+/**
+ * @brief Check if @p ftFace and @p requestedPointSize produces block that fit into atlas block
+ *
+ * @param[in/out] ftFace Face type object.
+ * @param[in] horizontalDpi The horizontal dpi.
+ * @param[in] verticalDpi The vertical dpi.
+ * @param[in] maxSizeFitInAtlas The maximum size of block to fit into atlas
+ * @param[in] requestedPointSize The requested point-size.
+ * @return whether the ftFace's block can fit into atlas
+ */
+bool IsFitIntoAtlas(FT_Face& ftFace, int& error, const unsigned int& horizontalDpi, const unsigned int& verticalDpi, const Size& maxSizeFitInAtlas, const uint32_t& requestedPointSize)
+{
+ bool isFit = false;
+
+ error = FT_Set_Char_Size(ftFace,
+ 0,
+ requestedPointSize,
+ horizontalDpi,
+ verticalDpi);
+
+ if(error == FT_Err_Ok)
+ {
+ //Check width and height of block for requestedPointSize
+ //If the width or height is greater than the maximum-size then decrement by one unit of point-size.
+ if(static_cast<float>(ftFace->size->metrics.height) * FROM_266 <= maxSizeFitInAtlas.height && (static_cast<float>(ftFace->size->metrics.ascender) - static_cast<float>(ftFace->size->metrics.descender)) * FROM_266 <= maxSizeFitInAtlas.width)
+ {
+ isFit = true;
+ }
+ }
+
+ return isFit;
+}
+
+/**
+ * @brief Search on proper @p requestedPointSize that produces block that fit into atlas block considering on @p ftFace, @p horizontalDpi, and @p verticalDpi
+ *
+ * @param[in/out] ftFace Face type object.
+ * @param[in] horizontalDpi The horizontal dpi.
+ * @param[in] verticalDpi The vertical dpi.
+ * @param[in] maxSizeFitInAtlas The maximum size of block to fit into atlas
+ * @param[in/out] requestedPointSize The requested point-size.
+ * @return FreeType error code. 0 means success when requesting the nominal size (in points).
+ */
+int SearchOnProperPointSize(FT_Face& ftFace, const unsigned int& horizontalDpi, const unsigned int& verticalDpi, const Size& maxSizeFitInAtlas, uint32_t& requestedPointSize)
+{
+ //To improve performance of sequential search. This code is applying Exponential search then followed by Binary search.
+ const uint32_t& pointSizePerOneUnit = TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ bool canFitInAtlas;
+ int error; // FreeType error code.
+
+ canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
+ if(FT_Err_Ok != error)
+ {
+ return error;
+ }
+
+ if(!canFitInAtlas)
+ {
+ //Exponential search
+ uint32_t exponentialDecrement = 1;
+
+ while(!canFitInAtlas && requestedPointSize > pointSizePerOneUnit * exponentialDecrement)
+ {
+ requestedPointSize -= (pointSizePerOneUnit * exponentialDecrement);
+ canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
+ if(FT_Err_Ok != error)
+ {
+ return error;
+ }
+
+ exponentialDecrement *= 2;
+ }
+
+ //Binary search
+ uint32_t minPointSize;
+ uint32_t maxPointSize;
+
+ if(canFitInAtlas)
+ {
+ exponentialDecrement /= 2;
+ minPointSize = requestedPointSize;
+ maxPointSize = requestedPointSize + (pointSizePerOneUnit * exponentialDecrement);
+ }
+ else
+ {
+ minPointSize = 0;
+ maxPointSize = requestedPointSize;
+ }
+
+ while(minPointSize < maxPointSize)
+ {
+ requestedPointSize = ((maxPointSize / pointSizePerOneUnit - minPointSize / pointSizePerOneUnit) / 2) * pointSizePerOneUnit + minPointSize;
+ canFitInAtlas = IsFitIntoAtlas(ftFace, error, horizontalDpi, verticalDpi, maxSizeFitInAtlas, requestedPointSize);
+ if(FT_Err_Ok != error)
+ {
+ return error;
+ }
+
+ if(canFitInAtlas)
+ {
+ if(minPointSize == requestedPointSize)
+ {
+ //Found targeted point-size
+ return error;
+ }
+
+ minPointSize = requestedPointSize;
+ }
+ else
+ {
+ maxPointSize = requestedPointSize;
+ }
+ }
+ }
+
+ return error;
+}
+
+FontClient::Plugin::FallbackCacheItem::FallbackCacheItem(FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets)
+: fontDescription{std::move(font)},
+ fallbackFonts{fallbackFonts},
+ characterSets{characterSets}
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(const FontDescription& fontDescription,
+ FontDescriptionId index)
+: fontDescription{fontDescription},
+ index{index}
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem(FontDescription&& fontDescription,
+ FontDescriptionId index)
+: fontDescription{std::move(fontDescription)},
+ index{index}
+{
+}
+
+FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem(FontDescriptionId validatedFontId,
+ PointSize26Dot6 requestedPointSize,
+ FontId fontId)
+: validatedFontId(validatedFontId),
+ requestedPointSize(requestedPointSize),
+ fontId(fontId)
+{
+}
+
+FontClient::Plugin::Plugin(unsigned int horizontalDpi,
+ unsigned int verticalDpi)
+: mFreeTypeLibrary(nullptr),
+ mDpiHorizontal(horizontalDpi),
+ mDpiVertical(verticalDpi),
+ mDefaultFontDescription(),
+ mSystemFonts(),
+ mDefaultFonts(),
+ mFontIdCache(),
+ mFontFaceCache(),
+ mValidatedFontCache(),
+ mFontDescriptionCache(),
+ mCharacterSetCache(),
+ mFontDescriptionSizeCache(),
+ mVectorFontCache(nullptr),
+ mEllipsisCache(),
+ mEmbeddedItemCache(),
+ mDefaultFontDescriptionCached(false),
+ mIsAtlasLimitationEnabled(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED),
+ mCurrentMaximumBlockSizeFitInAtlas(TextAbstraction::FontClient::MAX_SIZE_FIT_IN_ATLAS)
+
+{
+ int error = FT_Init_FreeType(&mFreeTypeLibrary);
+ if(FT_Err_Ok != error)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FreeType Init error: %d\n", error);
+ }
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ mVectorFontCache = new VectorFontCache(mFreeTypeLibrary);
+#endif
+}
+
+FontClient::Plugin::~Plugin()
+{
+ ClearFallbackCache(mFallbackCache);
+
+ // Free the resources allocated by the FcCharSet objects.
+ DestroyCharacterSets(mDefaultFontCharacterSets);
+ DestroyCharacterSets(mCharacterSetCache);
+ ClearCharacterSetFromFontFaceCache();
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ delete mVectorFontCache;
+#endif
+ FT_Done_FreeType(mFreeTypeLibrary);
+}
+
+void FontClient::Plugin::ClearCache()
+{
+ mDefaultFontDescription = FontDescription();
+
+ mSystemFonts.clear();
+ mDefaultFonts.clear();
+
+ DestroyCharacterSets(mDefaultFontCharacterSets);
+ mDefaultFontCharacterSets.Clear();
+
+ ClearFallbackCache(mFallbackCache);
+ mFallbackCache.clear();
+
+ mFontIdCache.Clear();
+
+ ClearCharacterSetFromFontFaceCache();
+ mFontFaceCache.clear();
+
+ mValidatedFontCache.clear();
+ mFontDescriptionCache.clear();
+
+ DestroyCharacterSets(mCharacterSetCache);
+ mCharacterSetCache.Clear();
+
+ mFontDescriptionSizeCache.clear();
+
+ mEllipsisCache.Clear();
+ mPixelBufferCache.clear();
+ mEmbeddedItemCache.Clear();
+ mBitmapFontCache.clear();
+
+ mDefaultFontDescriptionCached = false;
+}
+
+void FontClient::Plugin::SetDpi(unsigned int horizontalDpi,
+ unsigned int verticalDpi)
+{
+ mDpiHorizontal = horizontalDpi;
+ mDpiVertical = verticalDpi;
+}
+
+void FontClient::Plugin::ResetSystemDefaults()
+{
+ mDefaultFontDescriptionCached = false;
+}
+
+void FontClient::Plugin::SetFontList(const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ fontList.clear();
+
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcResult result = FcResultMatch;
+
+ // Match the pattern.
+ FcFontSet* fontSet = FcFontSort(nullptr /* use default configure */,
+ fontFamilyPattern,
+ false /* don't trim */,
+ nullptr,
+ &result); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
+
+ if(nullptr != fontSet)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of fonts found : [%d]\n", fontSet->nfont);
+ // Reserve some space to avoid reallocations.
+ fontList.reserve(fontSet->nfont);
+
+ for(int i = 0u; i < fontSet->nfont; ++i)
+ {
+ FcPattern* fontPattern = fontSet->fonts[i];
+
+ FontPath path;
+
+ // Skip fonts with no path
+ if(GetFcString(fontPattern, FC_FILE, path))
+ {
+ // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
+ FcCharSet* characterSet = nullptr;
+ FcPatternGetCharSet(fontPattern, FC_CHARSET, 0u, &characterSet);
+
+ // Increase the reference counter of the character set.
+ characterSetList.PushBack(FcCharSetCopy(characterSet));
+
+ fontList.push_back(FontDescription());
+ FontDescription& newFontDescription = fontList.back();
+
+ newFontDescription.path = std::move(path);
+
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
+ GetFcString(fontPattern, FC_FAMILY, newFontDescription.family);
+ GetFcInt(fontPattern, FC_WIDTH, width);
+ GetFcInt(fontPattern, FC_WEIGHT, weight);
+ GetFcInt(fontPattern, FC_SLANT, slant);
+ newFontDescription.width = IntToWidthType(width);
+ newFontDescription.weight = IntToWeightType(weight);
+ newFontDescription.slant = IntToSlantType(slant);
+
+ FONT_LOG_DESCRIPTION(newFontDescription, "");
+ }
+ }
+
+ // Destroys the font set created by FcFontSort.
+ FcFontSetDestroy(fontSet);
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " No fonts found.\n");
+ }
+
+ // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
+ FcPatternDestroy(fontFamilyPattern);
+}
+
+void FontClient::Plugin::GetDefaultFonts(FontList& defaultFonts)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+
+ if(mDefaultFonts.empty())
+ {
+ FontDescription fontDescription;
+ fontDescription.family = DEFAULT_FONT_FAMILY_NAME; // todo This could be set to the Platform font
+ fontDescription.width = DefaultFontWidth();
+ fontDescription.weight = DefaultFontWeight();
+ fontDescription.slant = DefaultFontSlant();
+ SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
+ }
+
+ defaultFonts = mDefaultFonts;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of default fonts : [%d]\n", mDefaultFonts.size());
+}
+
+void FontClient::Plugin::GetDefaultPlatformFontDescription(FontDescription& fontDescription)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+
+ if(!mDefaultFontDescriptionCached)
+ {
+ // Clear any font config stored info in the caches.
+
+ // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
+ DestroyCharacterSets(mDefaultFontCharacterSets);
+ DestroyCharacterSets(mCharacterSetCache);
+ mDefaultFontCharacterSets.Clear();
+ mCharacterSetCache.Clear();
+
+ for(auto& item : mFallbackCache)
+ {
+ // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
+ DestroyCharacterSets(*item.characterSets);
+
+ delete item.characterSets;
+ item.characterSets = nullptr;
+ }
+
+ // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
+ ClearCharacterSetFromFontFaceCache();
+
+ // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
+ FcInitReinitialize();
+
+ FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ if(nullptr != matchPattern)
+ {
+ FcConfigSubstitute(nullptr, matchPattern, FcMatchPattern);
+ FcDefaultSubstitute(matchPattern);
+
+ FcCharSet* characterSet = nullptr;
+ MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+ // Decrease the reference counter of the character set as it's not stored.
+ FcCharSetDestroy(characterSet);
+
+ // Destroys the pattern created.
+ FcPatternDestroy(matchPattern);
+ }
+
+ // Create again the character sets as they are not valid after FcInitReinitialize()
+
+ for(const auto& description : mDefaultFonts)
+ {
+ mDefaultFontCharacterSets.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ }
+
+ for(const auto& description : mFontDescriptionCache)
+ {
+ mCharacterSetCache.PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ }
+
+ for(auto& item : mFallbackCache)
+ {
+ if(nullptr != item.fallbackFonts)
+ {
+ if(nullptr == item.characterSets)
+ {
+ item.characterSets = new CharacterSetList;
+ }
+
+ for(const auto& description : *(item.fallbackFonts))
+ {
+ item.characterSets->PushBack(FcCharSetCopy(CreateCharacterSetFromDescription(description)));
+ }
+ }
+ }
+
+ mDefaultFontDescriptionCached = true;
+ }
+
+ fontDescription.path = mDefaultFontDescription.path;
+ fontDescription.family = mDefaultFontDescription.family;
+ fontDescription.width = mDefaultFontDescription.width;
+ fontDescription.weight = mDefaultFontDescription.weight;
+ fontDescription.slant = mDefaultFontDescription.slant;
+
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+}
+
+void FontClient::Plugin::GetSystemFonts(FontList& systemFonts)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+
+ if(mSystemFonts.empty())
+ {
+ InitSystemFonts();
+ }
+
+ systemFonts = mSystemFonts;
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of system fonts : [%d]\n", mSystemFonts.size());
+}
+
+void FontClient::Plugin::GetDescription(FontId id,
+ FontDescription& fontDescription) const
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", id);
+ const FontId index = id - 1u;
+
+ if((id > 0u) && (index < mFontIdCache.Count()))
+ {
+ const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+ switch(fontIdCacheItem.type)
+ {
+ case FontDescription::FACE_FONT:
+ {
+ for(const auto& item : mFontDescriptionSizeCache)
+ {
+ if(item.fontId == fontIdCacheItem.id)
+ {
+ fontDescription = *(mFontDescriptionCache.begin() + item.validatedFontId - 1u);
+
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ return;
+ }
+ }
+ break;
+ }
+ case FontDescription::BITMAP_FONT:
+ {
+ fontDescription.type = FontDescription::BITMAP_FONT;
+ fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
+ break;
+ }
+ default:
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
+ fontDescription.type = FontDescription::INVALID;
+ fontDescription.family.clear();
+ }
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " No description found for the font ID %d\n", id);
+}
+
+PointSize26Dot6 FontClient::Plugin::GetPointSize(FontId id)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", id);
+
+ PointSize26Dot6 pointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(id);
+ if(fontCacheItem != nullptr)
+ {
+ pointSize = fontCacheItem->GetPointSize();
+ }
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " point size : %d\n", pointSize);
+
+ return pointSize;
+}
+
+bool FontClient::Plugin::IsCharacterSupportedByFont(FontId fontId, Character character)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " character : %p\n", character);
+
+ bool isSupported = false;
+ auto fontCacheItem = const_cast<FontCacheItemInterface*>(GetCachedFontItem(fontId));
+ if(fontCacheItem != nullptr)
+ {
+ isSupported = fontCacheItem->IsCharacterSupported(character); // May cache
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false"));
+ return isSupported;
+}
+
+const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) const
+{
+ const FontId index = id - 1u;
+ if((id > 0u) && (index < mFontIdCache.Count()))
+ {
+ const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+ switch(fontIdCacheItem.type)
+ {
+ case FontDescription::FACE_FONT:
+ {
+ return &mFontFaceCache[fontIdCacheItem.id];
+ }
+ case FontDescription::BITMAP_FONT:
+ {
+ return &mBitmapFontCache[fontIdCacheItem.id];
+ }
+ default:
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
+ }
+ }
+ }
+ return nullptr;
+}
+
+FontId FontClient::Plugin::FindFontForCharacter(const FontList& fontList,
+ const CharacterSetList& characterSetList,
+ Character character,
+ PointSize26Dot6 requestedPointSize,
+ bool preferColor)
+{
+ DALI_ASSERT_DEBUG((fontList.size() == characterSetList.Count()) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets.");
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " character : %p\n", character);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " preferColor : %s\n", (preferColor ? "true" : "false"));
+
+ FontId fontId = 0u;
+ bool foundColor = false;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of fonts : %d\n", fontList.size());
+
+ // Traverse the list of fonts.
+ // Check for each font if supports the character.
+ for(unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index)
+ {
+ const FontDescription& description = fontList[index];
+ const FcCharSet* const characterSet = characterSetList[index];
+
+ FONT_LOG_DESCRIPTION(description, "");
+
+ bool foundInRanges = false;
+ if(nullptr != characterSet)
+ {
+ foundInRanges = FcCharSetHasChar(characterSet, character);
+ }
+
+ if(foundInRanges)
+ {
+ fontId = GetFontId(description, requestedPointSize, 0u);
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " font id : %d\n", fontId);
+
+ if(preferColor)
+ {
+ if((fontId > 0) &&
+ (fontId - 1u < mFontIdCache.Count()))
+ {
+ const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+
+ foundColor = item.mHasColorTables;
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " foundColor : %s\n", (foundColor ? "true" : "false"));
+ }
+
+ // Keep going unless we prefer a different (color) font.
+ if(!preferColor || foundColor)
+ {
+ break;
+ }
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
+ return fontId;
+}
+
+FontId FontClient::Plugin::FindDefaultFont(Character charcode,
+ PointSize26Dot6 requestedPointSize,
+ bool preferColor)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor);
+
+ FontId fontId(0);
+
+ // Create the list of default fonts if it has not been created.
+ if(mDefaultFonts.empty())
+ {
+ FontDescription fontDescription;
+ fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
+ fontDescription.width = DefaultFontWidth();
+ fontDescription.weight = DefaultFontWeight();
+ fontDescription.slant = DefaultFontSlant();
+
+ SetFontList(fontDescription, mDefaultFonts, mDefaultFontCharacterSets);
+ }
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of default fonts : %d\n", mDefaultFonts.size());
+
+ // Traverse the list of default fonts.
+ // Check for each default font if supports the character.
+ fontId = FindFontForCharacter(mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor);
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
+ return fontId;
+}
+
+FontId FontClient::Plugin::FindFallbackFont(Character charcode,
+ const FontDescription& preferredFontDescription,
+ PointSize26Dot6 requestedPointSize,
+ bool preferColor)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_REQUEST(charcode, requestedPointSize, preferColor);
+
+ // The font id to be returned.
+ FontId fontId = 0u;
+
+ FontDescription fontDescription;
+
+ // Fill the font description with the preferred font description and complete with the defaults.
+ fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
+ fontDescription.weight = ((FontWeight::NONE == preferredFontDescription.weight) ? DefaultFontWeight() : preferredFontDescription.weight);
+ fontDescription.width = ((FontWidth::NONE == preferredFontDescription.width) ? DefaultFontWidth() : preferredFontDescription.width);
+ fontDescription.slant = ((FontSlant::NONE == preferredFontDescription.slant) ? DefaultFontSlant() : preferredFontDescription.slant);
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " preferredFontDescription --> fontDescription\n");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str());
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight]);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width]);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant]);
+
+ // Check first if the font's description has been queried before.
+ FontList* fontList = nullptr;
+ CharacterSetList* characterSetList = nullptr;
+
+ if(!FindFallbackFontList(fontDescription, fontList, characterSetList))
+ {
+ fontList = new FontList;
+ characterSetList = new CharacterSetList;
+
+ SetFontList(fontDescription, *fontList, *characterSetList);
+#ifdef __APPLE__
+ FontDescription appleColorEmoji;
+ appleColorEmoji.family = "Apple Color Emoji";
+ appleColorEmoji.width = fontDescription.width;
+ appleColorEmoji.weight = fontDescription.weight;
+ appleColorEmoji.slant = fontDescription.slant;
+ FontList emojiFontList;
+ CharacterSetList emojiCharSetList;
+ SetFontList(appleColorEmoji, emojiFontList, emojiCharSetList);
+
+ std::move(fontList->begin(), fontList->end(), std::back_inserter(emojiFontList));
+ emojiCharSetList.Insert(emojiCharSetList.End(), characterSetList->Begin(), characterSetList->End());
+ *fontList = std::move(emojiFontList);
+ *characterSetList = std::move(emojiCharSetList);
+#endif
+
+ // Add the font-list to the cache.
+ mFallbackCache.push_back(std::move(FallbackCacheItem(std::move(fontDescription), fontList, characterSetList)));
+ }
+
+ if(fontList && characterSetList)
+ {
+ fontId = FindFontForCharacter(*fontList, *characterSetList, charcode, requestedPointSize, preferColor);
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
+ return fontId;
+}
+
+FontId FontClient::Plugin::GetFontId(const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex faceIndex,
+ bool cacheDescription)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+
+ FontId id = 0u;
+
+ if(nullptr != mFreeTypeLibrary)
+ {
+ FontId foundId = 0u;
+ if(FindFont(path, requestedPointSize, faceIndex, foundId))
+ {
+ id = foundId;
+ }
+ else
+ {
+ id = CreateFont(path, requestedPointSize, faceIndex, cacheDescription);
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", id);
+ return id;
+}
+
+FontId FontClient::Plugin::GetFontId(const FontDescription& fontDescription,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex faceIndex)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+
+ // This method uses three vectors which caches:
+ // * The bitmap font cache
+ // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
+ // * The path to font file names.
+ // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
+
+ // 1) Checks if the font description matches with a previously loaded bitmap font.
+ // Returns if a font is found.
+ // 2) Checks in the cache if the font's description has been validated before.
+ // If it was it gets an index to the vector with paths to font file names. Otherwise,
+ // retrieves using font config a path to a font file name which matches with the
+ // font's description. The path is stored in the cache.
+ //
+ // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
+ // font file names' exists. If exists, it gets the font id. If it doesn't it calls
+ // the GetFontId() method with the path to the font file name and the point size to
+ // get the font id.
+
+ // The font id to be returned.
+ FontId fontId = 0u;
+
+ // Check first if the font description matches with a previously loaded bitmap font.
+ if(FindBitmapFont(fontDescription.family, fontId))
+ {
+ return fontId;
+ }
+
+ // Check if the font's description have been validated before.
+ FontDescriptionId validatedFontId = 0u;
+
+ if(!FindValidatedFont(fontDescription,
+ validatedFontId))
+ {
+ // Use font config to validate the font's description.
+ ValidateFont(fontDescription,
+ validatedFontId);
+ }
+
+ FontId fontFaceId = 0u;
+ // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
+ if(!FindFont(validatedFontId, requestedPointSize, fontFaceId))
+ {
+ // Retrieve the font file name path.
+ const FontDescription& description = *(mFontDescriptionCache.begin() + validatedFontId - 1u);
+
+ // Retrieve the font id. Do not cache the description as it has been already cached.
+ fontId = GetFontId(description.path,
+ requestedPointSize,
+ faceIndex,
+ false);
+
+ fontFaceId = mFontIdCache[fontId - 1u].id;
+ mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(mCharacterSetCache[validatedFontId - 1u]);
+
+ // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
+ mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
+ requestedPointSize,
+ fontFaceId));
+ }
+ else
+ {
+ fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
+ return fontId;
+}
+
+FontId FontClient::Plugin::GetFontId(const BitmapFont& bitmapFont)
+{
+ for(const auto& item : mBitmapFontCache)
+ {
+ if(bitmapFont.name == item.font.name)
+ {
+ return item.id + 1u;
+ }
+ }
+
+ BitmapFontCacheItem bitmapFontCacheItem(bitmapFont, mFontIdCache.Count());
+
+ FontIdCacheItem fontIdCacheItem;
+ fontIdCacheItem.type = FontDescription::BITMAP_FONT;
+ fontIdCacheItem.id = mBitmapFontCache.size();
+
+ mBitmapFontCache.push_back(std::move(bitmapFontCacheItem));
+ mFontIdCache.PushBack(fontIdCacheItem);
+
+ return bitmapFontCacheItem.id + 1u;
+}
+
+void FontClient::Plugin::ValidateFont(const FontDescription& fontDescription,
+ FontDescriptionId& validatedFontId)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription);
+
+ FontDescription description;
+
+ FcCharSet* characterSet = nullptr;
+ bool matched = MatchFontDescriptionToPattern(fontFamilyPattern, description, &characterSet);
+ FcPatternDestroy(fontFamilyPattern);
+
+ if(matched && (nullptr != characterSet))
+ {
+ // Add the path to the cache.
+ description.type = FontDescription::FACE_FONT;
+ mFontDescriptionCache.push_back(description);
+
+ // Set the index to the vector of paths to font file names.
+ validatedFontId = mFontDescriptionCache.size();
+
+ FONT_LOG_DESCRIPTION(description, "matched");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId);
+
+ // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
+ mCharacterSetCache.PushBack(characterSet);
+
+ // Cache the index and the matched font's description.
+ FontDescriptionCacheItem item(description,
+ validatedFontId);
+
+ mValidatedFontCache.push_back(std::move(item));
+
+ if((fontDescription.family != description.family) ||
+ (fontDescription.width != description.width) ||
+ (fontDescription.weight != description.weight) ||
+ (fontDescription.slant != description.slant))
+ {
+ // Cache the given font's description if it's different than the matched.
+ FontDescriptionCacheItem item(fontDescription,
+ validatedFontId);
+
+ mValidatedFontCache.push_back(std::move(item));
+ }
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font validation failed for font [%s]\n", fontDescription.family.c_str());
+ }
+}
+
+void FontClient::Plugin::GetFontMetrics(FontId fontId,
+ FontMetrics& metrics)
+{
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
+ {
+ fontCacheItem->GetFontMetrics(metrics, mDpiVertical);
+ }
+}
+
+GlyphIndex FontClient::Plugin::GetGlyphIndex(FontId fontId,
+ Character charcode)
+{
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
+ {
+ return fontCacheItem->GetGlyphIndex(charcode);
+ }
+
+ return 0u;
+}
+
+bool FontClient::Plugin::GetGlyphMetrics(GlyphInfo* array,
+ uint32_t size,
+ GlyphType type,
+ bool horizontal)
+{
+ if(VECTOR_GLYPH == type)
+ {
+ return GetVectorMetrics(array, size, horizontal);
+ }
+
+ return GetBitmapMetrics(array, size, horizontal);
+}
+
+bool FontClient::Plugin::GetBitmapMetrics(GlyphInfo* array,
+ uint32_t size,
+ bool horizontal)
+{
+ bool success(false);
+
+ for(unsigned int i = 0; i < size; ++i)
+ {
+ GlyphInfo& glyph = array[i];
+
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(glyph.fontId);
+ if(fontCacheItem != nullptr)
+ {
+ success = fontCacheItem->GetGlyphMetrics(glyph, mDpiVertical, horizontal);
+ }
+ // Check if it's an embedded image.
+ else if((0u == glyph.fontId) && (0u != glyph.index) && (glyph.index <= mEmbeddedItemCache.Count()))
+ {
+ mEmbeddedItemCache[glyph.index - 1u].GetGlyphMetrics(glyph);
+ success = true;
+ }
+ }
+
+ return success;
+}
+
+bool FontClient::Plugin::GetVectorMetrics(GlyphInfo* array,
+ uint32_t size,
+ bool horizontal)
+{
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ bool success(true);
+
+ for(unsigned int i = 0u; i < size; ++i)
+ {
+ FontId fontId = array[i].fontId;
+
+ if((fontId > 0u) &&
+ (fontId - 1u) < mFontIdCache.Count())
+ {
+ FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+
+ if(!font.mVectorFontId)
+ {
+ font.mVectorFontId = mVectorFontCache->GetFontId(font.mPath);
+ }
+
+ mVectorFontCache->GetGlyphMetrics(font.mVectorFontId, array[i]);
+
+ // Vector metrics are in EMs, convert to pixels
+ const float scale = (static_cast<float>(font.mRequestedPointSize) * FROM_266) * static_cast<float>(mDpiVertical) / POINTS_PER_INCH;
+ array[i].width *= scale;
+ array[i].height *= scale;
+ array[i].xBearing *= scale;
+ array[i].yBearing *= scale;
+ array[i].advance *= scale;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+
+ return success;
+#else
+ return false;
+#endif
+}
+
+void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth)
+{
+ data.isColorBitmap = false;
+ data.isColorEmoji = false;
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
+ {
+ fontCacheItem->CreateBitmap(glyphIndex, data, outlineWidth, isItalicRequired, isBoldRequired);
+ }
+ else if((0u != glyphIndex) && (glyphIndex <= mEmbeddedItemCache.Count()))
+ {
+ // It's an embedded item.
+ mEmbeddedItemCache[glyphIndex - 1u].CreateBitmap(mPixelBufferCache, data);
+ }
+}
+
+PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth)
+{
+ TextAbstraction::FontClient::GlyphBufferData data;
+
+ CreateBitmap(fontId, glyphIndex, false, false, data, outlineWidth);
+
+ return PixelData::New(data.buffer,
+ data.width * data.height * Pixel::GetBytesPerPixel(data.format),
+ data.width,
+ data.height,
+ data.format,
+ PixelData::DELETE_ARRAY);
+}
+
+void FontClient::Plugin::CreateVectorBlob(FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight)
+{
+ blob = nullptr;
+ blobLength = 0;
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+ if((fontId > 0u) &&
+ (fontId - 1u < mFontIdCache.Count()))
+ {
+ const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
+ FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
+
+ if(!font.mVectorFontId)
+ {
+ font.mVectorFontId = mVectorFontCache->GetFontId(font.mPath);
+ }
+
+ mVectorFontCache->GetVectorBlob(font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight);
+ }
+#endif
+}
+
+const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph(PointSize26Dot6 requestedPointSize)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize %d.\n", requestedPointSize);
+
+ // First look into the cache if there is an ellipsis glyph for the requested point size.
+ for(const auto& item : mEllipsisCache)
+ {
+ if(item.requestedPointSize == requestedPointSize)
+ {
+ // Use the glyph in the cache.
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
+ return item.glyph;
+ }
+ }
+
+ // No glyph has been found. Create one.
+ mEllipsisCache.PushBack(EllipsisItem());
+ EllipsisItem& item = *(mEllipsisCache.End() - 1u);
+
+ item.requestedPointSize = requestedPointSize;
+
+ // Find a font for the ellipsis glyph.
+ item.glyph.fontId = FindDefaultFont(ELLIPSIS_CHARACTER,
+ requestedPointSize,
+ false);
+
+ // Set the character index to access the glyph inside the font.
+ item.glyph.index = FT_Get_Char_Index(mFontFaceCache[mFontIdCache[item.glyph.fontId - 1u].id].mFreeTypeFace,
+ ELLIPSIS_CHARACTER);
+
+ GetBitmapMetrics(&item.glyph, 1u, true);
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " glyph id %d found in the cache.\n", item.glyph.index);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font %d.\n", item.glyph.fontId);
+ return item.glyph;
+}
+
+bool FontClient::Plugin::IsColorGlyph(FontId fontId, GlyphIndex glyphIndex)
+{
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ return fontCacheItem && fontCacheItem->IsColorGlyph(glyphIndex);
+}
+
+FT_FaceRec_* FontClient::Plugin::GetFreetypeFace(FontId fontId)
+{
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
+ {
+ return fontCacheItem->GetTypeface();
+ }
+ return nullptr;
+}
+
+FontDescription::Type FontClient::Plugin::GetFontType(FontId fontId)
+{
+ const FontId index = fontId - 1u;
+ if((fontId > 0u) &&
+ (index < mFontIdCache.Count()))
+ {
+ return mFontIdCache[index].type;
+ }
+ return FontDescription::INVALID;
+}
+
+bool FontClient::Plugin::AddCustomFontDirectory(const FontPath& path)
+{
+ // nullptr as first parameter means the current configuration is used.
+ return FcConfigAppFontAddDir(nullptr, reinterpret_cast<const FcChar8*>(path.c_str()));
+}
+
+GlyphIndex FontClient::Plugin::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
+{
+ EmbeddedItem embeddedItem;
+
+ embeddedItem.pixelBufferId = 0u;
+ embeddedItem.width = description.width;
+ embeddedItem.height = description.height;
+
+ pixelFormat = Pixel::A8;
+
+ if(!description.url.empty())
+ {
+ // Check if the url is in the cache.
+ PixelBufferId index = 0u;
+
+ for(const auto& cacheItem : mPixelBufferCache)
+ {
+ ++index;
+ if(cacheItem.url == description.url)
+ {
+ // The url is in the pixel buffer cache.
+ // Set the index +1 to the vector.
+ embeddedItem.pixelBufferId = index;
+ break;
+ }
+ }
+
+ Devel::PixelBuffer pixelBuffer;
+ if(0u == embeddedItem.pixelBufferId)
+ {
+ // The pixel buffer is not in the cache. Create one and cache it.
+
+ // Load the image from the url.
+ pixelBuffer = LoadImageFromFile(description.url);
+
+ // Create the cache item.
+ PixelBufferCacheItem pixelBufferCacheItem;
+ pixelBufferCacheItem.pixelBuffer = pixelBuffer;
+ pixelBufferCacheItem.url = description.url;
+
+ // Store the cache item in the cache.
+ mPixelBufferCache.push_back(std::move(pixelBufferCacheItem));
+
+ // Set the pixel buffer id to the embedded item.
+ embeddedItem.pixelBufferId = mPixelBufferCache.size();
+ }
+ else
+ {
+ // Retrieve the pixel buffer from the cache to set the pixel format.
+ pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId - 1u].pixelBuffer;
+ }
+
+ if(pixelBuffer)
+ {
+ // Set the size of the embedded item if it has not been set.
+ if(0u == embeddedItem.width)
+ {
+ embeddedItem.width = static_cast<unsigned int>(pixelBuffer.GetWidth());
+ }
+
+ if(0u == embeddedItem.height)
+ {
+ embeddedItem.height = static_cast<unsigned int>(pixelBuffer.GetHeight());
+ }
+
+ // Set the pixel format.
+ pixelFormat = pixelBuffer.GetPixelFormat();
+ }
+ }
+
+ // Find if the same embeddedItem has already been created.
+ unsigned int index = 0u;
+ for(const auto& item : mEmbeddedItemCache)
+ {
+ ++index;
+ if((item.pixelBufferId == embeddedItem.pixelBufferId) &&
+ (item.width == embeddedItem.width) &&
+ (item.height == embeddedItem.height))
+ {
+ return index;
+ }
+ }
+
+ // Cache the embedded item.
+ mEmbeddedItemCache.PushBack(embeddedItem);
+
+ return mEmbeddedItemCache.Count();
+}
+
+void FontClient::Plugin::EnableAtlasLimitation(bool enabled)
+{
+ mIsAtlasLimitationEnabled = enabled;
+}
+
+bool FontClient::Plugin::IsAtlasLimitationEnabled() const
+{
+ return mIsAtlasLimitationEnabled;
+}
+
+Size FontClient::Plugin::GetMaximumTextAtlasSize() const
+{
+ return TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE;
+}
+
+Size FontClient::Plugin::GetDefaultTextAtlasSize() const
+{
+ return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE;
+}
+
+Size FontClient::Plugin::GetCurrentMaximumBlockSizeFitInAtlas() const
+{
+ return mCurrentMaximumBlockSizeFitInAtlas;
+}
+
+bool FontClient::Plugin::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas)
+{
+ bool isChanged = false;
+ const Size& maxTextAtlasSize = TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE;
+ const uint16_t& padding = TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK;
+
+ if(currentMaximumBlockSizeFitInAtlas.width <= maxTextAtlasSize.width - padding && currentMaximumBlockSizeFitInAtlas.height <= maxTextAtlasSize.height - padding)
+ {
+ mCurrentMaximumBlockSizeFitInAtlas = currentMaximumBlockSizeFitInAtlas;
+ isChanged = true;
+ }
+
+ return isChanged;
+}
+
+uint32_t FontClient::Plugin::GetNumberOfPointsPerOneUnitOfPointSize() const
+{
+ return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ ;
+}
+
+void FontClient::Plugin::InitSystemFonts()
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+
+ FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
+
+ if(fontSet)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " number of system fonts : %d\n", fontSet->nfont);
+
+ // Reserve some space to avoid reallocations.
+ mSystemFonts.reserve(fontSet->nfont);
+
+ for(int i = 0u; i < fontSet->nfont; ++i)
+ {
+ FcPattern* fontPattern = fontSet->fonts[i];
+
+ FontPath path;
+
+ // Skip fonts with no path
+ if(GetFcString(fontPattern, FC_FILE, path))
+ {
+ mSystemFonts.push_back(FontDescription());
+ FontDescription& fontDescription = mSystemFonts.back();
+
+ fontDescription.path = std::move(path);
+
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
+ GetFcString(fontPattern, FC_FAMILY, fontDescription.family);
+ GetFcInt(fontPattern, FC_WIDTH, width);
+ GetFcInt(fontPattern, FC_WEIGHT, weight);
+ GetFcInt(fontPattern, FC_SLANT, slant);
+ fontDescription.width = IntToWidthType(width);
+ fontDescription.weight = IntToWeightType(weight);
+ fontDescription.slant = IntToSlantType(slant);
+
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ }
+ }
+
+ // Destroys the font set created.
+ FcFontSetDestroy(fontSet);
+ }
+}
+
+bool FontClient::Plugin::MatchFontDescriptionToPattern(FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+
+ FcResult result = FcResultMatch;
+ FcPattern* match = FcFontMatch(nullptr /* use default configure */, pattern, &result); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ const bool matched = nullptr != match;
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " pattern matched : %s\n", (matched ? "true" : "false"));
+
+ if(matched)
+ {
+ int width = 0;
+ int weight = 0;
+ int slant = 0;
+ GetFcString(match, FC_FILE, fontDescription.path);
+ GetFcString(match, FC_FAMILY, fontDescription.family);
+ GetFcInt(match, FC_WIDTH, width);
+ GetFcInt(match, FC_WEIGHT, weight);
+ GetFcInt(match, FC_SLANT, slant);
+ fontDescription.width = IntToWidthType(width);
+ fontDescription.weight = IntToWeightType(weight);
+ fontDescription.slant = IntToSlantType(slant);
+
+ // Retrieve the character set and increase the reference counter.
+ FcPatternGetCharSet(match, FC_CHARSET, 0u, characterSet);
+ *characterSet = FcCharSetCopy(*characterSet);
+
+ // destroyed the matched pattern
+ FcPatternDestroy(match);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ }
+ return matched;
+}
+
+_FcFontSet* FontClient::Plugin::GetFcFontSet() const
+{
+ FcFontSet* fontset = nullptr;
+
+ // create a new pattern.
+ // a pattern holds a set of names, each name refers to a property of the font
+ FcPattern* pattern = FcPatternCreate();
+
+ if(nullptr != pattern)
+ {
+ // create an object set used to define which properties are to be returned in the patterns from FcFontList.
+ FcObjectSet* objectSet = FcObjectSetCreate();
+
+ if(nullptr != objectSet)
+ {
+ // build an object set from a list of property names
+ FcObjectSetAdd(objectSet, FC_FILE);
+ FcObjectSetAdd(objectSet, FC_FAMILY);
+ FcObjectSetAdd(objectSet, FC_WIDTH);
+ FcObjectSetAdd(objectSet, FC_WEIGHT);
+ FcObjectSetAdd(objectSet, FC_SLANT);
+
+ // get a list of fonts
+ // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
+ fontset = FcFontList(nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
+
+ // clear up the object set
+ FcObjectSetDestroy(objectSet);
+ }
+
+ // clear up the pattern
+ FcPatternDestroy(pattern);
+ }
+
+ return fontset;
+}
+
+bool FontClient::Plugin::GetFcString(const FcPattern* const pattern,
+ const char* const n,
+ std::string& string)
+{
+ FcChar8* file = nullptr;
+ const FcResult retVal = FcPatternGetString(pattern, n, 0u, &file);
+
+ if(FcResultMatch == retVal)
+ {
+ // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
+ string.assign(reinterpret_cast<const char*>(file));
+
+ return true;
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::GetFcInt(const _FcPattern* const pattern, const char* const n, int& intVal)
+{
+ const FcResult retVal = FcPatternGetInteger(pattern, n, 0u, &intVal);
+
+ if(FcResultMatch == retVal)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+FontId FontClient::Plugin::CreateFont(const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex faceIndex,
+ bool cacheDescription)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+
+ FontId id = 0u;
+
+ // Create & cache new font face
+ FT_Face ftFace;
+ int error = FT_New_Face(mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace);
+
+ if(FT_Err_Ok == error)
+ {
+ // Check if a font is scalable.
+ const bool isScalable = (0 != (ftFace->face_flags & FT_FACE_FLAG_SCALABLE));
+ const bool hasFixedSizedBitmaps = (0 != (ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES)) && (0 != ftFace->num_fixed_sizes);
+ const bool hasColorTables = (0 != (ftFace->face_flags & FT_FACE_FLAG_COLOR));
+ FontId fontFaceId = 0u;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " isScalable : [%s]\n", (isScalable ? "true" : "false"));
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " hasFixedSizedBitmaps : [%s]\n", (hasFixedSizedBitmaps ? "true" : "false"));
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " hasColorTables : [%s]\n", (hasColorTables ? "true" : "false"));
+
+ // Check to see if the font contains fixed sizes?
+ if(!isScalable && hasFixedSizedBitmaps)
+ {
+ PointSize26Dot6 actualPointSize = 0u;
+ int fixedSizeIndex = 0;
+ for(; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex)
+ {
+ const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " size index : %d, size : %d\n", fixedSizeIndex, fixedSize);
+
+ if(fixedSize >= requestedPointSize)
+ {
+ actualPointSize = fixedSize;
+ break;
+ }
+ }
+
+ if(0u == actualPointSize)
+ {
+ // The requested point size is bigger than the bigest fixed size.
+ fixedSizeIndex = ftFace->num_fixed_sizes - 1;
+ actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize);
+
+ // Tell Freetype to use this size
+ error = FT_Select_Size(ftFace, fixedSizeIndex);
+ if(FT_Err_Ok != error)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error);
+ }
+ else
+ {
+ const float fixedWidth = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].width);
+ const float fixedHeight = static_cast<float>(ftFace->available_sizes[fixedSizeIndex].height);
+
+ // Indicate that the font is a fixed sized bitmap
+ FontMetrics metrics(fixedHeight, // The ascender in pixels.
+ 0.0f,
+ fixedHeight, // The height in pixels.
+ 0.0f,
+ 0.0f);
+
+ // Create the FreeType font face item to cache.
+ FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
+
+ // Set the index to the font's id cache.
+ fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+ // Create the font id item to cache.
+ FontIdCacheItem fontIdCacheItem;
+ fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+ // Set the index to the FreeType font face cache.
+ fontIdCacheItem.id = mFontFaceCache.size();
+ fontFaceId = fontIdCacheItem.id + 1u;
+
+ // Cache the items.
+ mFontFaceCache.push_back(fontFaceCacheItem);
+ mFontIdCache.PushBack(fontIdCacheItem);
+
+ // Set the font id to be returned.
+ id = mFontIdCache.Count();
+ }
+ }
+ else
+ {
+ if(mIsAtlasLimitationEnabled)
+ {
+ //There is limitation on block size to fit in predefined atlas size.
+ //If the block size cannot fit into atlas size, then the system cannot draw block.
+ //This is workaround to avoid issue in advance
+ //Decrementing point-size until arriving to maximum allowed block size.
+ auto requestedPointSizeBackup = requestedPointSize;
+ const Size& maxSizeFitInAtlas = GetCurrentMaximumBlockSizeFitInAtlas();
+ error = SearchOnProperPointSize(ftFace, mDpiHorizontal, mDpiVertical, maxSizeFitInAtlas, requestedPointSize);
+
+ if(requestedPointSize != requestedPointSizeBackup)
+ {
+ DALI_LOG_WARNING(" The requested-point-size : %d, is reduced to point-size : %d\n", requestedPointSizeBackup, requestedPointSize);
+ }
+ }
+ else
+ {
+ error = FT_Set_Char_Size(ftFace,
+ 0,
+ requestedPointSize,
+ mDpiHorizontal,
+ mDpiVertical);
+ }
+
+ if(FT_Err_Ok == error)
+ {
+ FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
+
+ FontMetrics metrics(static_cast<float>(ftMetrics.ascender) * FROM_266,
+ static_cast<float>(ftMetrics.descender) * FROM_266,
+ static_cast<float>(ftMetrics.height) * FROM_266,
+ static_cast<float>(ftFace->underline_position) * FROM_266,
+ static_cast<float>(ftFace->underline_thickness) * FROM_266);
+
+ // Create the FreeType font face item to cache.
+ FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics);
+
+ // Set the index to the font's id cache.
+ fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+ // Create the font id item to cache.
+ FontIdCacheItem fontIdCacheItem;
+ fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+ // Set the index to the FreeType font face cache.
+ fontIdCacheItem.id = mFontFaceCache.size();
+ fontFaceId = fontIdCacheItem.id + 1u;
+
+ // Cache the items.
+ mFontFaceCache.push_back(fontFaceCacheItem);
+ mFontIdCache.PushBack(fontIdCacheItem);
+
+ // Set the font id to be returned.
+ id = mFontIdCache.Count();
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize);
+ }
+ }
+
+ if(0u != fontFaceId)
+ {
+ if(cacheDescription)
+ {
+ CacheFontPath(ftFace, fontFaceId, requestedPointSize, path);
+ }
+ }
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " FreeType New_Face error: %d for [%s]\n", error, path.c_str());
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", id);
+ return id;
+}
+
+bool FontClient::Plugin::FindFont(const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex faceIndex,
+ FontId& fontId) const
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " path : [%s]\n", path.c_str());
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fonts in the cache : %d\n", mFontFaceCache.size());
+
+ fontId = 0u;
+ for(const auto& cacheItem : mFontFaceCache)
+ {
+ if(cacheItem.mRequestedPointSize == requestedPointSize &&
+ cacheItem.mFaceIndex == faceIndex &&
+ cacheItem.mPath == path)
+ {
+ fontId = cacheItem.mFontId + 1u;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, id : %d\n", fontId);
+ return true;
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found\n");
+ return false;
+}
+
+bool FontClient::Plugin::FindValidatedFont(const FontDescription& fontDescription,
+ FontDescriptionId& validatedFontId)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of validated fonts in the cache : %d\n", mValidatedFontCache.size());
+
+ validatedFontId = 0u;
+
+ for(const auto& item : mValidatedFontCache)
+ {
+ if(!fontDescription.family.empty() &&
+ (fontDescription.family == item.fontDescription.family) &&
+ (fontDescription.width == item.fontDescription.width) &&
+ (fontDescription.weight == item.fontDescription.weight) &&
+ (fontDescription.slant == item.fontDescription.slant))
+ {
+ validatedFontId = item.index;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font found, id : %d\n", validatedFontId);
+ return true;
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validated font not found\n");
+ return false;
+}
+
+bool FontClient::Plugin::FindFallbackFontList(const FontDescription& fontDescription,
+ FontList*& fontList,
+ CharacterSetList*& characterSetList)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ FONT_LOG_DESCRIPTION(fontDescription, "");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::Verbose, " number of fallback font lists in the cache : %d\n", mFallbackCache.size());
+
+ fontList = nullptr;
+
+ for(const auto& item : mFallbackCache)
+ {
+ if(!fontDescription.family.empty() &&
+ (fontDescription.family == item.fontDescription.family) &&
+ (fontDescription.width == item.fontDescription.width) &&
+ (fontDescription.weight == item.fontDescription.weight) &&
+ (fontDescription.slant == item.fontDescription.slant))
+ {
+ fontList = item.fallbackFonts;
+ characterSetList = item.characterSets;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list found.\n");
+ return true;
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " fallback font list not found.\n");
+ return false;
+}
+
+bool FontClient::Plugin::FindFont(FontDescriptionId validatedFontId,
+ PointSize26Dot6 requestedPointSize,
+ FontId& fontId)
+{
+ DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " validatedFontId : %d\n", validatedFontId);
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
+
+ fontId = 0u;
+
+ for(const auto& item : mFontDescriptionSizeCache)
+ {
+ if((validatedFontId == item.validatedFontId) &&
+ (requestedPointSize == item.requestedPointSize))
+ {
+ fontId = item.fontId;
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font found, id : %d\n", fontId);
+ return true;
+ }
+ }
+
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font not found.\n");
+ return false;
+}
+
+bool FontClient::Plugin::FindBitmapFont(const FontFamily& bitmapFont, FontId& fontId) const
+{
+ fontId = 0u;
+
+ for(const auto& item : mBitmapFontCache)
+ {
+ if(bitmapFont == item.font.name)
+ {
+ fontId = item.id + 1u;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::IsScalable(const FontPath& path)
+{
+ bool isScalable = false;
+
+ FT_Face ftFace;
+ int error = FT_New_Face(mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace);
+ if(FT_Err_Ok != error)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str());
+ }
+ else
+ {
+ isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
+ }
+
+ return isScalable;
+}
+
+bool FontClient::Plugin::IsScalable(const FontDescription& fontDescription)
+{
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcResult result = FcResultMatch;
+
+ // match the pattern
+ FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+ bool isScalable = false;
+
+ if(match)
+ {
+ // Get the path to the font file name.
+ FontPath path;
+ GetFcString(match, FC_FILE, path);
+ isScalable = IsScalable(path);
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str());
+ }
+
+ // Destroys the created patterns.
+ FcPatternDestroy(match);
+ FcPatternDestroy(fontFamilyPattern);
+
+ return isScalable;
+}
+
+void FontClient::Plugin::GetFixedSizes(const FontPath& path, Vector<PointSize26Dot6>& sizes)
+{
+ // Empty the caller container
+ sizes.Clear();
+
+ FT_Face ftFace;
+ int error = FT_New_Face(mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace);
+ if(FT_Err_Ok != error)
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str());
+ }
+
+ // Fetch the number of fixed sizes available
+ if(ftFace->num_fixed_sizes && ftFace->available_sizes)
+ {
+ for(int i = 0; i < ftFace->num_fixed_sizes; ++i)
+ {
+ sizes.PushBack(ftFace->available_sizes[i].size);
+ }
+ }
+}
+
+void FontClient::Plugin::GetFixedSizes(const FontDescription& fontDescription,
+ Vector<PointSize26Dot6>& sizes)
+{
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern(fontDescription); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcResult result = FcResultMatch;
+
+ // match the pattern
+ FcPattern* match = FcFontMatch(nullptr /* use default configure */, fontFamilyPattern, &result); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ if(match)
+ {
+ // Get the path to the font file name.
+ FontPath path;
+ GetFcString(match, FC_FILE, path);
+ GetFixedSizes(path, sizes);
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str());
+ }
+
+ // Destroys the created patterns.
+ FcPatternDestroy(match);
+ FcPatternDestroy(fontFamilyPattern);
+}
+
+bool FontClient::Plugin::HasItalicStyle(FontId fontId) const
+{
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
+ {
+ return fontCacheItem->HasItalicStyle();
+ }
+ return false;
+}
+
+void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path)
+{
+ FontDescription description;
+ description.path = path;
+ description.family = std::move(FontFamily(ftFace->family_name));
+ description.weight = FontWeight::NONE;
+ description.width = FontWidth::NONE;
+ description.slant = FontSlant::NONE;
+
+ // Note FreeType doesn't give too much info to build a proper font style.
+ if(ftFace->style_flags & FT_STYLE_FLAG_ITALIC)
+ {
+ description.slant = FontSlant::ITALIC;
+ }
+ if(ftFace->style_flags & FT_STYLE_FLAG_BOLD)
+ {
+ description.weight = FontWeight::BOLD;
+ }
+
+ FontDescriptionId validatedFontId = 0u;
+ if(!FindValidatedFont(description,
+ validatedFontId))
+ {
+ FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcResult result = FcResultMatch;
+ FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcCharSet* characterSet = nullptr;
+ FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
+
+ const FontId fontFaceId = id - 1u;
+ mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy(characterSet); // Increases the reference counter.
+
+ // Destroys the created patterns.
+ FcPatternDestroy(match);
+ FcPatternDestroy(pattern);
+
+ // Add the path to the cache.
+ description.type = FontDescription::FACE_FONT;
+ mFontDescriptionCache.push_back(description);
+
+ // Set the index to the vector of paths to font file names.
+ validatedFontId = mFontDescriptionCache.size();
+
+ // Increase the reference counter and add the character set to the cache.
+ mCharacterSetCache.PushBack(FcCharSetCopy(characterSet));
+
+ // Cache the index and the font's description.
+ mValidatedFontCache.push_back(std::move(FontDescriptionCacheItem(std::move(description),
+ validatedFontId)));
+
+ // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
+ mFontDescriptionSizeCache.push_back(FontDescriptionSizeCacheItem(validatedFontId,
+ requestedPointSize,
+ fontFaceId));
+ }
+}
+
+void FontClient::Plugin::ClearFallbackCache(std::vector<FallbackCacheItem>& fallbackCache)
+{
+ for(auto& item : fallbackCache)
+ {
+ if(nullptr != item.fallbackFonts)
+ {
+ delete item.fallbackFonts;
+ }
+
+ if(nullptr != item.characterSets)
+ {
+ // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
+ DestroyCharacterSets(*item.characterSets);
+ delete item.characterSets;
+ }
+ }
+}
+
+void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
+{
+ for(auto& item : mFontFaceCache)
+ {
+ FcCharSetDestroy(item.mCharacterSet);
+ item.mCharacterSet = nullptr;
+ }
+}
+
+} // namespace Dali::TextAbstraction::Internal
#include <dali/devel-api/text-abstraction/font-metrics.h>
#include <dali/devel-api/text-abstraction/glyph-info.h>
#include <dali/internal/text/text-abstraction/font-client-impl.h>
+#include <dali/internal/text/text-abstraction/plugin/bitmap-font-cache-item.h>
+#include <dali/internal/text/text-abstraction/plugin/embedded-item.h>
+#include <dali/internal/text/text-abstraction/plugin/font-face-cache-item.h>
+#include <dali/internal/text/text-abstraction/plugin/pixel-buffer-cache-item.h>
#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
#include <third-party/glyphy/vector-font-cache.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
-#include FT_OUTLINE_H
#include FT_STROKER_H
#include FT_SYNTHESIS_H
typedef uint32_t FontDescriptionId;
/**
- * @brief Type used for indices addressing the vector with pixel buffers.
- */
-typedef uint32_t PixelBufferId;
-
-/**
* @brief Vector of character sets.
*/
typedef Vector<_FcCharSet*> CharacterSetList;
FontId fontId; ///< The font identifier.
};
- /**
- * @brief Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
- */
- struct FontFaceCacheItem
- {
- FontFaceCacheItem(FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex face,
- const FontMetrics& metrics);
-
- FontFaceCacheItem(FT_Face ftFace,
- const FontPath& path,
- PointSize26Dot6 requestedPointSize,
- FaceIndex face,
- const FontMetrics& metrics,
- int fixedSizeIndex,
- float fixedWidth,
- float fixedHeight,
- bool hasColorTables);
-
- FT_Face mFreeTypeFace; ///< The FreeType face.
- FontPath mPath; ///< The path to the font file name.
- PointSize26Dot6 mRequestedPointSize; ///< The font point size.
- FaceIndex mFaceIndex; ///< The face index.
- FontMetrics mMetrics; ///< The font metrics.
- _FcCharSet* mCharacterSet; ///< Pointer with the range of characters.
- int mFixedSizeIndex; ///< Index to the fixed size table for the requested size.
- float mFixedWidthPixels; ///< The height in pixels (fixed size bitmaps only)
- float mFixedHeightPixels; ///< The height in pixels (fixed size bitmaps only)
- unsigned int mVectorFontId; ///< The ID of the equivalent vector-based font
- FontId mFontId; ///< Index to the vector with the cache of font's ids.
- bool mIsFixedSizeBitmap : 1; ///< Whether the font has fixed size bitmaps.
- bool mHasColorTables : 1; ///< Whether the font has color tables.
- };
-
struct EllipsisItem
{
PointSize26Dot6 requestedPointSize;
};
/**
- * @brief Caches pixel buffers.
- */
- struct PixelBufferCacheItem
- {
- Devel::PixelBuffer pixelBuffer; ///< The pixel buffer loaded from the url.
- std::string url; ///< The url.
- };
-
- /**
- * @brief Caches embedded items.
- */
- struct EmbeddedItem
- {
- PixelBufferId pixelBufferId; ///< Index to the vector of pixel buffers
- unsigned int width; ///< The desired width.
- unsigned int height; ///< The desired height.
- };
-
- /**
- * @brief Stores a bitmap font and its pixel buffers per glyph.
- */
- struct BitmapFontCacheItem
- {
- BitmapFont font; ///< The bitmap font.
- std::vector<Devel::PixelBuffer> pixelBuffers; ///< The pixel buffers of the glyphs.
- FontId id; ///< Index to the vector with the cache of font's ids.
- };
-
- /**
* Constructor.
*
* Initializes the FreeType library.
bool IsCharacterSupportedByFont(FontId fontId, Character character);
/**
+ * Get the cached font item for the given font
+ * @param[in] id The font id to search for
+ * @return the matching cached font item
+ */
+ const FontCacheItemInterface* GetCachedFontItem(FontId id) const;
+
+ /**
* @brief Finds within the @p fontList a font which support the @p carcode.
*
* @param[in] fontList A list of font paths, family, width, weight and slant.
bool MatchFontDescriptionToPattern(_FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, _FcCharSet** characterSet);
/**
- * @brief Creates a font family pattern used to match fonts.
- *
- * @note Need to call FcPatternDestroy to free the resources.
- *
- * @param[in] fontDescription The font to cache.
- *
- * @return The pattern.
- */
- _FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription) const;
-
- /**
* @brief Retrieves the fonts present in the platform.
*
* @note Need to call FcFontSetDestroy to free the allocated resources.
bool cacheDescription);
/**
- * @brief Copy the color bitmap given in @p srcBuffer to @p data.
- *
- * @param[out] data The bitmap data.
- * @param[in] srcWidth The width of the bitmap.
- * @param[in] srcHeight The height of the bitmap.
- * @param[in] srcBuffer The buffer of the bitmap.
- */
- void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer);
-
- /**
- * @brief Copy the FreeType bitmap to the given buffer.
- *
- * @param[out] data The bitmap data.
- * @param[in] srcBitmap The FreeType bitmap.
- * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
- */
- void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired);
-
- /**
* @brief Finds in the cache if there is a triplet with the path to the font file name, the font point size and the face index.
* If there is one , if writes the font identifier in the param @p fontId.
*
void CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path);
/**
- * @brief Creates a character set from a given font's @p description.
- *
- * @note Need to call FcCharSetDestroy to free the resources.
- *
- * @param[in] description The font's description.
- *
- * @return A character set.
- */
- _FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description);
-
- /**
* @brief Free the resources allocated in the fallback cache.
*
* @param[in] fallbackCache The fallback cache.
void ClearCharacterSetFromFontFaceCache();
private:
- // Declared private and left undefined to avoid copies.
- Plugin(const Plugin&);
- // Declared private and left undefined to avoid copies.
- Plugin& operator=(const Plugin&);
+ Plugin(const Plugin&) = delete;
+ Plugin& operator=(const Plugin&) = delete;
private:
FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
+
+#include <memory>
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+namespace
+{
+// http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+// NONE -1 --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
+// ULTRA_CONDENSED 50
+// EXTRA_CONDENSED 63
+// CONDENSED 75
+// SEMI_CONDENSED 87
+// NORMAL 100
+// SEMI_EXPANDED 113
+// EXPANDED 125
+// EXTRA_EXPANDED 150
+// ULTRA_EXPANDED 200
+const int FONT_WIDTH_TYPE_TO_INT[] = {-1, 50, 63, 75, 87, 100, 113, 125, 150, 200};
+const unsigned int NUM_FONT_WIDTH_TYPE = sizeof(FONT_WIDTH_TYPE_TO_INT) / sizeof(int);
+
+// NONE -1 --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
+// THIN 0
+// ULTRA_LIGHT, EXTRA_LIGHT 40
+// LIGHT 50
+// DEMI_LIGHT, SEMI_LIGHT 55
+// BOOK 75
+// NORMAL, REGULAR 80
+// MEDIUM 100
+// DEMI_BOLD, SEMI_BOLD 180
+// BOLD 200
+// ULTRA_BOLD, EXTRA_BOLD 205
+// BLACK, HEAVY, EXTRA_BLACK 210
+const int FONT_WEIGHT_TYPE_TO_INT[] = {-1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210};
+const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof(FONT_WEIGHT_TYPE_TO_INT) / sizeof(int);
+
+// NONE -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
+// NORMAL, ROMAN 0
+// ITALIC 100
+// OBLIQUE 110
+const int FONT_SLANT_TYPE_TO_INT[] = {-1, 0, 100, 110};
+const unsigned int NUM_FONT_SLANT_TYPE = sizeof(FONT_SLANT_TYPE_TO_INT) / sizeof(int);
+
+} // namespace
+
+/**
+ * @brief Returns the FontWidth's enum index for the given width value.
+ *
+ * @param[in] width The width value.
+ *
+ * @return The FontWidth's enum index.
+ */
+const FontWidth::Type IntToWidthType(int width)
+{
+ return static_cast<FontWidth::Type>(ValueToIndex(width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u));
+}
+
+/**
+ * @brief Returns the FontWeight's enum index for the given weight value.
+ *
+ * @param[in] weight The weight value.
+ *
+ * @return The FontWeight's enum index.
+ */
+const FontWeight::Type IntToWeightType(int weight)
+{
+ return static_cast<FontWeight::Type>(ValueToIndex(weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u));
+}
+
+/**
+ * @brief Returns the FontSlant's enum index for the given slant value.
+ *
+ * @param[in] slant The slant value.
+ *
+ * @return The FontSlant's enum index.
+ */
+const FontSlant::Type IntToSlantType(int slant)
+{
+ return static_cast<FontSlant::Type>(ValueToIndex(slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u));
+}
+
+const int DEFAULT_FONT_WIDTH(100);
+const int DEFAULT_FONT_WEIGHT(80);
+const int DEFAULT_FONT_SLANT(0);
+
+const FontWidth::Type DefaultFontWidth()
+{
+ return IntToWidthType(DEFAULT_FONT_WIDTH);
+}
+const FontWeight::Type DefaultFontWeight()
+{
+ return IntToWeightType(DEFAULT_FONT_WEIGHT);
+}
+const FontSlant::Type DefaultFontSlant()
+{
+ return IntToSlantType(DEFAULT_FONT_SLANT);
+}
+
+/**
+ * @brief Copy the color bitmap given in @p srcBuffer to @p data.
+ *
+ * @param[out] data The bitmap data.
+ * @param[in] srcWidth The width of the bitmap.
+ * @param[in] srcHeight The height of the bitmap.
+ * @param[in] srcBuffer The buffer of the bitmap.
+ */
+void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer)
+{
+ // Set the input dimensions.
+ const ImageDimensions inputDimensions(srcWidth, srcHeight);
+
+ // Set the output dimensions.
+ // If the output dimension is not given, the input dimension is set
+ // and won't be downscaling.
+ data.width = (data.width == 0) ? srcWidth : data.width;
+ data.height = (data.height == 0) ? srcHeight : data.height;
+ const ImageDimensions desiredDimensions(data.width, data.height);
+
+ // Creates the output buffer
+ const unsigned int bufferSize = data.width * data.height * 4u;
+ data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+ if(inputDimensions == desiredDimensions)
+ {
+ // There isn't downscaling.
+ memcpy(data.buffer, srcBuffer, bufferSize);
+ }
+ else
+ {
+ Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
+ inputDimensions,
+ data.buffer,
+ desiredDimensions);
+ }
+}
+
+/**
+ * @brief Copy the FreeType bitmap to the given buffer.
+ *
+ * @param[out] data The bitmap data.
+ * @param[in] srcBitmap The FreeType bitmap.
+ * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
+ */
+void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired)
+{
+ if(srcBitmap.width * srcBitmap.rows > 0)
+ {
+ switch(srcBitmap.pixel_mode)
+ {
+ case FT_PIXEL_MODE_GRAY:
+ {
+ if(srcBitmap.pitch == static_cast<int>(srcBitmap.width))
+ {
+ uint8_t* pixelsIn = srcBitmap.buffer;
+ unsigned int width = srcBitmap.width;
+ unsigned height = srcBitmap.rows;
+
+ std::unique_ptr<uint8_t, void (*)(void*)> pixelsOutPtr(nullptr, free);
+
+ if(isShearRequired)
+ {
+ /**
+ * Glyphs' bitmaps with no slant retrieved from FreeType:
+ * __________ ____
+ * |XXXXXXXX| |XX|
+ * | XX | |XX|
+ * | XX | |XX|
+ * | XX | |XX|
+ * | XX | |XX|
+ * | XX | |XX|
+ * ---------- ----
+ *
+ * Expected glyphs' bitmaps with italic slant:
+ * ____________ ______
+ * | XXXXXXXX| | XX|
+ * | XX | | XX|
+ * | XX | | XX |
+ * | XX | | XX |
+ * | XX | |XX |
+ * | XX | |XX |
+ * ------------ ------
+ *
+ * Glyphs' bitmaps with software italic slant retrieved from FreeType:
+ * __________ ______
+ * |XXXXXXXX| | XX|
+ * | XX | | XX|
+ * | XX | | XX |
+ * | XX | | XX |
+ * | XX | |XX |
+ * | XX | |XX |
+ * ---------- ------
+ *
+ * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
+ */
+ unsigned int widthOut = 0u;
+ unsigned int heightOut = 0u;
+ uint8_t* pixelsOut = nullptr;
+
+ Dali::Internal::Platform::HorizontalShear(pixelsIn,
+ width,
+ height,
+ 1u,
+ -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
+ pixelsOut,
+ widthOut,
+ heightOut);
+
+ width = widthOut;
+ height = heightOut;
+ pixelsIn = pixelsOut;
+ pixelsOutPtr.reset(pixelsOut);
+ }
+
+ const unsigned int bufferSize = width * height;
+ data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+ data.width = width;
+ data.height = height;
+ data.format = Pixel::L8; // Sets the pixel format.
+ memcpy(data.buffer, pixelsIn, bufferSize);
+ }
+ break;
+ }
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+ case FT_PIXEL_MODE_BGRA:
+ {
+ if(srcBitmap.pitch == static_cast<int>(srcBitmap.width << 2u))
+ {
+ ConvertBitmap(data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer);
+
+ // Sets the pixel format.
+ data.format = Pixel::BGRA8888;
+ }
+ break;
+ }
+#endif
+ default:
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n");
+ break;
+ }
+ }
+ }
+}
+
+FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription)
+{
+ // create the cached font family lookup pattern
+ // a pattern holds a set of names, each name refers to a property of the font
+ FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ if(!fontFamilyPattern)
+ {
+ return nullptr;
+ }
+
+ // add a property to the pattern for the font family
+ FcPatternAddString(fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fontDescription.family.c_str()));
+
+ // add a property to the pattern for local setting.
+ const char* locale = setlocale(LC_MESSAGES, nullptr);
+ if(locale != nullptr)
+ {
+ FcPatternAddString(fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>(locale));
+ }
+
+ int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
+ if(width < 0)
+ {
+ // Use default.
+ width = DEFAULT_FONT_WIDTH;
+ }
+
+ int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
+ if(weight < 0)
+ {
+ // Use default.
+ weight = DEFAULT_FONT_WEIGHT;
+ }
+
+ int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
+ if(slant < 0)
+ {
+ // Use default.
+ slant = DEFAULT_FONT_SLANT;
+ }
+
+ FcPatternAddInteger(fontFamilyPattern, FC_WIDTH, width);
+ FcPatternAddInteger(fontFamilyPattern, FC_WEIGHT, weight);
+ FcPatternAddInteger(fontFamilyPattern, FC_SLANT, slant);
+
+ // modify the config, with the mFontFamilyPatterm
+ FcConfigSubstitute(nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern);
+
+ // provide default values for unspecified properties in the font pattern
+ // e.g. patterns without a specified style or weight are set to Medium
+ FcDefaultSubstitute(fontFamilyPattern);
+
+ return fontFamilyPattern;
+}
+
+FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description)
+{
+ FcCharSet* characterSet = nullptr;
+
+ FcPattern* pattern = CreateFontFamilyPattern(description); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ if(nullptr != pattern)
+ {
+ FcResult result = FcResultMatch;
+ FcPattern* match = FcFontMatch(nullptr, pattern, &result); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+ FcPatternGetCharSet(match, FC_CHARSET, 0u, &characterSet);
+
+ // Destroys the created patterns.
+ FcPatternDestroy(match);
+ FcPatternDestroy(pattern);
+ }
+
+ return characterSet;
+}
+
+} // namespace Dali::TextAbstraction::Internal
--- /dev/null
+#ifndef DALI_TEST_ABSTRACTION_INTERNAL_FONT_CLIENT_UTILS_H
+#define DALI_TEST_ABSTRACTION_INTERNAL_FONT_CLIENT_UTILS_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_STROKER_H
+#include FT_SYNTHESIS_H
+
+namespace Dali::TextAbstraction::Internal
+{
+void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
+ unsigned int srcWidth,
+ unsigned int srcHeight,
+ const unsigned char* const srcBuffer);
+
+void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
+ FT_Bitmap srcBitmap,
+ bool isShearRequired);
+
+/**
+ * @brief Creates a font family pattern used to match fonts.
+ *
+ * @note Need to call FcPatternDestroy to free the resources.
+ *
+ * @param[in] fontDescription The font to cache.
+ *
+ * @return The pattern.
+ */
+FcPattern* CreateFontFamilyPattern(const FontDescription& fontDescription);
+
+/**
+ * @brief Creates a character set from a given font's @p description.
+ *
+ * @note Need to call FcCharSetDestroy to free the resources.
+ *
+ * @param[in] description The font's description.
+ *
+ * @return A character set.
+ */
+FcCharSet* CreateCharacterSetFromDescription(const FontDescription& description);
+
+constexpr int ValueToIndex(int value, const int* const table, unsigned int maxIndex)
+{
+ if(nullptr == table)
+ {
+ // Return an invalid index if there is no table.
+ return -1;
+ }
+
+ if(value <= table[0])
+ {
+ return 0;
+ }
+
+ if(value >= table[maxIndex])
+ {
+ return maxIndex;
+ }
+
+ for(unsigned int index = 0u; index < maxIndex; ++index)
+ {
+ const int v1 = table[index];
+ const unsigned int indexPlus = index + 1u;
+ const int v2 = table[indexPlus];
+ if((v1 < value) && (value <= v2))
+ {
+ const int result = ((v1 > 0) && ((value - v1) < (v2 - value))) ? index : indexPlus;
+ return result;
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief Returns the FontWidth's enum index for the given width value.
+ *
+ * @param[in] width The width value.
+ *
+ * @return The FontWidth's enum index.
+ */
+const FontWidth::Type IntToWidthType(int width);
+
+/**
+ * @brief Returns the FontWeight's enum index for the given weight value.
+ *
+ * @param[in] weight The weight value.
+ *
+ * @return The FontWeight's enum index.
+ */
+const FontWeight::Type IntToWeightType(int weight);
+
+/**
+ * @brief Returns the FontSlant's enum index for the given slant value.
+ *
+ * @param[in] slant The slant value.
+ *
+ * @return The FontSlant's enum index.
+ */
+const FontSlant::Type IntToSlantType(int slant);
+
+const FontWidth::Type DefaultFontWidth();
+const FontWeight::Type DefaultFontWeight();
+const FontSlant::Type DefaultFontSlant();
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif // DALI_TEST_ABSTRACTION_INTERNAL_FONT_CLIENT_UTILS_H
--- /dev/null
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/integration-api/debug.h>
+#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
+#include <dali/internal/text/text-abstraction/plugin/font-face-cache-item.h>
+
+#if defined(DEBUG_ENABLED)
+extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
+
+namespace Dali::TextAbstraction::Internal
+{
+const float FROM_266 = 1.0f / 64.0f;
+const float POINTS_PER_INCH = 72.f;
+
+FontFaceCacheItem::FontFaceCacheItem(FT_Library& freeTypeLibrary,
+ FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics)
+: mFreeTypeLibrary(freeTypeLibrary),
+ mFreeTypeFace(ftFace),
+ mPath(path),
+ mRequestedPointSize(requestedPointSize),
+ mFaceIndex(face),
+ mMetrics(metrics),
+ mCharacterSet(nullptr),
+ mFixedSizeIndex(0),
+ mFixedWidthPixels(0.f),
+ mFixedHeightPixels(0.f),
+ mVectorFontId(0u),
+ mFontId(0u),
+ mIsFixedSizeBitmap(false),
+ mHasColorTables(false)
+{
+}
+
+FontFaceCacheItem::FontFaceCacheItem(FT_Library& freeTypeLibrary,
+ FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics,
+ int fixedSizeIndex,
+ float fixedWidth,
+ float fixedHeight,
+ bool hasColorTables)
+: mFreeTypeLibrary(freeTypeLibrary),
+ mFreeTypeFace(ftFace),
+ mPath(path),
+ mRequestedPointSize(requestedPointSize),
+ mFaceIndex(face),
+ mMetrics(metrics),
+ mCharacterSet(nullptr),
+ mFixedSizeIndex(fixedSizeIndex),
+ mFixedWidthPixels(fixedWidth),
+ mFixedHeightPixels(fixedHeight),
+ mVectorFontId(0u),
+ mFontId(0u),
+ mIsFixedSizeBitmap(true),
+ mHasColorTables(hasColorTables)
+{
+}
+
+void FontFaceCacheItem::GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const
+{
+ metrics = mMetrics;
+
+ // Adjust the metrics if the fixed-size font should be down-scaled
+ if(mIsFixedSizeBitmap)
+ {
+ const float desiredFixedSize = static_cast<float>(mRequestedPointSize) * FROM_266 / POINTS_PER_INCH * dpiVertical;
+
+ if(desiredFixedSize > 0.f)
+ {
+ const float scaleFactor = desiredFixedSize / mFixedHeightPixels;
+
+ metrics.ascender = metrics.ascender * scaleFactor;
+ metrics.descender = metrics.descender * scaleFactor;
+ metrics.height = metrics.height * scaleFactor;
+ metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
+ metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
+ }
+ }
+}
+
+bool FontFaceCacheItem::GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const
+{
+ bool success(true);
+
+ FT_Face ftFace = mFreeTypeFace;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+ // Check to see if we should be loading a Fixed Size bitmap?
+ if(mIsFixedSizeBitmap)
+ {
+ FT_Select_Size(ftFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
+ int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_COLOR);
+ if(FT_Err_Ok == error)
+ {
+ glyph.width = mFixedWidthPixels;
+ glyph.height = mFixedHeightPixels;
+ glyph.advance = mFixedWidthPixels;
+ glyph.xBearing = 0.0f;
+ glyph.yBearing = mFixedHeightPixels;
+
+ // Adjust the metrics if the fixed-size font should be down-scaled
+ const float desiredFixedSize = static_cast<float>(mRequestedPointSize) * FROM_266 / POINTS_PER_INCH * dpiVertical;
+
+ if(desiredFixedSize > 0.f)
+ {
+ const float scaleFactor = desiredFixedSize / mFixedHeightPixels;
+
+ glyph.width = glyph.width * scaleFactor;
+ glyph.height = glyph.height * scaleFactor;
+ glyph.advance = glyph.advance * scaleFactor;
+ glyph.xBearing = glyph.xBearing * scaleFactor;
+ glyph.yBearing = glyph.yBearing * scaleFactor;
+
+ glyph.scaleFactor = scaleFactor;
+ }
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error);
+ success = false;
+ }
+ }
+ else
+#endif
+ {
+ // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
+ // i.e. with the SNum-3R font.
+ // @todo: add an option to use the FT_LOAD_DEFAULT if required?
+ int error = FT_Load_Glyph(ftFace, glyph.index, FT_LOAD_NO_AUTOHINT);
+
+ // Keep the width of the glyph before doing the software emboldening.
+ // It will be used to calculate a scale factor to be applied to the
+ // advance as Harfbuzz doesn't apply any SW emboldening to calculate
+ // the advance of the glyph.
+ const float width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
+
+ if(FT_Err_Ok == error)
+ {
+ const bool isEmboldeningRequired = glyph.isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD);
+ if(isEmboldeningRequired)
+ {
+ // Does the software bold.
+ FT_GlyphSlot_Embolden(ftFace->glyph);
+ }
+
+ glyph.width = static_cast<float>(ftFace->glyph->metrics.width) * FROM_266;
+ glyph.height = static_cast<float>(ftFace->glyph->metrics.height) * FROM_266;
+ if(horizontal)
+ {
+ glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingX) * FROM_266;
+ glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.horiBearingY) * FROM_266;
+ }
+ else
+ {
+ glyph.xBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingX) * FROM_266;
+ glyph.yBearing += static_cast<float>(ftFace->glyph->metrics.vertBearingY) * FROM_266;
+ }
+
+ if(isEmboldeningRequired && !Dali::EqualsZero(width))
+ {
+ // If the glyph is emboldened by software, the advance is multiplied by a
+ // scale factor to make it slightly bigger.
+ glyph.advance *= (glyph.width / width);
+ }
+
+ // Use the bounding box of the bitmap to correct the metrics.
+ // For some fonts i.e the SNum-3R the metrics need to be corrected,
+ // otherwise the glyphs 'dance' up and down depending on the
+ // font's point size.
+
+ FT_Glyph ftGlyph;
+ error = FT_Get_Glyph(ftFace->glyph, &ftGlyph);
+
+ FT_BBox bbox;
+ FT_Glyph_Get_CBox(ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox);
+
+ const float descender = glyph.height - glyph.yBearing;
+ glyph.height = (bbox.yMax - bbox.yMin) * FROM_266;
+ glyph.yBearing = glyph.height - round(descender);
+
+ // Created FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph(ftGlyph);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ return success;
+}
+
+/**
+ * @brief Create a bitmap representation of a glyph from a face font
+ *
+ * @param[in] glyphIndex The index of a glyph within the specified font.
+ * @param[in] isItalicRequired Whether the glyph requires italic style.
+ * @param[in] isBoldRequired Whether the glyph requires bold style.
+ * @param[out] data The bitmap data.
+ * @param[in] outlineWidth The width of the glyph outline in pixels.
+ */
+void FontFaceCacheItem::CreateBitmap(
+ GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+{
+ FT_Face ftFace = mFreeTypeFace;
+ FT_Error error;
+ // For the software italics.
+ bool isShearRequired = false;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+ // Check to see if this is fixed size bitmap
+ if(mIsFixedSizeBitmap)
+ {
+ error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_COLOR);
+ }
+ else
+#endif
+ {
+ // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
+ // i.e. with the SNum-3R font.
+ // @todo: add an option to use the FT_LOAD_DEFAULT if required?
+ error = FT_Load_Glyph(ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT);
+ }
+ if(FT_Err_Ok == error)
+ {
+ if(isBoldRequired && !(ftFace->style_flags & FT_STYLE_FLAG_BOLD))
+ {
+ // Does the software bold.
+ FT_GlyphSlot_Embolden(ftFace->glyph);
+ }
+
+ if(isItalicRequired && !(ftFace->style_flags & FT_STYLE_FLAG_ITALIC))
+ {
+ // Will do the software italic.
+ isShearRequired = true;
+ }
+
+ FT_Glyph glyph;
+ error = FT_Get_Glyph(ftFace->glyph, &glyph);
+
+ // Convert to bitmap if necessary
+ if(FT_Err_Ok == error)
+ {
+ if(glyph->format != FT_GLYPH_FORMAT_BITMAP)
+ {
+ int offsetX = 0, offsetY = 0;
+ bool isOutlineGlyph = (glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0);
+
+ // Create a bitmap for the outline
+ if(isOutlineGlyph)
+ {
+ // Retrieve the horizontal and vertical distance from the current pen position to the
+ // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+ if(FT_Err_Ok == error)
+ {
+ FT_Glyph normalGlyph;
+ error = FT_Get_Glyph(ftFace->glyph, &normalGlyph);
+
+ error = FT_Glyph_To_Bitmap(&normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1);
+ if(FT_Err_Ok == error)
+ {
+ FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(normalGlyph);
+
+ offsetX = bitmapGlyph->left;
+ offsetY = bitmapGlyph->top;
+ }
+
+ // Created FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph(normalGlyph);
+ }
+
+ // Now apply the outline
+
+ // Set up a stroker
+ FT_Stroker stroker;
+ error = FT_Stroker_New(mFreeTypeLibrary, &stroker);
+
+ if(FT_Err_Ok == error)
+ {
+ FT_Stroker_Set(stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+ error = FT_Glyph_StrokeBorder(&glyph, stroker, 0, 1);
+
+ if(FT_Err_Ok == error)
+ {
+ FT_Stroker_Done(stroker);
+ }
+ else
+ {
+ DALI_LOG_ERROR("FT_Glyph_StrokeBorder Failed with error: %d\n", error);
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR("FT_Stroker_New Failed with error: %d\n", error);
+ }
+ }
+
+ error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+ if(FT_Err_Ok == error)
+ {
+ FT_BitmapGlyph bitmapGlyph = reinterpret_cast<FT_BitmapGlyph>(glyph);
+
+ if(isOutlineGlyph)
+ {
+ // Calculate the additional horizontal and vertical offsets needed for the position of the outline glyph
+ data.outlineOffsetX = offsetX - bitmapGlyph->left - outlineWidth;
+ data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
+ }
+
+ ConvertBitmap(data, bitmapGlyph->bitmap, isShearRequired);
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error);
+ }
+ }
+ else
+ {
+ ConvertBitmap(data, ftFace->glyph->bitmap, isShearRequired);
+ }
+
+ data.isColorEmoji = mIsFixedSizeBitmap;
+
+ // Created FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph(glyph);
+ }
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error);
+ }
+}
+
+bool FontFaceCacheItem::IsColorGlyph(GlyphIndex glyphIndex) const
+{
+ FT_Error error = -1;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+ // Check to see if this is fixed size bitmap
+ if(mHasColorTables)
+ {
+ error = FT_Load_Glyph(mFreeTypeFace, glyphIndex, FT_LOAD_COLOR);
+ }
+#endif
+ return FT_Err_Ok == error;
+}
+
+/**
+ * Check if the character is supported by this font
+ * @param[in] character The character to test
+ */
+bool FontFaceCacheItem::IsCharacterSupported(Character character)
+{
+ if(nullptr == mCharacterSet)
+ {
+ // Create again the character set.
+ // It can be null if the ResetSystemDefaults() method has been called.
+
+ FontDescription description;
+ description.path = mPath;
+ description.family = std::move(FontFamily(mFreeTypeFace->family_name));
+ description.weight = FontWeight::NONE;
+ description.width = FontWidth::NONE;
+ description.slant = FontSlant::NONE;
+
+ // Note FreeType doesn't give too much info to build a proper font style.
+ if(mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC)
+ {
+ description.slant = FontSlant::ITALIC;
+ }
+ if(mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD)
+ {
+ description.weight = FontWeight::BOLD;
+ }
+
+ mCharacterSet = FcCharSetCopy(CreateCharacterSetFromDescription(description));
+ }
+
+ return FcCharSetHasChar(mCharacterSet, character);
+}
+
+GlyphIndex FontFaceCacheItem::GetGlyphIndex(Character character) const
+{
+ return FT_Get_Char_Index(mFreeTypeFace, character);
+}
+
+} // namespace Dali::TextAbstraction::Internal
--- /dev/null
+#ifndef DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_CACHE_ITEM_H
+#define DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_CACHE_ITEM_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// INTERNAL INCLUDES
+
+#include <dali/internal/text/text-abstraction/plugin/font-cache-item-interface.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_STROKER_H
+#include FT_SYNTHESIS_H
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+ */
+struct FontFaceCacheItem : public FontCacheItemInterface
+{
+ FontFaceCacheItem(FT_Library& freeTypeLibrary,
+ FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics);
+
+ FontFaceCacheItem(FT_Library& freeTypeLibrary,
+ FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 requestedPointSize,
+ FaceIndex face,
+ const FontMetrics& metrics,
+ int fixedSizeIndex,
+ float fixedWidth,
+ float fixedHeight,
+ bool hasColorTables);
+
+ /**
+ * @copydoc FontCacheItemInterface::GetFontMetrics()
+ */
+ void GetFontMetrics(FontMetrics& metrics, unsigned int dpiVertical) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::GetGlyphMetrics()
+ */
+ bool GetGlyphMetrics(GlyphInfo& glyph, unsigned int dpiVertical, bool horizontal) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::CreateBitmap()
+ */
+ void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::IsColorGlyph()
+ */
+ bool IsColorGlyph(GlyphIndex glyphIndex) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::IsCharacterSupported()
+ */
+ bool IsCharacterSupported(Character character) override;
+
+ /**
+ * @copydoc FontCacheItemInterface::GetPointSize()
+ */
+ PointSize26Dot6 GetPointSize() const override
+ {
+ return mRequestedPointSize;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::GetGlyphIndex()
+ */
+ GlyphIndex GetGlyphIndex(Character character) const override;
+
+ /**
+ * @copydoc FontCacheItemInterface::GetTypeface()
+ */
+ FT_Face GetTypeface() const override
+ {
+ return mFreeTypeFace;
+ }
+
+ /**
+ * @copydoc FontCacheItemInterface::HasItalicStyle()
+ */
+ bool HasItalicStyle() const override
+ {
+ return (0u != (mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC));
+ }
+
+ FT_Library& mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+ FT_Face mFreeTypeFace; ///< The FreeType face.
+ FontPath mPath; ///< The path to the font file name.
+ PointSize26Dot6 mRequestedPointSize; ///< The font point size.
+ FaceIndex mFaceIndex; ///< The face index.
+ FontMetrics mMetrics; ///< The font metrics.
+ _FcCharSet* mCharacterSet; ///< Pointer with the range of characters.
+ int mFixedSizeIndex; ///< Index to the fixed size table for the requested size.
+ float mFixedWidthPixels; ///< The height in pixels (fixed size bitmaps only)
+ float mFixedHeightPixels; ///< The height in pixels (fixed size bitmaps only)
+ unsigned int mVectorFontId; ///< The ID of the equivalent vector-based font
+ FontId mFontId; ///< Index to the vector with the cache of font's ids.
+ bool mIsFixedSizeBitmap : 1; ///< Whether the font has fixed size bitmaps.
+ bool mHasColorTables : 1; ///< Whether the font has color tables.
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_TEST_ABSTRACTION_INTERNAL_FONT_FACE_CACHE_ITEM_H
--- /dev/null
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_PLUGIN_PIXEL_BUFFER_CACHE_ITEM_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_PLUGIN_PIXEL_BUFFER_CACHE_ITEM_H
+
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Dali::TextAbstraction::Internal
+{
+/**
+ * @brief Type used for indices addressing the vector with pixel buffers.
+ */
+typedef uint32_t PixelBufferId;
+
+/**
+ * @brief Caches pixel buffers.
+ */
+struct PixelBufferCacheItem
+{
+ Devel::PixelBuffer pixelBuffer; ///< The pixel buffer loaded from the url.
+ std::string url; ///< The url.
+};
+
+} // namespace Dali::TextAbstraction::Internal
+
+#endif //DALI_INTERNAL_TEXT_ABSTRACTION_PLUGIN_PIXEL_BUFFER_CACHE_ITEM_H
{
const unsigned int ADAPTOR_MAJOR_VERSION = 2;
const unsigned int ADAPTOR_MINOR_VERSION = 0;
-const unsigned int ADAPTOR_MICRO_VERSION = 50;
+const unsigned int ADAPTOR_MICRO_VERSION = 51;
const char* const ADAPTOR_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali2-adaptor
Summary: The DALi Tizen Adaptor
-Version: 2.0.50
+Version: 2.0.51
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT