From: Shrouq Sabah Date: Wed, 10 Mar 2021 12:57:22 +0000 (+0200) Subject: Fixing issue: On Text, reducing font-point-size when the Glyph-block-size be larger... X-Git-Tag: dali_2.0.24~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F22%2F254922%2F33;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Fixing issue: On Text, reducing font-point-size when the Glyph-block-size be larger than Atlas-block-size to fit into it. Issue: On TextEditor or TextField when use font size (Point-Size) which creating Glyphs its size larger than Atlas-block size then logging error says that can’t create block and nothing appear in Text-Controller. Solution: At Adaptor level, checking block size according to point-size if the block will be larger than Atlas size then keep decreasing point-size until achieve block that fit into Atlas size. Toolkit calls API named “EnableAtlasLimitation” on Font-Client object to activate this validation on Adaptor level. Since the Atlas size information added as constants in Font-Client class. Log warning that the point-size is reduced. Automated test-cases added to Adaptor and Toolkit Added APIs into font-client/Adaptor for Point-size & Atlas information instead of constants/literal values in toolkit. Reproduce by: Creating TextEditor or TextFiled then set properties: mEditor.SetProperty( TextEditor::Property::POINT_SIZE, 330) ; mEditor.SetProperty( TextEditor::Property::FONT_FAMILY, " DejaVu Sans ") ; Logged error appears: Logged ERROR: “ERROR: DALI: CreateAtlas Atlas 512 x 512 too small. Dimensions need to be at least 517x517” Logged ERROR: “ERROR: DALI: Add Failed to create an atlas of 512 x 512 blocksize: 514 x 514.” Change-Id: Ia47462aa74b9807ed916fd63c4ba8b47437582e6 --- diff --git a/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf b/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf new file mode 100644 index 0000000..5267218 Binary files /dev/null and b/automated-tests/resources/fonts/dejavu/DejaVuSans.ttf differ diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp index 1774a04..ebf8994 100644 --- a/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp +++ b/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp @@ -20,8 +20,10 @@ #include #include #include +#include #include #include +#include using namespace Dali; @@ -85,3 +87,269 @@ int UtcDaliFontClient(void) END_TEST; } + +int UtcDaliFontClientAtlasLimitation(void) +{ + TestApplication application; + bool result = 0; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + + tet_infoline("UtcDaliFontClientAtlasLimitation Default"); + result = fontClient.IsAtlasLimitationEnabled(); + DALI_TEST_EQUALS(TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED, result, TEST_LOCATION); + + tet_infoline("UtcDaliFontClientAtlasLimitation Enabled"); + fontClient.EnableAtlasLimitation(true); + result = fontClient.IsAtlasLimitationEnabled(); + DALI_TEST_EQUALS(true, result, TEST_LOCATION); + + tet_infoline("UtcDaliFontClientAtlasLimitation Disabled"); + fontClient.EnableAtlasLimitation(false); + result = fontClient.IsAtlasLimitationEnabled(); + DALI_TEST_EQUALS(false, result, TEST_LOCATION); + END_TEST; + } + +const std::string DEFAULT_FONT_DIR( "/resources/fonts" ); +const uint32_t MAX_WIDTH_FIT_IN_ATLAS = TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK; +const uint32_t MAX_HEIGHT_FIT_IN_ATLAS = TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT - TextAbstraction::FontClient::PADDING_TEXT_ATLAS_BLOCK; + +int UtcDaliFontClientAtlasLimitationEnabled(void) +{ + + TestApplication application; + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.EnableAtlasLimitation(true); + + // The font file "DejaVuSans.ttf" is copied from Toolkit to Adaptor to make test-case of specific font-family. + // Note the block size depends on font-family. + // This is to create FontDescription and pass it to GetFontId with point-size (various cases). + TextAbstraction::FontDescription fontDescription; + fontDescription.path = pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf"; + fontDescription.family = "DejaVuSans"; + fontDescription.width = TextAbstraction::FontWidth::NONE; + fontDescription.weight = TextAbstraction::FontWeight::NORMAL; + fontDescription.slant = TextAbstraction::FontSlant::NONE; + + + // Block's width or height are less than 512 + tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=200"); + uint32_t pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + TextAbstraction::FontId fontId200 = fontClient.GetFontId(fontDescription, pointSize200); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData200; + glyphBufferData200.width = 0; + glyphBufferData200.height = 0; + fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0); + + DALI_TEST_GREATER( MAX_WIDTH_FIT_IN_ATLAS, glyphBufferData200.width, TEST_LOCATION ); + DALI_TEST_GREATER( MAX_HEIGHT_FIT_IN_ATLAS, glyphBufferData200.height, TEST_LOCATION ); + + // Block's width or height are greater than 512 and less than 1024 + uint32_t pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=1000"); + TextAbstraction::FontId fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData1000; + glyphBufferData1000.width = 0; + glyphBufferData1000.height = 0; + fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0); + + DALI_TEST_GREATER( MAX_WIDTH_FIT_IN_ATLAS, glyphBufferData1000.width, TEST_LOCATION ); + DALI_TEST_GREATER( MAX_HEIGHT_FIT_IN_ATLAS, glyphBufferData1000.height, TEST_LOCATION ); + + // Block's width or height are greater than 1024 and less than 2048 + uint32_t pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + tet_infoline("UtcDaliFontClientAtlasLimitationEnabled PointSize=2000"); + TextAbstraction::FontId fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData2000; + glyphBufferData2000.width = 0; + glyphBufferData2000.height = 0; + fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0); + + DALI_TEST_GREATER( MAX_WIDTH_FIT_IN_ATLAS, glyphBufferData2000.width, TEST_LOCATION ); + DALI_TEST_GREATER( MAX_HEIGHT_FIT_IN_ATLAS, glyphBufferData2000.height, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliFontClientAtlasLimitationDisabled(void) +{ + + TestApplication application; + + char* pathNamePtr = get_current_dir_name(); + const std::string pathName( pathNamePtr ); + free( pathNamePtr ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.EnableAtlasLimitation(false); + + TextAbstraction::FontDescription fontDescription; + fontDescription.path = pathName + DEFAULT_FONT_DIR + "/dejavu/DejaVuSans.ttf"; + fontDescription.family = "DejaVuSans"; + fontDescription.width = TextAbstraction::FontWidth::NONE; + fontDescription.weight = TextAbstraction::FontWeight::NORMAL; + fontDescription.slant = TextAbstraction::FontSlant::NONE; + + // Block's width or height are less than 512 + tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=200"); + uint32_t pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + TextAbstraction::FontId fontId200 = fontClient.GetFontId(fontDescription, pointSize200); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData200; + glyphBufferData200.width = 0; + glyphBufferData200.height = 0; + fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0); + + DALI_TEST_GREATER(512u, glyphBufferData200.width, TEST_LOCATION ); //93u + DALI_TEST_GREATER(512u, glyphBufferData200.height, TEST_LOCATION ); //115u + + // Block's width or height are greater than 512 and less than 1024 + tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=1000"); + uint32_t pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + TextAbstraction::FontId fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData1000; + glyphBufferData1000.width = 0; + glyphBufferData1000.height = 0; + fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0); + + DALI_TEST_GREATER( 512u, glyphBufferData1000.width, TEST_LOCATION ); //462u + DALI_TEST_GREATER( glyphBufferData1000.height, 512u, TEST_LOCATION ); //574u + + // Block's width or height are greater than 1024 and less than 2048 + tet_infoline("UtcDaliFontClientAtlasLimitationDisabled PointSize=2000"); + uint32_t pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; + TextAbstraction::FontId fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000); + TextAbstraction::FontClient::GlyphBufferData glyphBufferData2000; + glyphBufferData2000.width = 0; + glyphBufferData2000.height = 0; + fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0); + + DALI_TEST_GREATER( 1024u, glyphBufferData2000.width, TEST_LOCATION ); //924u + DALI_TEST_GREATER( glyphBufferData2000.height, 1024u, TEST_LOCATION ); //1148u + + END_TEST; +} + +int UtcDaliFontClientCurrentMaximumBlockSizeFitInAtlas(void) +{ + TestApplication application; + tet_infoline(" UtcDaliFontClientCurrentMaximumBlockSizeFitInAtlas "); + + bool isChanged ; + TextAbstraction::FontClient fontClient; + fontClient = TextAbstraction::FontClient::Get(); + + Size defaultTextAtlasSize = fontClient.GetDefaultTextAtlasSize(); + Size maximumTextAtlasSize = fontClient.GetMaximumTextAtlasSize(); + Size currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + + tet_infoline("CurrentMaximumBlockSizeFitInAtlas start with default "); + DALI_TEST_EQUALS( currentMaximumBlockSizeFitInAtlas, defaultTextAtlasSize, TEST_LOCATION ); + + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is changed with current "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(currentMaximumBlockSizeFitInAtlas); + DALI_TEST_CHECK (isChanged); + + Size decreaseOnlyWidth (currentMaximumBlockSizeFitInAtlas.width - 1u, currentMaximumBlockSizeFitInAtlas.height); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is changed with width < current "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(decreaseOnlyWidth); + DALI_TEST_CHECK (isChanged); + + Size decreaseOnlyHeigth (currentMaximumBlockSizeFitInAtlas.width, currentMaximumBlockSizeFitInAtlas.height - 1u); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is changed with height < current "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(decreaseOnlyHeigth); + DALI_TEST_CHECK (isChanged); + + Size decreaseBoth (currentMaximumBlockSizeFitInAtlas.width - 1u, currentMaximumBlockSizeFitInAtlas.height - 1u); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is changed with size < current "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(decreaseBoth); + DALI_TEST_CHECK (isChanged); + + Size increaseOnlyWidth (maximumTextAtlasSize.width + 1u, currentMaximumBlockSizeFitInAtlas.height); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is not changed with width > max "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(increaseOnlyWidth); + DALI_TEST_CHECK (!isChanged); + + Size increaseOnlyHeigth (currentMaximumBlockSizeFitInAtlas.width, maximumTextAtlasSize.height + 1u); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is not changed with height > max "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(increaseOnlyHeigth); + DALI_TEST_CHECK (!isChanged); + + Size increaseBoth (maximumTextAtlasSize.width + 1u, maximumTextAtlasSize.height + 1u); + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is not changed with size > max "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(increaseBoth); + DALI_TEST_CHECK (!isChanged); + + currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + if(currentMaximumBlockSizeFitInAtlas.width < maximumTextAtlasSize.width && currentMaximumBlockSizeFitInAtlas.height < maximumTextAtlasSize.height) + { + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is changed with current < size < max "); + Size increaseWidth = Size(currentMaximumBlockSizeFitInAtlas.width + 1u, currentMaximumBlockSizeFitInAtlas.height); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(increaseWidth); + DALI_TEST_CHECK (isChanged); + currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + + Size increaseHeigth = Size(currentMaximumBlockSizeFitInAtlas.width, currentMaximumBlockSizeFitInAtlas.height + 1u); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(increaseHeigth); + DALI_TEST_CHECK (isChanged); + currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + + Size sizeLessThanMax = Size(currentMaximumBlockSizeFitInAtlas.width + 1u, currentMaximumBlockSizeFitInAtlas.height + 1u); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(sizeLessThanMax); + + if(currentMaximumBlockSizeFitInAtlas.width < maximumTextAtlasSize.width && currentMaximumBlockSizeFitInAtlas.height < maximumTextAtlasSize.height) + { + DALI_TEST_CHECK (isChanged); + } + else + { + DALI_TEST_CHECK (!isChanged); + } + + currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + + DALI_TEST_NOT_EQUALS (currentMaximumBlockSizeFitInAtlas, defaultTextAtlasSize, 0.0f, TEST_LOCATION ); + DALI_TEST_EQUALS (currentMaximumBlockSizeFitInAtlas, sizeLessThanMax, TEST_LOCATION ); + + tet_infoline("SetCurrentMaximumBlockSizeFitInAtlas is not changed with size == max "); + isChanged = fontClient.SetCurrentMaximumBlockSizeFitInAtlas(maximumTextAtlasSize); + DALI_TEST_CHECK (!isChanged); + } + + currentMaximumBlockSizeFitInAtlas = fontClient.GetCurrentMaximumBlockSizeFitInAtlas(); + DALI_TEST_NOT_EQUALS (currentMaximumBlockSizeFitInAtlas, maximumTextAtlasSize, 0.0f, TEST_LOCATION ); + + + END_TEST; +} + +int UtcDaliFontClientTextAtlasConstants(void) +{ + TestApplication application; + tet_infoline(" UtcDaliFontClientTextAtlasConstants "); + + TextAbstraction::FontClient fontClient; + fontClient = TextAbstraction::FontClient::Get(); + + Size defaultTextAtlasSize = fontClient.GetDefaultTextAtlasSize(); + Size defaultTextAtlasWidthHeight(TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_WIDTH, TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_HEIGHT); + DALI_TEST_EQUALS (defaultTextAtlasSize, TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE, TEST_LOCATION ); + DALI_TEST_EQUALS (defaultTextAtlasSize, defaultTextAtlasWidthHeight, TEST_LOCATION ); + + + Size maximumTextAtlasSize = fontClient.GetMaximumTextAtlasSize(); + Size maxTextAtlasWidthHeight(TextAbstraction::FontClient::MAX_TEXT_ATLAS_WIDTH, TextAbstraction::FontClient::MAX_TEXT_ATLAS_HEIGHT); + DALI_TEST_EQUALS (maximumTextAtlasSize, TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE, TEST_LOCATION ); + DALI_TEST_EQUALS (maximumTextAtlasSize, maxTextAtlasWidthHeight, TEST_LOCATION ); + + + uint32_t numberOfPointsPerOneUnitOfPointSize = fontClient.GetNumberOfPointsPerOneUnitOfPointSize(); + 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 diff --git a/dali/devel-api/text-abstraction/font-client.cpp b/dali/devel-api/text-abstraction/font-client.cpp index 5f0f5c4..7531f55 100644 --- a/dali/devel-api/text-abstraction/font-client.cpp +++ b/dali/devel-api/text-abstraction/font-client.cpp @@ -28,6 +28,26 @@ namespace TextAbstraction const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64 const float FontClient::DEFAULT_ITALIC_ANGLE = 12.f * Dali::Math::PI_OVER_180; // FreeType documentation states the software italic is done by doing a horizontal shear of 12 degrees (file ftsynth.h). +//Default atlas block +const bool FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED = true; +const uint32_t FontClient::DEFAULT_TEXT_ATLAS_WIDTH = 512u; +const uint32_t FontClient::DEFAULT_TEXT_ATLAS_HEIGHT = 512u; +const Size FontClient::DEFAULT_TEXT_ATLAS_SIZE(DEFAULT_TEXT_ATLAS_WIDTH, DEFAULT_TEXT_ATLAS_HEIGHT); + +//Maximum atlas block +const uint32_t FontClient::MAX_TEXT_ATLAS_WIDTH = 1024u; +const uint32_t FontClient::MAX_TEXT_ATLAS_HEIGHT = 1024u; +const Size FontClient::MAX_TEXT_ATLAS_SIZE(MAX_TEXT_ATLAS_WIDTH, MAX_TEXT_ATLAS_HEIGHT); + +//MAX_WIDTH_FIT_IN_ATLAS: blockWidth + 2 * DOUBLE_PIXEL_PADDING + 1u <= atlasWidth +//MAX_HEIGHT_FIT_IN_ATLAS: blockHeight + 2 * DOUBLE_PIXEL_PADDING + 1u <= atlasHeight +const uint16_t FontClient::PADDING_TEXT_ATLAS_BLOCK = 5u; // 2 * DOUBLE_PIXEL_PADDING + 1u + +//Maximum block size to fit into atlas block +const Size FontClient::MAX_SIZE_FIT_IN_ATLAS(MAX_TEXT_ATLAS_WIDTH - PADDING_TEXT_ATLAS_BLOCK, MAX_TEXT_ATLAS_HEIGHT - PADDING_TEXT_ATLAS_BLOCK ); + +const uint32_t FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE = 64u;//Found this value from toolkit + FontClient::GlyphBufferData::GlyphBufferData() : buffer{nullptr}, width{0u}, @@ -235,6 +255,41 @@ GlyphIndex FontClient::CreateEmbeddedItem(const EmbeddedItemDescription& descrip return GetImplementation(*this).CreateEmbeddedItem(description, pixelFormat); } +void FontClient::EnableAtlasLimitation(bool enabled) +{ + return GetImplementation(*this).EnableAtlasLimitation(enabled); +} + +bool FontClient::IsAtlasLimitationEnabled() const +{ + return GetImplementation(*this).IsAtlasLimitationEnabled( ); +} + +Size FontClient::GetMaximumTextAtlasSize() const +{ + return GetImplementation(*this).GetMaximumTextAtlasSize( ); +} + +Size FontClient::GetDefaultTextAtlasSize() const +{ + return GetImplementation(*this).GetDefaultTextAtlasSize( ); +} + +Size FontClient::GetCurrentMaximumBlockSizeFitInAtlas() const +{ + return GetImplementation(*this).GetCurrentMaximumBlockSizeFitInAtlas( ); +} + +bool FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas) +{ + return GetImplementation(*this).SetCurrentMaximumBlockSizeFitInAtlas(currentMaximumBlockSizeFitInAtlas); +} + +uint32_t FontClient::GetNumberOfPointsPerOneUnitOfPointSize() const +{ + return GetImplementation(*this).GetNumberOfPointsPerOneUnitOfPointSize(); +} + FontClient::FontClient(Internal::FontClient* internal) : BaseHandle(internal) { diff --git a/dali/devel-api/text-abstraction/font-client.h b/dali/devel-api/text-abstraction/font-client.h index 92c8390..e77b53f 100644 --- a/dali/devel-api/text-abstraction/font-client.h +++ b/dali/devel-api/text-abstraction/font-client.h @@ -64,6 +64,22 @@ public: static const PointSize26Dot6 DEFAULT_POINT_SIZE; ///< The default point size. static const float DEFAULT_ITALIC_ANGLE; ///< The default software italic angle in radians. + static const bool DEFAULT_ATLAS_LIMITATION_ENABLED; ///< The default behavior of whether atlas limitation is enabled in dali. + static const uint32_t DEFAULT_TEXT_ATLAS_WIDTH; ///< The default width of text-atlas-block. + static const uint32_t DEFAULT_TEXT_ATLAS_HEIGHT; ///< The default height of text-atlas-block. + static const Size DEFAULT_TEXT_ATLAS_SIZE; ///< The default size(width, height) of text-atlas-block. + + static const uint32_t MAX_TEXT_ATLAS_WIDTH; ///< The maximum width of text-atlas-block. + static const uint32_t MAX_TEXT_ATLAS_HEIGHT; ///< The maximum height of text-atlas-block. + static const Size MAX_TEXT_ATLAS_SIZE; ///< The maximum height of text-atlas-block. + + static const uint16_t PADDING_TEXT_ATLAS_BLOCK ; ///< Padding per edge. How much the block size (width, height) less than the text-atlas-block size (width, height). + static const Size MAX_SIZE_FIT_IN_ATLAS; ///< The maximum block's size fit into text-atlas-block. + + static const uint32_t NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE; ///< Factor multiply point-size in toolkit. + + + /** * @brief Struct used to retrieve the glyph's bitmap. */ @@ -468,6 +484,63 @@ public: */ GlyphIndex CreateEmbeddedItem(const EmbeddedItemDescription& description, Pixel::Format& pixelFormat); + /** + * @brief true to enable Atlas-Limitation. + * + * @note Used default configuration. + * @param[in] enabled The on/off value to enable/disable Atlas-Limitation. + */ + void EnableAtlasLimitation(bool enabled); + + /** + * @brief Check Atlas-Limitation is enabled or disabled. + * + * @note Used default configuration. + * return true if Atlas-Limitation is enabled, otherwise false. + */ + bool IsAtlasLimitationEnabled() const; + + /** + * @brief retrieve the maximum allowed width and height for text-atlas-block. + * + * @note Used default configuration. + * return the maximum width and height of text-atlas-block. + */ + Size GetMaximumTextAtlasSize() const; + + /** + * @brief retrieve the default width and height for text-atlas-block. + * + * @note Used default configuration. + * return the default width and height of text-atlas-block. + */ + Size GetDefaultTextAtlasSize() const; + + /** + * @brief retrieve the current maximum width and height for text-atlas-block. + * + * @note Used default configuration. + * return the current maximum width and height of text-atlas-block. + */ + Size GetCurrentMaximumBlockSizeFitInAtlas() const; + + /** + * @brief set the achieved size (width and height) for text-atlas-block. + * If @p currentMaximumBlockSizeFitInAtlas larger than the current maximum text atlas then store, otherwise ignore. + * + * @note Used default configuration. + * return true if the current maximum text atlas size is changed, otherwise false. + */ + bool SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas); + + /** + * @brief retrieve the number of points to scale-up one unit of point-size. + * + * @note Used default configuration. + * return the number of points per one unit of point-size + */ + uint32_t GetNumberOfPointsPerOneUnitOfPointSize() const; + public: // Not intended for application developers /** * @brief This constructor is used by FontClient::Get(). diff --git a/dali/internal/text/text-abstraction/font-client-impl.cpp b/dali/internal/text/text-abstraction/font-client-impl.cpp index 3f3bedb..d708d85 100644 --- a/dali/internal/text/text-abstraction/font-client-impl.cpp +++ b/dali/internal/text/text-abstraction/font-client-impl.cpp @@ -333,6 +333,63 @@ GlyphIndex FontClient::CreateEmbeddedItem(const TextAbstraction::FontClient::Emb return mPlugin->CreateEmbeddedItem(description, pixelFormat); } +void FontClient::EnableAtlasLimitation(bool enabled) +{ + CreatePlugin(); + return mPlugin->EnableAtlasLimitation(enabled); +} + +bool FontClient::IsAtlasLimitationEnabled() const +{ + if(mPlugin) + { + return mPlugin->IsAtlasLimitationEnabled(); + } + return TextAbstraction::FontClient::DEFAULT_ATLAS_LIMITATION_ENABLED; +} + +Size FontClient::GetMaximumTextAtlasSize() const +{ + if(mPlugin) + { + return mPlugin->GetMaximumTextAtlasSize(); + } + return TextAbstraction::FontClient::MAX_TEXT_ATLAS_SIZE; +} + +Size FontClient::GetDefaultTextAtlasSize() const +{ + if(mPlugin) + { + return mPlugin->GetDefaultTextAtlasSize(); + } + return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE; +} + +Size FontClient::GetCurrentMaximumBlockSizeFitInAtlas() const +{ + if(mPlugin) + { + return mPlugin->GetCurrentMaximumBlockSizeFitInAtlas(); + } + return TextAbstraction::FontClient::DEFAULT_TEXT_ATLAS_SIZE; +} + +bool FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas) +{ + CreatePlugin(); + return mPlugin->SetCurrentMaximumBlockSizeFitInAtlas(currentMaximumBlockSizeFitInAtlas); +} + +uint32_t FontClient::GetNumberOfPointsPerOneUnitOfPointSize() const +{ + if(mPlugin) + { + return mPlugin->GetNumberOfPointsPerOneUnitOfPointSize(); + } + return TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;; +} + FT_FaceRec_* FontClient::GetFreetypeFace(FontId fontId) { CreatePlugin(); diff --git a/dali/internal/text/text-abstraction/font-client-impl.h b/dali/internal/text/text-abstraction/font-client-impl.h index de6b99f..07eea78 100644 --- a/dali/internal/text/text-abstraction/font-client-impl.h +++ b/dali/internal/text/text-abstraction/font-client-impl.h @@ -219,6 +219,41 @@ public: GlyphIndex CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat); /** + * @copydoc Dali::TextAbstraction::FontClient::EnableAtlasLimitation(bool enabled) + */ + void EnableAtlasLimitation(bool enabled); + + /** + * @copydoc Dali::TextAbstraction::FontClient::IsAtlasLimitationEnabled() + */ + bool IsAtlasLimitationEnabled() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetMaximumTextAtlasSize() + */ + Size GetMaximumTextAtlasSize() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetDefaultTextAtlasSize() + */ + Size GetDefaultTextAtlasSize() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetCurrentMaximumBlockSizeFitInAtlas() + */ + Size GetCurrentMaximumBlockSizeFitInAtlas() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas) + */ + bool SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas); + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetNumberOfPointsPerOneUnitOfPointSize() + */ + uint32_t GetNumberOfPointsPerOneUnitOfPointSize() const; + + /** * @brief Retrieves the pointer to the FreeType Font Face for the given @p fontId. * * @param[in] fontId The font id. diff --git a/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp b/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp index 5bf652c..60deca8 100644 --- a/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp +++ b/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp @@ -154,6 +154,126 @@ void DestroyCharacterSets(CharacterSetList& characterSets) } } +/** + * @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(ftFace->size->metrics.height) * FROM_266 <= maxSizeFitInAtlas.height + && (static_cast(ftFace->size->metrics.ascender)-static_cast(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}, @@ -247,7 +367,10 @@ FontClient::Plugin::Plugin(unsigned int horizontalDpi, mVectorFontCache(nullptr), mEllipsisCache(), mEmbeddedItemCache(), - mDefaultFontDescriptionCached(false) + 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) @@ -1882,6 +2005,54 @@ GlyphIndex FontClient::Plugin::CreateEmbeddedItem(const TextAbstraction::FontCli 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() { @@ -2198,11 +2369,29 @@ FontId FontClient::Plugin::CreateFont(const FontPath& path, } else { - error = FT_Set_Char_Size(ftFace, + 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) { diff --git a/dali/internal/text/text-abstraction/font-client-plugin-impl.h b/dali/internal/text/text-abstraction/font-client-plugin-impl.h index 1449e49..fb3569a 100644 --- a/dali/internal/text/text-abstraction/font-client-plugin-impl.h +++ b/dali/internal/text/text-abstraction/font-client-plugin-impl.h @@ -391,6 +391,41 @@ struct FontClient::Plugin GlyphIndex CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat); /** + * @copydoc Dali::TextAbstraction::FontClient::EnableAtlasLimitation(bool enabled) + */ + void EnableAtlasLimitation(bool enabled); + + /** + * @copydoc Dali::TextAbstraction::FontClient::IsAtlasLimitationEnabled() + */ + bool IsAtlasLimitationEnabled() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetMaximumTextAtlasSize() + */ + Size GetMaximumTextAtlasSize() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetDefaultTextAtlasSize() + */ + Size GetDefaultTextAtlasSize() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetCurrentMaximumBlockSizeFitInAtlas() + */ + Size GetCurrentMaximumBlockSizeFitInAtlas() const; + + /** + * @copydoc Dali::TextAbstraction::FontClient::SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas) + */ + bool SetCurrentMaximumBlockSizeFitInAtlas(const Size& currentMaximumBlockSizeFitInAtlas); + + /** + * @copydoc Dali::TextAbstraction::FontClient::GetNumberOfPointsPerOneUnitOfPointSize() + */ + uint32_t GetNumberOfPointsPerOneUnitOfPointSize() const; + + /** * @copydoc Dali::TextAbstraction::Internal::FontClient::GetFreetypeFace() */ FT_FaceRec_* GetFreetypeFace(FontId fontId); @@ -649,6 +684,9 @@ private: std::vector mBitmapFontCache; ///< Stores bitmap fonts. bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not + + bool mIsAtlasLimitationEnabled : 1; ///< Whether the validation on maximum atlas block size, then reduce block size to fit into it is enabled or not. + Vector2 mCurrentMaximumBlockSizeFitInAtlas; ///< The current maximum size (width, height) of text-atlas-block. }; } // namespace Internal