const float POINTS_PER_INCH = 72.f;
/**
+ * @brief Maximum rate of bitmap glyph resize.
+ * If scale factor is bigger than this value, we will not cache resized glyph.
+ * Else, resize bitmap glyph itself and cache it.
+ */
+constexpr float MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE = 1.5f;
+
+/**
* @brief Maximum size of glyph cache per each font face.
*/
constexpr std::size_t DEFAULT_GLYPH_CACHE_MAX = 128;
if(mIsFixedSizeBitmap)
{
FT_Select_Size(mFreeTypeFace, mFixedSizeIndex); ///< @todo: needs to be investigated why it's needed to select the size again.
- mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_COLOR, false, glyphData, error);
+ mGlyphCacheManager->GetGlyphCacheDataFromIndex(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, glyphData, error);
if(FT_Err_Ok == error)
{
glyphInfo.yBearing = round(glyphInfo.yBearing * scaleFactor);
glyphInfo.scaleFactor = scaleFactor;
+
+ if(scaleFactor < MAXIMUM_RATE_OF_BITMAP_GLYPH_CACHE_RESIZE)
+ {
+ // Resize bitmap glyph and cache it due to the performance issue.
+ // If scaleFactor is too big, cached bitmap may hold too big memory.
+ // So, we only hold small enough case.
+
+ // TODO : If dpiVertical value changed, this resize feature will be break down.
+ // Otherwise, this glyph will be resized only one times.
+ mGlyphCacheManager->ResizeBitmapGlyph(glyphInfo.index, FT_LOAD_COLOR, glyphInfo.isBoldRequired, static_cast<uint32_t>(glyphInfo.width), static_cast<uint32_t>(glyphInfo.height));
+ }
}
}
else
* limitations under the License.
*/
+// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
#include <dali/internal/text/text-abstraction/plugin/font-client-utils.h>
#include <dali/internal/text/text-abstraction/plugin/font-face-glyph-cache-manager.h>
+
+// EXTERNAL INCLUDES
#include FT_BITMAP_H
#if defined(DEBUG_ENABLED)
return false;
}
+void GlyphCacheManager::ResizeBitmapGlyph(
+ const GlyphIndex& index,
+ const FT_Int32& flag,
+ const bool& isBoldRequired,
+ const uint32_t& desiredWidth,
+ const uint32_t& desiredHeight)
+{
+ FT_Error error;
+ GlyphCacheData originGlyphData;
+ if(GetGlyphCacheDataFromIndex(index, flag, isBoldRequired, originGlyphData, error))
+ {
+ if(DALI_LIKELY(originGlyphData.mIsBitmap && originGlyphData.mBitmap))
+ {
+ const bool requiredResize = (originGlyphData.mBitmap->rows != desiredHeight) || (originGlyphData.mBitmap->width != desiredWidth);
+ if(requiredResize)
+ {
+ const GlyphCacheKey key = GlyphCacheKey(index, flag, isBoldRequired);
+ auto iter = mLRUGlyphCache.Find(key);
+
+ GlyphCacheData& destinationGlpyhData = iter->element;
+
+ const ImageDimensions inputDimensions(destinationGlpyhData.mBitmap->width, destinationGlpyhData.mBitmap->rows);
+ const ImageDimensions desiredDimensions(desiredWidth, desiredHeight);
+
+ uint8_t* desiredBuffer = nullptr;
+
+ switch(destinationGlpyhData.mBitmap->pixel_mode)
+ {
+ case FT_PIXEL_MODE_GRAY:
+ {
+ if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width))
+ {
+ desiredBuffer = new uint8_t[desiredWidth * desiredHeight];
+ // Resize bitmap here.
+ Dali::Internal::Platform::LanczosSample1BPP(destinationGlpyhData.mBitmap->buffer,
+ inputDimensions,
+ destinationGlpyhData.mBitmap->width,
+ desiredBuffer,
+ desiredDimensions);
+ }
+ break;
+ }
+#ifdef FREETYPE_BITMAP_SUPPORT
+ case FT_PIXEL_MODE_BGRA:
+ {
+ if(destinationGlpyhData.mBitmap->pitch == static_cast<int>(destinationGlpyhData.mBitmap->width << 2u))
+ {
+ desiredBuffer = new uint8_t[(desiredWidth * desiredHeight) << 2u];
+ // Resize bitmap here.
+ Dali::Internal::Platform::LanczosSample4BPP(destinationGlpyhData.mBitmap->buffer,
+ inputDimensions,
+ destinationGlpyhData.mBitmap->width,
+ desiredBuffer,
+ desiredDimensions);
+ }
+ break;
+ }
+#endif
+ default:
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, "FontClient::Plugin::GlyphCacheManager::ResizeBitmapGlyph. FontClient Unable to create Bitmap of this PixelType\n");
+ break;
+ }
+ }
+
+ if(desiredBuffer)
+ {
+ // Success to resize bitmap glyph.
+ // Release origin bitmap buffer.
+ delete[] destinationGlpyhData.mBitmap->buffer;
+
+ // Replace as desired buffer and size.
+ destinationGlpyhData.mBitmap->buffer = desiredBuffer;
+ destinationGlpyhData.mBitmap->width = desiredWidth;
+ destinationGlpyhData.mBitmap->rows = desiredHeight;
+ switch(destinationGlpyhData.mBitmap->pixel_mode)
+ {
+ case FT_PIXEL_MODE_GRAY:
+ {
+ destinationGlpyhData.mBitmap->pitch = desiredWidth;
+ break;
+ }
+#ifdef FREETYPE_BITMAP_SUPPORT
+ case FT_PIXEL_MODE_BGRA:
+ {
+ destinationGlpyhData.mBitmap->pitch = desiredWidth << 2u;
+ break;
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+}
+
void GlyphCacheManager::GlyphCacheData::ReleaseGlyphData()
{
if(mIsBitmap && mBitmap)
FT_Error& error);
/**
- * @brief Load GlyphCacheData from face. The result will be cached.
+ * @brief Load GlyphCacheData from face. The result will not be cached.
* @note If we call this API, We should release GlyphCacheData manually.
*
* @param[in] index Index of glyph in this face.
GlyphCacheData& data,
FT_Error& error);
+ /**
+ * @brief Resize bitmap glyph. The result will change cached glyph bitmap information.
+ * If glyph is not bitmap glyph, nothing happened.
+ *
+ * @param[in] index Index of glyph in this face.
+ * @param[in] flag Flag when we load the glyph.
+ * @param[in] isBoldRequired True if we require some software bold.
+ * @param[in] desiredWidth Desired width of bitmap.
+ * @param[in] desiredHeight Desired height of bitmap.
+ */
+ void ResizeBitmapGlyph(
+ const GlyphIndex& index,
+ const FT_Int32& flag,
+ const bool& isBoldRequired,
+ const uint32_t& desiredWidth,
+ const uint32_t& desiredHeight);
+
private:
// Private struct area.
/**