GlyphBufferData did a lot of process.
Since that struct job has more line than FontClient itself,
seperate new cpp file for it.
Change-Id: I85a2c9a1b011ef6d5455cc7d93ac11348b59e6e0
Signed-off-by: Eunki Hong <eunkiki.hong@samsung.com>
// 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;
+ uint32_t pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ TextAbstraction::FontId fontId200 = fontClient.GetFontId(fontDescription, pointSize200);
+ TextAbstraction::GlyphBufferData glyphBufferData200;
glyphBufferData200.width = 0;
glyphBufferData200.height = 0;
fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0);
// 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;
+ TextAbstraction::FontId fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000);
+ TextAbstraction::GlyphBufferData glyphBufferData1000;
glyphBufferData1000.width = 0;
glyphBufferData1000.height = 0;
fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0);
// 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;
+ TextAbstraction::FontId fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000);
+ TextAbstraction::GlyphBufferData glyphBufferData2000;
glyphBufferData2000.width = 0;
glyphBufferData2000.height = 0;
fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0);
// 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;
+ uint32_t pointSize200 = 200 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ TextAbstraction::FontId fontId200 = fontClient.GetFontId(fontDescription, pointSize200);
+ TextAbstraction::GlyphBufferData glyphBufferData200;
glyphBufferData200.width = 0;
glyphBufferData200.height = 0;
fontClient.CreateBitmap(fontId200, 68, false, false, glyphBufferData200, 0);
// 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;
+ uint32_t pointSize1000 = 1000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ TextAbstraction::FontId fontId1000 = fontClient.GetFontId(fontDescription, pointSize1000);
+ TextAbstraction::GlyphBufferData glyphBufferData1000;
glyphBufferData1000.width = 0;
glyphBufferData1000.height = 0;
fontClient.CreateBitmap(fontId1000, 68, false, false, glyphBufferData1000, 0);
// 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;
+ uint32_t pointSize2000 = 2000 * TextAbstraction::FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE;
+ TextAbstraction::FontId fontId2000 = fontClient.GetFontId(fontDescription, pointSize2000);
+ TextAbstraction::GlyphBufferData glyphBufferData2000;
glyphBufferData2000.width = 0;
glyphBufferData2000.height = 0;
fontClient.CreateBitmap(fontId2000, 68, false, false, glyphBufferData2000, 0);
DALI_TEST_GREATER(glyphBufferData2000.height, 1024u, TEST_LOCATION); //1148u
// Test GlyphBufferData move
- TextAbstraction::FontClient::GlyphBufferData movedGlyphBufferData2000 = std::move(glyphBufferData2000);
+ TextAbstraction::GlyphBufferData movedGlyphBufferData2000 = std::move(glyphBufferData2000);
for(int i = 0; i < 50; ++i)
{
- TextAbstraction::FontClient::GlyphBufferData dummy = std::move(movedGlyphBufferData2000);
+ TextAbstraction::GlyphBufferData dummy = std::move(movedGlyphBufferData2000);
movedGlyphBufferData2000 = std::move(dummy);
// Test moved GlyphBufferData destruct well
${adaptor_devel_api_dir}/text-abstraction/font-client.cpp
${adaptor_devel_api_dir}/text-abstraction/font-list.cpp
${adaptor_devel_api_dir}/text-abstraction/font-metrics.cpp
+ ${adaptor_devel_api_dir}/text-abstraction/glyph-buffer-data.cpp
${adaptor_devel_api_dir}/text-abstraction/glyph-info.cpp
${adaptor_devel_api_dir}/text-abstraction/script.cpp
${adaptor_devel_api_dir}/text-abstraction/segmentation.cpp
${adaptor_devel_api_dir}/text-abstraction/font-client.h
${adaptor_devel_api_dir}/text-abstraction/font-list.h
${adaptor_devel_api_dir}/text-abstraction/font-metrics.h
+ ${adaptor_devel_api_dir}/text-abstraction/glyph-buffer-data.h
${adaptor_devel_api_dir}/text-abstraction/glyph-info.h
${adaptor_devel_api_dir}/text-abstraction/script.h
${adaptor_devel_api_dir}/text-abstraction/segmentation.h
#include <dali/devel-api/text-abstraction/font-client.h>
// INTERNAL INCLUDES
-#include <dali/internal/imaging/common/image-operations.h>
#include <dali/internal/text/text-abstraction/font-client-impl.h>
namespace Dali
{
namespace TextAbstraction
{
+// FontClient static const value definition.
+
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).
const uint32_t FontClient::NUMBER_OF_POINTS_PER_ONE_UNIT_OF_POINT_SIZE = 64u; //Found this value from toolkit
-// FontClient::GlyphBufferData
-
-FontClient::GlyphBufferData::GlyphBufferData()
-: buffer{nullptr},
- width{0u},
- height{0u},
- outlineOffsetX{0},
- outlineOffsetY{0},
- format{Pixel::A8},
- compressionType{CompressionType::NO_COMPRESSION},
- isColorEmoji{false},
- isColorBitmap{false},
- isBufferOwned{false}
-{
-}
-
-FontClient::GlyphBufferData::~GlyphBufferData()
-{
- if(isBufferOwned)
- {
- free(buffer);
- }
-}
-
-FontClient::GlyphBufferData::GlyphBufferData(FontClient::GlyphBufferData&& rhs) noexcept
-: buffer{rhs.buffer},
- width{rhs.width},
- height{rhs.height},
- outlineOffsetX{rhs.outlineOffsetX},
- outlineOffsetY{rhs.outlineOffsetY},
- format{rhs.format},
- compressionType{rhs.compressionType},
- isColorEmoji{rhs.isColorEmoji},
- isColorBitmap{rhs.isColorBitmap},
- isBufferOwned{rhs.isBufferOwned}
-{
- // Remove moved data
- rhs.buffer = nullptr;
- rhs.isBufferOwned = false;
-}
-
-FontClient::GlyphBufferData& FontClient::GlyphBufferData::operator=(FontClient::GlyphBufferData&& rhs) noexcept
-{
- buffer = rhs.buffer;
- width = rhs.width;
- height = rhs.height;
- outlineOffsetX = rhs.outlineOffsetX;
- outlineOffsetY = rhs.outlineOffsetY;
- format = rhs.format;
- compressionType = rhs.compressionType;
- isColorEmoji = rhs.isColorEmoji;
- isColorBitmap = rhs.isColorBitmap;
- isBufferOwned = rhs.isBufferOwned;
-
- // Remove moved data
- rhs.buffer = nullptr;
- rhs.isBufferOwned = false;
-
- return *this;
-}
-
-size_t FontClient::GlyphBufferData::Compress(const uint8_t* const __restrict__ inBuffer, GlyphBufferData& __restrict__ outBufferData)
-{
- size_t bufferSize = 0u;
- uint8_t*& __restrict__ compressedBuffer = outBufferData.buffer;
- switch(outBufferData.compressionType)
- {
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
- {
- bufferSize = static_cast<size_t>(outBufferData.width) * static_cast<size_t>(outBufferData.height) * static_cast<size_t>(Pixel::GetBytesPerPixel(outBufferData.format));
-
- compressedBuffer = (uint8_t*)malloc(bufferSize);
- if(DALI_UNLIKELY(compressedBuffer == nullptr))
- {
- return 0u;
- }
- outBufferData.isBufferOwned = true;
-
- // Copy buffer without compress
- memcpy(compressedBuffer, inBuffer, bufferSize);
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
- {
- const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
- const uint32_t componentCount = (widthByte >> 1);
- const bool considerPadding = (widthByte & 1) ? true : false;
-
- // For BIT_PER_PIXEL_4 type, we can know final compressed buffer size immediatly.
- bufferSize = static_cast<size_t>(outBufferData.height) * static_cast<size_t>(componentCount + (considerPadding ? 1 : 0));
- compressedBuffer = (uint8_t*)malloc(bufferSize);
- if(DALI_UNLIKELY(compressedBuffer == nullptr))
- {
- return 0u;
- }
- outBufferData.isBufferOwned = true;
-
- uint8_t* __restrict__ outBufferPtr = compressedBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBuffer;
-
- // Compress for each line
- for(uint32_t y = 0; y < outBufferData.height; ++y)
- {
- for(uint32_t x = 0; x < componentCount; ++x)
- {
- const uint8_t v0 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
- const uint8_t v1 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
-
- *(outBufferPtr++) = (v0 << 4) | v1;
- }
- if(considerPadding)
- {
- *(outBufferPtr++) = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
- }
- }
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
- {
- const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
-
- // Allocate temperal buffer. Note that RLE4 can be bigger than original buffer.
- uint8_t* __restrict__ tempBuffer = (uint8_t*)malloc(outBufferData.height * (widthByte + 1));
- if(DALI_UNLIKELY(tempBuffer == nullptr))
- {
- return 0u;
- }
-
- uint8_t* __restrict__ outBufferPtr = tempBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBuffer;
-
- bufferSize = 0u;
-
- // Compress for each line
- for(uint32_t y = 0; y < outBufferData.height; ++y)
- {
- uint32_t encodedByte = 0;
- while(encodedByte < widthByte)
- {
- // Case 1 : Remain only 1 byte
- if(DALI_UNLIKELY(encodedByte + 1 == widthByte))
- {
- const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
- *(outBufferPtr++) = v0;
- ++encodedByte;
- ++bufferSize;
- }
- // Case 2 : Remain only 2 byte
- else if(DALI_UNLIKELY(encodedByte + 2 == widthByte))
- {
- const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
- const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
- encodedByte += 2;
- if(v0 == v1)
- {
- *(outBufferPtr++) = 0x80 | v0;
- ++bufferSize;
- }
- else
- {
- *(outBufferPtr++) = 0x10 | v0;
- *(outBufferPtr++) = v1 << 4;
- bufferSize += 2;
- }
- }
- // Case 3 : Normal case. Remain byte bigger or equal than 3.
- else
- {
- // Compress rule -
- // Read 2 byte as v0 and v1.
- // - If v0 == v1, We can compress. mark the first bit as 1. and remain 3 bit mark as the "runLength - 2".
- // runLength can be maximum 9.
- // - If v0 != v1, We cannot compress. mark the first bit as 0. and remain 3 bit mark as the "(nonRunLength - 1) / 2"
- // Due to the BitPerPixel is 4, nonRunLength should be odd value.
- // nonRunLength cutted if v0 == v1.
- // nonRunLength can be maximum 15.
-
- const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
- const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
- encodedByte += 2;
- // We can compress by RLE
- if(v0 == v1)
- {
- uint8_t runLength = 2;
- while(encodedByte < widthByte && runLength < 9)
- {
- const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v2 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prev2) & 0x0f; // Intented underflow
- if(v2 == v0)
- {
- ++inBufferPtr;
- ++encodedByte;
- ++runLength;
- }
- else
- {
- break;
- }
- }
-
- // Update (runLength - 2) result.
- *(outBufferPtr++) = ((0x8 | (runLength - 2)) << 4) | v0;
- ++bufferSize;
- }
- // We cannot compress by RLE.
- else
- {
- // Read one more value.
- const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t v2 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev2) & 0x0f; // Intented underflow
- ++encodedByte;
-
- uint8_t nonRunLength = 3;
- uint8_t* nonRunLengthHeaderPtr = outBufferPtr;
- *(outBufferPtr++) = v0;
- *(outBufferPtr++) = (v1 << 4) | v2;
- bufferSize += 2;
- while(encodedByte < widthByte && nonRunLength < 15)
- {
- if(DALI_LIKELY(encodedByte + 1 < widthByte))
- {
- const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t w0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
- const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1 - widthByte));
- const uint8_t w1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1)) - prew1) & 0x0f; // Intented underflow
- if(w0 == w1)
- {
- // Stop non-compress logic.
- break;
- }
- else
- {
- ++bufferSize;
- *(outBufferPtr++) = (w0 << 4) | w1;
- inBufferPtr += 2;
- encodedByte += 2;
- nonRunLength += 2;
- }
- }
- else
- {
- // Edge case. There is only one pixel remained.
- const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
- const uint8_t w0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
- {
- ++bufferSize;
- *(outBufferPtr++) = (w0 << 4);
- ++encodedByte;
- ++inBufferPtr;
- // Increase nonRunLength 2 even latest value is invalid.
- nonRunLength += 2;
- }
- }
- }
-
- // Update (nonRunLength-1)/2 result into header.
- *(nonRunLengthHeaderPtr) |= (nonRunLength >> 1) << 4;
- }
- }
- }
- }
-
- // Allocate and copy data
- compressedBuffer = (uint8_t*)malloc(bufferSize);
- if(DALI_UNLIKELY(compressedBuffer == nullptr))
- {
- free(tempBuffer);
- return 0u;
- }
- outBufferData.isBufferOwned = true;
-
- memcpy(compressedBuffer, tempBuffer, bufferSize);
- free(tempBuffer);
-
- break;
- }
- default:
- {
- break;
- }
- }
-
- return bufferSize;
-}
-
-void FontClient::GlyphBufferData::Decompress(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer)
-{
- if(DALI_UNLIKELY(outBuffer == nullptr))
- {
- return;
- }
-
- switch(inBufferData.compressionType)
- {
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
- {
- const auto bufferSize = inBufferData.width * inBufferData.height * Pixel::GetBytesPerPixel(inBufferData.format);
-
- // Copy buffer without compress
- memcpy(outBuffer, inBufferData.buffer, bufferSize);
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
- {
- const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
- const uint32_t componentCount = (widthByte >> 1);
- const bool considerPadding = (widthByte & 1) ? true : false;
-
- uint8_t* __restrict__ outBufferPtr = outBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
-
- // Compress for each line
- for(uint32_t y = 0; y < inBufferData.height; ++y)
- {
- for(uint32_t x = 0; x < componentCount; ++x)
- {
- const uint8_t v = *(inBufferPtr++);
- const uint8_t v0 = (v >> 4) & 0x0f;
- const uint8_t v1 = v & 0x0f;
-
- *(outBufferPtr++) = (v0 << 4) | v0;
- *(outBufferPtr++) = (v1 << 4) | v1;
- }
- if(considerPadding)
- {
- const uint8_t v = *(inBufferPtr++);
- *(outBufferPtr++) = (v << 4) | v;
- }
- }
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
- {
- const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
- uint8_t* __restrict__ outBufferPtr = outBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
- // Compress for each line
- for(uint32_t y = 0; y < inBufferData.height; ++y)
- {
- uint32_t x = 0;
- uint32_t decodedByte = 0;
- while(decodedByte < widthByte)
- {
- const uint8_t v = *(inBufferPtr++);
- ++x;
- // Compress by RLE
- if(v & 0x80)
- {
- const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
- decodedByte += runLength;
- const uint8_t repeatValue = v & 0x0f;
- for(uint8_t iter = 0; iter < runLength; ++iter)
- {
- const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
- const uint8_t v0 = (prev0 + repeatValue) & 0x0f;
- *(outBufferPtr++) = (v0 << 4) | v0;
- }
- }
- // Not compress by RLE
- else
- {
- const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
- decodedByte += nonRunLength;
- // First value.
- const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
- const uint8_t v0 = (prev0 + (v & 0x0f)) & 0x0f;
- *(outBufferPtr++) = (v0 << 4) | v0;
-
- const bool ignoreLastValue = decodedByte > widthByte ? true : false;
- if(DALI_UNLIKELY(ignoreLastValue))
- {
- --decodedByte;
- for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
- {
- const uint8_t w = *(inBufferPtr++);
- const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
- const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
- const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
- const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
- ++x;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- *(outBufferPtr++) = (w1 << 4) | w1;
- }
- // Last value.
- {
- const uint8_t w = ((*(inBufferPtr++)) >> 4) & 0x0f;
- const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
- const uint8_t w0 = (prew0 + w) & 0x0f;
- ++x;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- }
- }
- else
- {
- for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
- {
- const uint8_t w = *(inBufferPtr++);
- const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
- const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
- const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
- const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
- ++x;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- *(outBufferPtr++) = (w1 << 4) | w1;
- }
- }
- }
- }
- }
- break;
- }
- default:
- {
- break;
- }
- }
-}
-
-void FontClient::GlyphBufferData::DecompressScanline(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer, uint32_t& __restrict__ offset)
-{
- switch(inBufferData.compressionType)
- {
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION:
- {
- const auto bufferSize = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
- // Copy buffer without compress
- memcpy(outBuffer, inBufferData.buffer + offset, bufferSize);
-
- // Update offset
- offset += bufferSize;
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4:
- {
- const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
- const uint32_t componentCount = (widthByte >> 1);
- const bool considerPadding = (widthByte & 1) ? true : false;
-
- uint8_t* __restrict__ outBufferPtr = outBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
-
- // Decompress scanline
- for(uint32_t x = 0; x < componentCount; ++x)
- {
- const uint8_t v = *(inBufferPtr++);
- const uint8_t v0 = (v >> 4) & 0x0f;
- const uint8_t v1 = v & 0x0f;
-
- *(outBufferPtr++) = (v0 << 4) | v0;
- *(outBufferPtr++) = (v1 << 4) | v1;
- }
- if(considerPadding)
- {
- const uint8_t v = *(inBufferPtr++);
- *(outBufferPtr++) = (v << 4) | v;
- }
-
- // Update offset
- offset += (widthByte + 1u) >> 1u;
- break;
- }
- case TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4:
- {
- const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
-
- uint8_t* __restrict__ outBufferPtr = outBuffer;
- const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
-
- // If offset is zero, fill outBuffer as 0 first.
- if(DALI_UNLIKELY(offset == 0))
- {
- memset(outBufferPtr, 0, widthByte);
- }
-
- // Decompress scanline
- uint32_t decodedByte = 0;
- while(decodedByte < widthByte)
- {
- const uint8_t v = *(inBufferPtr++);
- ++offset;
- // Compress by RLE
- if(v & 0x80)
- {
- const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
- decodedByte += runLength;
- const uint8_t repeatValue = (v & 0x0f);
- for(uint8_t iter = 0; iter < runLength; ++iter)
- {
- const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
- const uint8_t v0 = (prev0 + repeatValue) & 0x0f;
- *(outBufferPtr++) = (v0 << 4) | v0;
- }
- }
- // Not compress by RLE
- else
- {
- const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
- decodedByte += nonRunLength;
- // First value.
- const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
- const uint8_t v0 = (prev0 + (v & 0x0f)) & 0x0f;
- *(outBufferPtr++) = (v0 << 4) | v0;
-
- const bool ignoreLastValue = decodedByte > widthByte ? true : false;
- if(DALI_UNLIKELY(ignoreLastValue))
- {
- --decodedByte;
- for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
- {
- const uint8_t w = *(inBufferPtr++);
- const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
- const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
- const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
- const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
- ++offset;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- *(outBufferPtr++) = (w1 << 4) | w1;
- }
- // Last value.
- {
- const uint8_t w = ((*(inBufferPtr++)) >> 4) & 0x0f;
- const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
- const uint8_t w0 = (prew0 + w) & 0x0f;
- ++offset;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- }
- }
- else
- {
- for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
- {
- const uint8_t w = *(inBufferPtr++);
- const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
- const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
- const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
- const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
- ++offset;
-
- *(outBufferPtr++) = (w0 << 4) | w0;
- *(outBufferPtr++) = (w1 << 4) | w1;
- }
- }
- }
- }
- break;
- }
- default:
- {
- break;
- }
- }
-}
-
// FontClient
FontClient FontClient::Get()
// INTERNAL INCLUDES
#include <dali/devel-api/text-abstraction/font-list.h>
+#include <dali/devel-api/text-abstraction/glyph-buffer-data.h>
#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/dali-adaptor-common.h>
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.
- */
- struct DALI_ADAPTOR_API GlyphBufferData
- {
- /**
- * @brief Constructor.
- *
- * Initializes struct members to their defaults.
- */
- GlyphBufferData();
-
- /**
- * @brief Destructor.
- */
- ~GlyphBufferData();
-
- /**
- * @brief Move constructor.
- *
- * @param[in] rhs moved data.
- */
- GlyphBufferData(GlyphBufferData&& rhs) noexcept;
-
- /**
- * @brief Move assign operator.
- *
- * @param[in] rhs moved data.
- * @return A reference to this.
- */
- GlyphBufferData& operator=(GlyphBufferData&& rhs) noexcept;
-
- // Compression method of buffer. Each buffer compressed line by line
- enum class CompressionType
- {
- NO_COMPRESSION = 0, // No compression
- BPP_4 = 1, // Compress as 4 bit. Color become value * 17 (0x00, 0x11, 0x22, ... 0xee, 0xff).
- // Only works for Pixel::L8 format
- RLE_4 = 2, // Compress as 4 bit, and Run-Length-Encode. For more high compress rate, we store difference between previous scanline.
- // Only works for Pixel::L8 format
- };
-
- /**
- * @brief Helper static function to compress raw buffer from inBuffer to outBufferData.buffer.
- * outBufferData will have it's own buffer.
- *
- * @pre outBufferData must not have it's own buffer.
- * @param[in] inBuffer The input raw data.
- * @param[in, out] outBufferData The output glyph buffer data.
- * @return Size of compressed out buffer, Or 0 if compress failed.
- */
- static size_t Compress(const uint8_t* const inBuffer, GlyphBufferData& outBufferData);
-
- /**
- * @brief Helper static function to decompress raw buffer from inBuffer to outBufferPtr.
- * If outBuffer is nullptr, Do nothing.
- *
- * @pre outBuffer memory should be allocated.
- * @param[in] inBufferData The input glyph buffer data.
- * @param[in, out] outBuffer The output pointer of raw buffer data.
- */
- static void Decompress(const GlyphBufferData& inBufferData, uint8_t* outBuffer);
-
- /**
- * @brief Special Helper static function to decompress raw buffer from inBuffer to outBuffer one scanline.
- * After decompress one scanline successed, offset will be changed.
- *
- * @pre outBuffer memory should be allocated.
- * @pre if inBufferData's compression type is RLE4, outBuffer memory should store the previous scanline data.
- * @param[in] inBufferData The input glyph buffer data.
- * @param[in, out] outBuffer The output pointer of raw buffer data.
- * @param[in, out] offset The offset of input. It will be changed as next scanline's offset.
- */
- static void DecompressScanline(const GlyphBufferData& inBufferData, uint8_t* outBuffer, uint32_t& offset);
-
- private:
- // Delete copy operation.
- GlyphBufferData(const GlyphBufferData& rhs) = delete;
- GlyphBufferData& operator=(const GlyphBufferData& rhs) = delete;
-
- public:
- uint8_t* buffer; ///< The glyph's bitmap buffer data.
- uint32_t width; ///< The width of the bitmap.
- uint32_t height; ///< The height of the bitmap.
- int outlineOffsetX; ///< The additional horizontal offset to be added for the glyph's position for outline.
- int outlineOffsetY; ///< The additional vertical offset to be added for the glyph's position for outline.
- Pixel::Format format; ///< The pixel's format of the bitmap.
- CompressionType compressionType; ///< The type of buffer compression.
- bool isColorEmoji : 1; ///< Whether the glyph is an emoji.
- bool isColorBitmap : 1; ///< Whether the glyph is a color bitmap.
- bool isBufferOwned : 1; ///< Whether the glyph's bitmap buffer data owned by this class or not. Becareful when you use non-owned buffer data.
- };
-
- /**
* @brief Used to load an embedded item into the font client.
*/
struct EmbeddedItemDescription
--- /dev/null
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/glyph-buffer-data.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/image-operations.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+GlyphBufferData::GlyphBufferData()
+: buffer{nullptr},
+ width{0u},
+ height{0u},
+ outlineOffsetX{0},
+ outlineOffsetY{0},
+ format{Pixel::A8},
+ compressionType{CompressionType::NO_COMPRESSION},
+ isColorEmoji{false},
+ isColorBitmap{false},
+ isBufferOwned{false}
+{
+}
+
+GlyphBufferData::~GlyphBufferData()
+{
+ if(isBufferOwned)
+ {
+ free(buffer);
+ }
+}
+
+GlyphBufferData::GlyphBufferData(GlyphBufferData&& rhs) noexcept
+: buffer{rhs.buffer},
+ width{rhs.width},
+ height{rhs.height},
+ outlineOffsetX{rhs.outlineOffsetX},
+ outlineOffsetY{rhs.outlineOffsetY},
+ format{rhs.format},
+ compressionType{rhs.compressionType},
+ isColorEmoji{rhs.isColorEmoji},
+ isColorBitmap{rhs.isColorBitmap},
+ isBufferOwned{rhs.isBufferOwned}
+{
+ // Remove moved data
+ rhs.buffer = nullptr;
+ rhs.isBufferOwned = false;
+}
+
+GlyphBufferData& GlyphBufferData::operator=(GlyphBufferData&& rhs) noexcept
+{
+ buffer = rhs.buffer;
+ width = rhs.width;
+ height = rhs.height;
+ outlineOffsetX = rhs.outlineOffsetX;
+ outlineOffsetY = rhs.outlineOffsetY;
+ format = rhs.format;
+ compressionType = rhs.compressionType;
+ isColorEmoji = rhs.isColorEmoji;
+ isColorBitmap = rhs.isColorBitmap;
+ isBufferOwned = rhs.isBufferOwned;
+
+ // Remove moved data
+ rhs.buffer = nullptr;
+ rhs.isBufferOwned = false;
+
+ return *this;
+}
+
+size_t GlyphBufferData::Compress(const uint8_t* const __restrict__ inBuffer, GlyphBufferData& __restrict__ outBufferData)
+{
+ size_t bufferSize = 0u;
+ uint8_t*& __restrict__ compressedBuffer = outBufferData.buffer;
+ switch(outBufferData.compressionType)
+ {
+ case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+ {
+ bufferSize = static_cast<size_t>(outBufferData.width) * static_cast<size_t>(outBufferData.height) * static_cast<size_t>(Pixel::GetBytesPerPixel(outBufferData.format));
+
+ compressedBuffer = (uint8_t*)malloc(bufferSize);
+ if(DALI_UNLIKELY(compressedBuffer == nullptr))
+ {
+ return 0u;
+ }
+ outBufferData.isBufferOwned = true;
+
+ // Copy buffer without compress
+ memcpy(compressedBuffer, inBuffer, bufferSize);
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+ {
+ const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
+ const uint32_t componentCount = (widthByte >> 1);
+ const bool considerPadding = (widthByte & 1) ? true : false;
+
+ // For BIT_PER_PIXEL_4 type, we can know final compressed buffer size immediatly.
+ bufferSize = static_cast<size_t>(outBufferData.height) * static_cast<size_t>(componentCount + (considerPadding ? 1 : 0));
+ compressedBuffer = (uint8_t*)malloc(bufferSize);
+ if(DALI_UNLIKELY(compressedBuffer == nullptr))
+ {
+ return 0u;
+ }
+ outBufferData.isBufferOwned = true;
+
+ uint8_t* __restrict__ outBufferPtr = compressedBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBuffer;
+
+ // Compress for each line
+ for(uint32_t y = 0; y < outBufferData.height; ++y)
+ {
+ for(uint32_t x = 0; x < componentCount; ++x)
+ {
+ const uint8_t v0 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+ const uint8_t v1 = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+
+ *(outBufferPtr++) = (v0 << 4) | v1;
+ }
+ if(considerPadding)
+ {
+ *(outBufferPtr++) = Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++));
+ }
+ }
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+ {
+ const uint32_t widthByte = outBufferData.width * Pixel::GetBytesPerPixel(outBufferData.format);
+
+ // Allocate temperal buffer. Note that RLE4 can be bigger than original buffer.
+ uint8_t* __restrict__ tempBuffer = (uint8_t*)malloc(outBufferData.height * (widthByte + 1));
+ if(DALI_UNLIKELY(tempBuffer == nullptr))
+ {
+ return 0u;
+ }
+
+ uint8_t* __restrict__ outBufferPtr = tempBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBuffer;
+
+ bufferSize = 0u;
+
+ // Compress for each line
+ for(uint32_t y = 0; y < outBufferData.height; ++y)
+ {
+ uint32_t encodedByte = 0;
+ while(encodedByte < widthByte)
+ {
+ // Case 1 : Remain only 1 byte
+ if(DALI_UNLIKELY(encodedByte + 1 == widthByte))
+ {
+ const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+ *(outBufferPtr++) = v0;
+ ++encodedByte;
+ ++bufferSize;
+ }
+ // Case 2 : Remain only 2 byte
+ else if(DALI_UNLIKELY(encodedByte + 2 == widthByte))
+ {
+ const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+ const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
+ encodedByte += 2;
+ if(v0 == v1)
+ {
+ *(outBufferPtr++) = 0x80 | v0;
+ ++bufferSize;
+ }
+ else
+ {
+ *(outBufferPtr++) = 0x10 | v0;
+ *(outBufferPtr++) = v1 << 4;
+ bufferSize += 2;
+ }
+ }
+ // Case 3 : Normal case. Remain byte bigger or equal than 3.
+ else
+ {
+ // Compress rule -
+ // Read 2 byte as v0 and v1.
+ // - If v0 == v1, We can compress. mark the first bit as 1. and remain 3 bit mark as the "runLength - 2".
+ // runLength can be maximum 9.
+ // - If v0 != v1, We cannot compress. mark the first bit as 0. and remain 3 bit mark as the "(nonRunLength - 1) / 2"
+ // Due to the BitPerPixel is 4, nonRunLength should be odd value.
+ // nonRunLength cutted if v0 == v1.
+ // nonRunLength can be maximum 15.
+
+ const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev0) & 0x0f; // Intented underflow
+ const uint8_t prev1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev1) & 0x0f; // Intented underflow
+ encodedByte += 2;
+ // We can compress by RLE
+ if(v0 == v1)
+ {
+ uint8_t runLength = 2;
+ while(encodedByte < widthByte && runLength < 9)
+ {
+ const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v2 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prev2) & 0x0f; // Intented underflow
+ if(v2 == v0)
+ {
+ ++inBufferPtr;
+ ++encodedByte;
+ ++runLength;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Update (runLength - 2) result.
+ *(outBufferPtr++) = ((0x8 | (runLength - 2)) << 4) | v0;
+ ++bufferSize;
+ }
+ // We cannot compress by RLE.
+ else
+ {
+ // Read one more value.
+ const uint8_t prev2 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t v2 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr++)) - prev2) & 0x0f; // Intented underflow
+ ++encodedByte;
+
+ uint8_t nonRunLength = 3;
+ uint8_t* nonRunLengthHeaderPtr = outBufferPtr;
+ *(outBufferPtr++) = v0;
+ *(outBufferPtr++) = (v1 << 4) | v2;
+ bufferSize += 2;
+ while(encodedByte < widthByte && nonRunLength < 15)
+ {
+ if(DALI_LIKELY(encodedByte + 1 < widthByte))
+ {
+ const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t w0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
+ const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1 - widthByte));
+ const uint8_t w1 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr + 1)) - prew1) & 0x0f; // Intented underflow
+ if(w0 == w1)
+ {
+ // Stop non-compress logic.
+ break;
+ }
+ else
+ {
+ ++bufferSize;
+ *(outBufferPtr++) = (w0 << 4) | w1;
+ inBufferPtr += 2;
+ encodedByte += 2;
+ nonRunLength += 2;
+ }
+ }
+ else
+ {
+ // Edge case. There is only one pixel remained.
+ const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr - widthByte));
+ const uint8_t w0 = (Dali::Internal::Platform::CompressBitPerPixel8To4(*(inBufferPtr)) - prew0) & 0x0f; // Intented underflow
+ {
+ ++bufferSize;
+ *(outBufferPtr++) = (w0 << 4);
+ ++encodedByte;
+ ++inBufferPtr;
+ // Increase nonRunLength 2 even latest value is invalid.
+ nonRunLength += 2;
+ }
+ }
+ }
+
+ // Update (nonRunLength-1)/2 result into header.
+ *(nonRunLengthHeaderPtr) |= (nonRunLength >> 1) << 4;
+ }
+ }
+ }
+ }
+
+ // Allocate and copy data
+ compressedBuffer = (uint8_t*)malloc(bufferSize);
+ if(DALI_UNLIKELY(compressedBuffer == nullptr))
+ {
+ free(tempBuffer);
+ return 0u;
+ }
+ outBufferData.isBufferOwned = true;
+
+ memcpy(compressedBuffer, tempBuffer, bufferSize);
+ free(tempBuffer);
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return bufferSize;
+}
+
+void GlyphBufferData::Decompress(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer)
+{
+ if(DALI_UNLIKELY(outBuffer == nullptr))
+ {
+ return;
+ }
+
+ switch(inBufferData.compressionType)
+ {
+ case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+ {
+ const auto bufferSize = inBufferData.width * inBufferData.height * Pixel::GetBytesPerPixel(inBufferData.format);
+
+ // Copy buffer without compress
+ memcpy(outBuffer, inBufferData.buffer, bufferSize);
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+ {
+ const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+ const uint32_t componentCount = (widthByte >> 1);
+ const bool considerPadding = (widthByte & 1) ? true : false;
+
+ uint8_t* __restrict__ outBufferPtr = outBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
+
+ // Compress for each line
+ for(uint32_t y = 0; y < inBufferData.height; ++y)
+ {
+ for(uint32_t x = 0; x < componentCount; ++x)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ const uint8_t v0 = (v >> 4) & 0x0f;
+ const uint8_t v1 = v & 0x0f;
+
+ *(outBufferPtr++) = (v0 << 4) | v0;
+ *(outBufferPtr++) = (v1 << 4) | v1;
+ }
+ if(considerPadding)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ *(outBufferPtr++) = (v << 4) | v;
+ }
+ }
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+ {
+ const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+ uint8_t* __restrict__ outBufferPtr = outBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer;
+ // Compress for each line
+ for(uint32_t y = 0; y < inBufferData.height; ++y)
+ {
+ uint32_t x = 0;
+ uint32_t decodedByte = 0;
+ while(decodedByte < widthByte)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ ++x;
+ // Compress by RLE
+ if(v & 0x80)
+ {
+ const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
+ decodedByte += runLength;
+ const uint8_t repeatValue = v & 0x0f;
+ for(uint8_t iter = 0; iter < runLength; ++iter)
+ {
+ const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+ const uint8_t v0 = (prev0 + repeatValue) & 0x0f;
+ *(outBufferPtr++) = (v0 << 4) | v0;
+ }
+ }
+ // Not compress by RLE
+ else
+ {
+ const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
+ decodedByte += nonRunLength;
+ // First value.
+ const uint8_t prev0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+ const uint8_t v0 = (prev0 + (v & 0x0f)) & 0x0f;
+ *(outBufferPtr++) = (v0 << 4) | v0;
+
+ const bool ignoreLastValue = decodedByte > widthByte ? true : false;
+ if(DALI_UNLIKELY(ignoreLastValue))
+ {
+ --decodedByte;
+ for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
+ {
+ const uint8_t w = *(inBufferPtr++);
+ const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+ const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+ const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
+ const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
+ ++x;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ *(outBufferPtr++) = (w1 << 4) | w1;
+ }
+ // Last value.
+ {
+ const uint8_t w = ((*(inBufferPtr++)) >> 4) & 0x0f;
+ const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+ const uint8_t w0 = (prew0 + w) & 0x0f;
+ ++x;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ }
+ }
+ else
+ {
+ for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
+ {
+ const uint8_t w = *(inBufferPtr++);
+ const uint8_t prew0 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte)) & 0x0f;
+ const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+ const uint8_t prew1 = DALI_UNLIKELY(y == 0) ? 0 : (*(outBufferPtr - widthByte + 1)) & 0x0f;
+ const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
+ ++x;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ *(outBufferPtr++) = (w1 << 4) | w1;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+void GlyphBufferData::DecompressScanline(const GlyphBufferData& __restrict__ inBufferData, uint8_t* __restrict__ outBuffer, uint32_t& __restrict__ offset)
+{
+ switch(inBufferData.compressionType)
+ {
+ case TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION:
+ {
+ const auto bufferSize = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+ // Copy buffer without compress
+ memcpy(outBuffer, inBufferData.buffer + offset, bufferSize);
+
+ // Update offset
+ offset += bufferSize;
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::BPP_4:
+ {
+ const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+ const uint32_t componentCount = (widthByte >> 1);
+ const bool considerPadding = (widthByte & 1) ? true : false;
+
+ uint8_t* __restrict__ outBufferPtr = outBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
+
+ // Decompress scanline
+ for(uint32_t x = 0; x < componentCount; ++x)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ const uint8_t v0 = (v >> 4) & 0x0f;
+ const uint8_t v1 = v & 0x0f;
+
+ *(outBufferPtr++) = (v0 << 4) | v0;
+ *(outBufferPtr++) = (v1 << 4) | v1;
+ }
+ if(considerPadding)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ *(outBufferPtr++) = (v << 4) | v;
+ }
+
+ // Update offset
+ offset += (widthByte + 1u) >> 1u;
+ break;
+ }
+ case TextAbstraction::GlyphBufferData::CompressionType::RLE_4:
+ {
+ const uint32_t widthByte = inBufferData.width * Pixel::GetBytesPerPixel(inBufferData.format);
+
+ uint8_t* __restrict__ outBufferPtr = outBuffer;
+ const uint8_t* __restrict__ inBufferPtr = inBufferData.buffer + offset;
+
+ // If offset is zero, fill outBuffer as 0 first.
+ if(DALI_UNLIKELY(offset == 0))
+ {
+ memset(outBufferPtr, 0, widthByte);
+ }
+
+ // Decompress scanline
+ uint32_t decodedByte = 0;
+ while(decodedByte < widthByte)
+ {
+ const uint8_t v = *(inBufferPtr++);
+ ++offset;
+ // Compress by RLE
+ if(v & 0x80)
+ {
+ const uint8_t runLength = ((v >> 4) & 0x07) + 2u;
+ decodedByte += runLength;
+ const uint8_t repeatValue = (v & 0x0f);
+ for(uint8_t iter = 0; iter < runLength; ++iter)
+ {
+ const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
+ const uint8_t v0 = (prev0 + repeatValue) & 0x0f;
+ *(outBufferPtr++) = (v0 << 4) | v0;
+ }
+ }
+ // Not compress by RLE
+ else
+ {
+ const uint8_t nonRunLength = (((v >> 4) & 0x07) << 1u) + 1u;
+ decodedByte += nonRunLength;
+ // First value.
+ const uint8_t prev0 = (*(outBufferPtr)) & 0x0f;
+ const uint8_t v0 = (prev0 + (v & 0x0f)) & 0x0f;
+ *(outBufferPtr++) = (v0 << 4) | v0;
+
+ const bool ignoreLastValue = decodedByte > widthByte ? true : false;
+ if(DALI_UNLIKELY(ignoreLastValue))
+ {
+ --decodedByte;
+ for(uint8_t iter = 1; iter + 2 < nonRunLength; iter += 2)
+ {
+ const uint8_t w = *(inBufferPtr++);
+ const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+ const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+ const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
+ const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
+ ++offset;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ *(outBufferPtr++) = (w1 << 4) | w1;
+ }
+ // Last value.
+ {
+ const uint8_t w = ((*(inBufferPtr++)) >> 4) & 0x0f;
+ const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+ const uint8_t w0 = (prew0 + w) & 0x0f;
+ ++offset;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ }
+ }
+ else
+ {
+ for(uint8_t iter = 1; iter < nonRunLength; iter += 2)
+ {
+ const uint8_t w = *(inBufferPtr++);
+ const uint8_t prew0 = (*(outBufferPtr)) & 0x0f;
+ const uint8_t w0 = (prew0 + ((w >> 4) & 0x0f)) & 0x0f;
+ const uint8_t prew1 = (*(outBufferPtr + 1)) & 0x0f;
+ const uint8_t w1 = (prew1 + (w & 0x0f)) & 0x0f;
+ ++offset;
+
+ *(outBufferPtr++) = (w0 << 4) | w0;
+ *(outBufferPtr++) = (w1 << 4) | w1;
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_TEXT_ABSTRACTION_GLYPH_BUFFER_DATA_H
+#define DALI_TEXT_ABSTRACTION_GLYPH_BUFFER_DATA_H
+
+/*
+ * Copyright (c) 2023 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/pixel.h>
+#include <cstddef> /// for size_t
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace TextAbstraction
+{
+/**
+ * @brief Struct used to retrieve the glyph's bitmap.
+ */
+struct DALI_ADAPTOR_API GlyphBufferData
+{
+ /**
+ * @brief Constructor.
+ *
+ * Initializes struct members to their defaults.
+ */
+ GlyphBufferData();
+
+ /**
+ * @brief Destructor.
+ */
+ ~GlyphBufferData();
+
+ /**
+ * @brief Move constructor.
+ *
+ * @param[in] rhs moved data.
+ */
+ GlyphBufferData(GlyphBufferData&& rhs) noexcept;
+
+ /**
+ * @brief Move assign operator.
+ *
+ * @param[in] rhs moved data.
+ * @return A reference to this.
+ */
+ GlyphBufferData& operator=(GlyphBufferData&& rhs) noexcept;
+
+ // Compression method of buffer. Each buffer compressed line by line
+ enum class CompressionType
+ {
+ NO_COMPRESSION = 0, // No compression
+ BPP_4 = 1, // Compress as 4 bit. Color become value * 17 (0x00, 0x11, 0x22, ... 0xee, 0xff).
+ // Only works for Pixel::L8 format
+ RLE_4 = 2, // Compress as 4 bit, and Run-Length-Encode. For more high compress rate, we store difference between previous scanline.
+ // Only works for Pixel::L8 format
+ };
+
+ /**
+ * @brief Helper static function to compress raw buffer from inBuffer to outBufferData.buffer.
+ * outBufferData will have it's own buffer.
+ *
+ * @pre outBufferData must not have it's own buffer.
+ * @param[in] inBuffer The input raw data.
+ * @param[in, out] outBufferData The output glyph buffer data.
+ * @return Size of compressed out buffer, Or 0 if compress failed.
+ */
+ static size_t Compress(const uint8_t* const inBuffer, GlyphBufferData& outBufferData);
+
+ /**
+ * @brief Helper static function to decompress raw buffer from inBuffer to outBufferPtr.
+ * If outBuffer is nullptr, Do nothing.
+ *
+ * @pre outBuffer memory should be allocated.
+ * @param[in] inBufferData The input glyph buffer data.
+ * @param[in, out] outBuffer The output pointer of raw buffer data.
+ */
+ static void Decompress(const GlyphBufferData& inBufferData, uint8_t* outBuffer);
+
+ /**
+ * @brief Special Helper static function to decompress raw buffer from inBuffer to outBuffer one scanline.
+ * After decompress one scanline successed, offset will be changed.
+ *
+ * @pre outBuffer memory should be allocated.
+ * @pre if inBufferData's compression type is RLE4, outBuffer memory should store the previous scanline data.
+ * @param[in] inBufferData The input glyph buffer data.
+ * @param[in, out] outBuffer The output pointer of raw buffer data.
+ * @param[in, out] offset The offset of input. It will be changed as next scanline's offset.
+ */
+ static void DecompressScanline(const GlyphBufferData& inBufferData, uint8_t* outBuffer, uint32_t& offset);
+
+private:
+ // Delete copy operation.
+ GlyphBufferData(const GlyphBufferData& rhs) = delete;
+ GlyphBufferData& operator=(const GlyphBufferData& rhs) = delete;
+
+public:
+ uint8_t* buffer; ///< The glyph's bitmap buffer data.
+ uint32_t width; ///< The width of the bitmap.
+ uint32_t height; ///< The height of the bitmap.
+ int outlineOffsetX; ///< The additional horizontal offset to be added for the glyph's position for outline.
+ int outlineOffsetY; ///< The additional vertical offset to be added for the glyph's position for outline.
+ Pixel::Format format; ///< The pixel's format of the bitmap.
+ CompressionType compressionType; ///< The type of buffer compression.
+ bool isColorEmoji : 1; ///< Whether the glyph is an emoji.
+ bool isColorBitmap : 1; ///< Whether the glyph is a color bitmap.
+ bool isBufferOwned : 1; ///< Whether the glyph's bitmap buffer data owned by this class or not. Becareful when you use non-owned buffer data.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif //DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
DELETE
};
- GlyphBuffer(Dali::TextAbstraction::FontClient::GlyphBufferData& data, DestructorType type)
+ GlyphBuffer(Dali::TextAbstraction::GlyphBufferData& data, DestructorType type)
: data(data),
type(type)
{
}
}
- Dali::TextAbstraction::FontClient::GlyphBufferData& data;
- DestructorType type;
+ Dali::TextAbstraction::GlyphBufferData& data;
+ DestructorType type;
};
/**
void CopyImageToSurface(
const TextAbstraction::TextRenderer::Parameters& parameters,
const Pixel::Format pixelFormat,
- TextAbstraction::FontClient::GlyphBufferData& data,
+ TextAbstraction::GlyphBufferData& data,
unsigned char* buffer,
const int rgbaCase,
const double glyphX,
const cairo_glyph_t& glyph = *(cairoGlyphsBuffer + index);
// Retrieve the image
- TextAbstraction::FontClient::GlyphBufferData data;
+ TextAbstraction::GlyphBufferData data;
if(isEmoji)
{
data.width = parameters.glyphs[run.glyphIndex].width;
const unsigned int pixelSize = Pixel::GetBytesPerPixel(data.format);
// If we need to decompress, create new memory and replace ownership.
- if(data.compressionType != TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION)
+ if(data.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION)
{
uint8_t* newBuffer = (uint8_t*)malloc(widthOut * heightOut * pixelSize);
if(DALI_LIKELY(newBuffer != nullptr))
{
- TextAbstraction::FontClient::GlyphBufferData::Decompress(data, newBuffer);
+ TextAbstraction::GlyphBufferData::Decompress(data, newBuffer);
if(data.isBufferOwned)
{
// Release previous buffer
}
data.isBufferOwned = true;
data.buffer = newBuffer;
- data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
}
}
free(data.buffer);
}
data.isBufferOwned = true;
- data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = Dali::TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
data.buffer = pixelsOut;
data.width = widthOut;
data.height = heightOut;
return mPlugin->GetGlyphMetrics(array, size, type, horizontal);
}
-void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth)
+void FontClient::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth)
{
CreatePlugin();
bool GetGlyphMetrics(GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal);
/**
- * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+ * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth )
*/
- void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth);
+ void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth);
/**
* @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
}
void BitmapFontCacheItem::CreateBitmap(
- GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+ GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
{
unsigned int index = 0u;
for(auto& item : font.glyphs)
/**
* @copydoc FontCacheItemInterface::CreateBitmap()
*/
- void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+ void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
/**
* @copydoc FontCacheItemInterface::IsColorGlyph()
glyph.scaleFactor = 1.f;
}
-void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
- Dali::TextAbstraction::FontClient::GlyphBufferData& data)
+void EmbeddedItem::CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+ Dali::TextAbstraction::GlyphBufferData& data)
{
data.width = width;
data.height = height;
else
{
data.isBufferOwned = true;
- data.compressionType = Dali::TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = Dali::TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
// Creates the output buffer
const uint32_t bufferSize = data.width * data.height * 4u;
* @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);
+ void CreateBitmap(const std::vector<PixelBufferCacheItem>& pixelBufferCache,
+ Dali::TextAbstraction::GlyphBufferData& data);
PixelBufferId pixelBufferId{0u}; ///< Index to the vector of pixel buffers
uint32_t width{0u}; ///< The desired width.
* @param[in] isItalicRequired
* @param[in] isBoldRequired
*/
- virtual void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const = 0;
+ virtual void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const = 0;
/**
* Return true if the glyph is colored
#endif
}
-void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth) const
+void FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth) const
{
data.isColorBitmap = false;
data.isColorEmoji = false;
PixelData FontClient::Plugin::CreateBitmap(FontId fontId, GlyphIndex glyphIndex, int outlineWidth) const
{
- TextAbstraction::FontClient::GlyphBufferData data;
+ TextAbstraction::GlyphBufferData data;
CreateBitmap(fontId, glyphIndex, false, false, data, outlineWidth);
// If data is compressed or not owned buffer, copy this.
- if(!data.isBufferOwned || data.compressionType != TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION)
+ if(!data.isBufferOwned || data.compressionType != TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION)
{
uint8_t* newBuffer = (uint8_t*)malloc(data.width * data.height * Pixel::GetBytesPerPixel(data.format));
- TextAbstraction::FontClient::GlyphBufferData::Decompress(data, newBuffer);
+ TextAbstraction::GlyphBufferData::Decompress(data, newBuffer);
if(data.isBufferOwned)
{
free(data.buffer);
data.buffer = newBuffer;
data.isBufferOwned = true;
- data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
}
return PixelData::New(data.buffer,
bool GetVectorMetrics(GlyphInfo* array, uint32_t size, bool horizontal) const;
/**
- * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+ * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth )
*/
- void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth) const;
+ void CreateBitmap(FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth) const;
/**
* @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
* @param[in] srcHeight The height of the bitmap.
* @param[in] srcBuffer The buffer of the bitmap.
*/
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer, const Pixel::Format srcFormat)
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer, const Pixel::Format srcFormat)
{
// Set the input dimensions.
const ImageDimensions inputDimensions(srcWidth, srcHeight);
data.format = srcFormat;
// Note we don't compress here
- data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
const uint32_t bytePerPixel = Dali::Pixel::GetBytesPerPixel(srcFormat);
* @param[in] moveBuffer Whether the bitmap buffer move. True if just copy buffer pointer. False if we use memcpy. (Default is false.)
* @note If you set moveBuffer=true, the bitmap's buffer moved frome srcBitmap to data. So srcBitmap buffer changed as nullptr.
*/
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap& srcBitmap, bool isShearRequired, bool moveBuffer)
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data, FT_Bitmap& srcBitmap, bool isShearRequired, bool moveBuffer)
{
data.buffer = nullptr;
if(srcBitmap.width * srcBitmap.rows > 0)
data.format = Pixel::L8; // Sets the pixel format.
// Note we don't compress here
- data.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ data.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
if(moveBuffer)
{
namespace Dali::TextAbstraction::Internal
{
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
- unsigned int srcWidth,
- unsigned int srcHeight,
- const unsigned char* const srcBuffer,
- const Pixel::Format srcFormat);
-
-void ConvertBitmap(TextAbstraction::FontClient::GlyphBufferData& data,
- FT_Bitmap& srcBitmap,
- bool isShearRequired,
- bool moveBuffer = false);
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data,
+ unsigned int srcWidth,
+ unsigned int srcHeight,
+ const unsigned char* const srcBuffer,
+ const Pixel::Format srcFormat);
+
+void ConvertBitmap(TextAbstraction::GlyphBufferData& data,
+ FT_Bitmap& srcBitmap,
+ bool isShearRequired,
+ bool moveBuffer = false);
/**
* @brief Creates a font family pattern used to match fonts.
* @param[in] isBoldRequired Whether the glyph requires bold style.
*/
void FontFaceCacheItem::CreateBitmap(
- GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
+ GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const
{
GlyphCacheManager::GlyphCacheData glyphData;
FT_Error error;
/**
* @copydoc FontCacheItemInterface::CreateBitmap()
*/
- void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
+ void CreateBitmap(GlyphIndex glyphIndex, Dali::TextAbstraction::GlyphBufferData& data, int outlineWidth, bool isItalicRequired, bool isBoldRequired) const override;
/**
* @copydoc FontCacheItemInterface::IsColorGlyph()
GlyphCacheData& destinationGlpyhData = mLRUGlyphCache.GetElement(iter);
- destinationGlpyhData.mRenderedBuffer = new TextAbstraction::FontClient::GlyphBufferData();
+ destinationGlpyhData.mRenderedBuffer = new TextAbstraction::GlyphBufferData();
if(DALI_UNLIKELY(!destinationGlpyhData.mRenderedBuffer))
{
DALI_LOG_ERROR("Allocate GlyphBufferData failed\n");
return;
}
- TextAbstraction::FontClient::GlyphBufferData& renderBuffer = *destinationGlpyhData.mRenderedBuffer;
+ TextAbstraction::GlyphBufferData& renderBuffer = *destinationGlpyhData.mRenderedBuffer;
// Set basic informations.
renderBuffer.width = srcBitmap.width;
if(policy == CompressionPolicyType::SPEED)
{
// If policy is SPEED, we will not compress bitmap.
- renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
}
else
{
// If small enough glyph, compress as BPP4 method.
if(srcBitmap.width < THRESHOLD_WIDTH_FOR_RLE4_COMPRESSION)
{
- renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::BPP_4;
+ renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::BPP_4;
}
else
{
- renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::RLE_4;
+ renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::RLE_4;
}
}
- const auto compressedBufferSize = TextAbstraction::FontClient::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
+ const auto compressedBufferSize = TextAbstraction::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
if(DALI_UNLIKELY(compressedBufferSize == 0u))
{
DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_GRAY");
case FT_PIXEL_MODE_BGRA:
{
// Copy buffer without compress
- renderBuffer.compressionType = TextAbstraction::FontClient::GlyphBufferData::CompressionType::NO_COMPRESSION;
+ renderBuffer.compressionType = TextAbstraction::GlyphBufferData::CompressionType::NO_COMPRESSION;
renderBuffer.format = Pixel::BGRA8888;
- const auto compressedBufferSize = TextAbstraction::FontClient::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
+ const auto compressedBufferSize = TextAbstraction::GlyphBufferData::Compress(srcBitmap.buffer, renderBuffer);
if(DALI_UNLIKELY(compressedBufferSize == 0u))
{
DALI_ASSERT_DEBUG(0 == "Compress failed at FT_PIXEL_MODE_BGRA");
*/
// INTERNAL INCLUDES
-#include <dali/devel-api/text-abstraction/font-client.h> // For GlyphBufferData
+#include <dali/devel-api/text-abstraction/glyph-buffer-data.h>
#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
#include <dali/internal/text/text-abstraction/plugin/lru-cache-container.h>
FT_Int32 mStyleFlags{0}; // Get from FT_Face
bool mIsBitmap{false};
- TextAbstraction::FontClient::GlyphBufferData* mRenderedBuffer{nullptr}; // Rendered glyph buffer. Cached only if system allow to cache and we rendered it before. Otherwise, just nullptr
+ TextAbstraction::GlyphBufferData* mRenderedBuffer{nullptr}; // Rendered glyph buffer. Cached only if system allow to cache and we rendered it before. Otherwise, just nullptr
/**
* @brief Release the memory of loaded mGlyph / mBitmap.