ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
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}\" )
#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/plugin/font-client-utils.h>
#include <stdint.h>
return o;
}
-int UtcDaliFontClientFindFallbackFont(void)
+int UtcDaliFontClientGetDefaultPlatformFontDescription(void)
{
TestApplication application;
- tet_infoline(" UtcDaliFontClientFindFallbackFont ");
+ tet_infoline(" UtcDaliFontClientGetDefaultPlatformFontDescription");
FontClient fontClient;
fontClient = FontClient::Get();
- FontList fontList;
- fontClient.GetSystemFonts(fontList);
- DALI_TEST_CHECK(fontList.size() > 0);
-
- const std::string emptyString;
- FontDescription fontDescription;
- fontDescription.width = FontWidth::NORMAL;
- fontDescription.weight = FontWeight::NORMAL;
- fontDescription.slant = FontSlant::NORMAL;
- fontDescription.type = FontDescription::BITMAP_FONT;
+ FontDescription fontDescription;
+ fontClient.GetDefaultPlatformFontDescription(fontDescription);
std::ostringstream oss;
oss << fontDescription;
- tet_printf("Looking for: %s", oss.str().c_str());
+ 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);
- DALI_TEST_CHECK(fontId != 0);
- fontClient.GetDescription(fontId, fontDescription);
- oss.clear();
- oss << fontDescription;
- tet_printf("Found: %d: %s", fontId, oss.str().c_str());
-
- bool color = fontClient.IsColorGlyph(fontId, fontClient.GetGlyphIndex(fontId, 'A'));
- DALI_TEST_CHECK(color || 1);
+ bool supported = fontClient.IsCharacterSupportedByFont(fontId, 'A');
+ DALI_TEST_EQUALS(supported, true, TEST_LOCATION);
END_TEST;
}
-int UtcDaliFontClientGetDefaultPlatformFontDescription(void)
+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(" UtcDaliFontClientGetDefaultPlatformFontDescription");
+ tet_infoline(" UtcDaliFontClientTestBitmapFont");
FontClient fontClient;
fontClient = FontClient::Get();
- FontDescription fontDescription;
- fontClient.GetDefaultPlatformFontDescription(fontDescription);
+ auto bitmapFontId = SetupBitmapFont();
+ FontDescription fontDescription;
+ fontClient.GetDescription(bitmapFontId, fontDescription);
std::ostringstream oss;
oss << fontDescription;
- tet_printf("%s", oss.str().c_str());
+ tet_printf("Found: %d: %s", bitmapFontId, oss.str().c_str());
- DALI_TEST_CHECK(fontDescription.path.empty() == false);
+ bool color = fontClient.IsColorGlyph(bitmapFontId, fontClient.GetGlyphIndex(bitmapFontId, '2'));
+ DALI_TEST_EQUALS(color, true, TEST_LOCATION);
- FontId fontId = fontClient.FindFallbackFont('A',
- fontDescription,
- FontClient::DEFAULT_POINT_SIZE,
- true);
+ 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);
- bool supported = fontClient.IsCharacterSupportedByFont(fontId, 'A');
- DALI_TEST_EQUALS(supported, true, TEST_LOCATION);
END_TEST;
}
/**
* @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);
${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.
+ */
+
+#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
#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>
using Dali::Vector;
using namespace std;
-namespace Dali
-{
-namespace TextAbstraction
-{
-namespace Internal
+namespace Dali::TextAbstraction::Internal
{
/**
* @brief Free the resources allocated by the FcCharSet objects.
{
}
-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),
{
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()))
+ PointSize26Dot6 pointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(id);
+ if(fontCacheItem != nullptr)
{
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- switch(fontIdCacheItem.type)
- {
- case FontDescription::FACE_FONT:
- {
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " point size : %d\n", (*(mFontFaceCache.begin() + fontIdCacheItem.id)).mRequestedPointSize);
- return (*(mFontFaceCache.begin() + fontIdCacheItem.id)).mRequestedPointSize;
- }
- case FontDescription::BITMAP_FONT:
- {
- return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
- }
- default:
- {
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
- {
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid font ID %d\n", id);
+ pointSize = fontCacheItem->GetPointSize();
}
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " point size : %d\n", pointSize);
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE);
- return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+ return pointSize;
}
bool FontClient::Plugin::IsCharacterSupportedByFont(FontId fontId, Character character)
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " font id : %d\n", fontId);
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " character : %p\n", character);
- if((fontId < 1u) || (fontId > mFontIdCache.Count()))
+ bool isSupported = false;
+ auto fontCacheItem = const_cast<FontCacheItemInterface*>(GetCachedFontItem(fontId));
+ if(fontCacheItem != nullptr)
{
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid font id. Number of items in the cache: %d\n", mFontIdCache.Count());
- return false;
+ isSupported = fontCacheItem->IsCharacterSupported(character); // May cache
}
- --fontId;
-
- bool isSupported = false;
-
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false"));
+ return isSupported;
+}
- switch(fontIdCacheItem.type)
+const FontCacheItemInterface* FontClient::Plugin::GetCachedFontItem(FontId id) const
+{
+ const FontId index = id - 1u;
+ if((id > 0u) && (index < mFontIdCache.Count()))
{
- case FontDescription::FACE_FONT:
+ const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+ switch(fontIdCacheItem.type)
{
- if(fontIdCacheItem.id < mFontFaceCache.size())
+ case FontDescription::FACE_FONT:
{
- 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);
+ return &mFontFaceCache[fontIdCacheItem.id];
}
- break;
- }
- case FontDescription::BITMAP_FONT:
- {
- const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
-
- for(const auto& glyph : bitmapFont.glyphs)
+ case FontDescription::BITMAP_FONT:
{
- if(glyph.utf32 == character)
- {
- isSupported = true;
- break;
- }
+ return &mBitmapFontCache[fontIdCacheItem.id];
+ }
+ default:
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
}
- break;
- }
- default:
- {
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
}
}
-
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " is supported : %s\n", (isSupported ? "true" : "false"));
- return isSupported;
+ return nullptr;
}
FontId FontClient::Plugin::FindFontForCharacter(const FontList& fontList,
}
}
- 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;
- }
+ BitmapFontCacheItem bitmapFontCacheItem(bitmapFont, mFontIdCache.Count());
FontIdCacheItem fontIdCacheItem;
fontIdCacheItem.type = FontDescription::BITMAP_FONT;
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(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
- else
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
{
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId);
+ fontCacheItem->GetFontMetrics(metrics, mDpiVertical);
}
}
GlyphIndex FontClient::Plugin::GetGlyphIndex(FontId fontId,
Character charcode)
{
- GlyphIndex glyphIndex = 0u;
- const FontId index = fontId - 1u;
-
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
{
- 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 fontCacheItem->GetGlyphIndex(charcode);
}
- return glyphIndex;
+ return 0u;
}
bool FontClient::Plugin::GetGlyphMetrics(GlyphInfo* array,
uint32_t size,
bool horizontal)
{
- bool success(true);
+ bool success(false);
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 FontCacheItemInterface* fontCacheItem = GetCachedFontItem(glyph.fontId);
+ if(fontCacheItem != nullptr)
{
- 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(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;
- }
- }
- 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(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
+ success = fontCacheItem->GetGlyphMetrics(glyph, mDpiVertical, horizontal);
}
- else
+ // Check if it's an embedded image.
+ else if((0u == glyph.fontId) && (0u != glyph.index) && (glyph.index <= mEmbeddedItemCache.Count()))
{
- // 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;
- }
+ mEmbeddedItemCache[glyph.index - 1u].GetGlyphMetrics(glyph);
+ success = true;
}
}
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 FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
{
- 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(gFontClientLogFilter, 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(gFontClientLogFilter, 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(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
+ fontCacheItem->CreateBitmap(glyphIndex, data, outlineWidth, isItalicRequired, isBoldRequired);
}
- else
+ else if((0u != glyphIndex) && (glyphIndex <= mEmbeddedItemCache.Count()))
{
- 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.
- }
- }
+ // It's an embedded item.
+ mEmbeddedItemCache[glyphIndex - 1u].CreateBitmap(mPixelBufferCache, data);
}
}
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(gFontClientLogFilter, Debug::General, " Invalid type of font\n");
- }
- }
- }
-
- return FT_Err_Ok == error;
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ return fontCacheItem && fontCacheItem->IsColorGlyph(glyphIndex);
}
FT_FaceRec_* FontClient::Plugin::GetFreetypeFace(FontId fontId)
{
- FT_Face fontFace = nullptr;
-
- const FontId index = fontId - 1u;
- if((fontId > 0u) &&
- (index < mFontIdCache.Count()))
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
{
- const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
-
- if(FontDescription::FACE_FONT == fontIdCacheItem.type)
- {
- fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
- }
+ return fontCacheItem->GetTypeface();
}
- return fontFace;
+ return nullptr;
}
FontDescription::Type FontClient::Plugin::GetFontType(FontId fontId)
0.0f);
// Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables);
+ 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();
static_cast<float>(ftFace->underline_thickness) * FROM_266);
// Create the FreeType font face item to cache.
- FontFaceCacheItem fontFaceCacheItem(ftFace, path, requestedPointSize, faceIndex, metrics);
+ FontFaceCacheItem fontFaceCacheItem(mFreeTypeLibrary, ftFace, path, requestedPointSize, faceIndex, metrics);
// Set the index to the font's id cache.
fontFaceCacheItem.mFontId = mFontIdCache.Count();
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
+ const FontCacheItemInterface* fontCacheItem = GetCachedFontItem(fontId);
+ if(fontCacheItem != nullptr)
{
- DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId);
+ return fontCacheItem->HasItalicStyle();
}
-
- return hasItalicStyle;
+ return false;
}
void FontClient::Plugin::CacheFontPath(FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize, const FontPath& path)
}
}
-} // namespace Internal
-
-} // namespace TextAbstraction
-
-} // namespace Dali
+} // 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>
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.
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.
#include <memory>
+#if defined(DEBUG_ENABLED)
extern Dali::Integration::Log::Filter* gFontClientLogFilter;
+#endif
namespace Dali::TextAbstraction::Internal
{
#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
{
--- /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