*/
int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
{
- unsigned outWidth = -1, outHeight = -1;
+ unsigned outWidth = -1, outHeight = -1, outStride = -1;
// Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced:
unsigned char check_4x4[16 * 3] = {
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(check_4x4[0], (unsigned char)0x7f, TEST_LOCATION);
// Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
unsigned char single_4x4[16 * 3] = {
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(single_4x4[0], (unsigned char)0xf, TEST_LOCATION);
// Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
// (white pixel at bottom-right of image)
unsigned char single_4x4_2[16 * 3] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff};
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+ DALI_TEST_EQUALS(outStride, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION);
// Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
}
// Scaling to 0 x 0 should stop at 1 x 1:
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+ DALI_TEST_CHECK(outStride == outWidth);
// Scaling to 1 x 1 should hit 1 x 1:
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 608, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 1u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 1u, TEST_LOCATION);
+ DALI_TEST_CHECK(outStride == outWidth);
// Scaling to original dimensions should NOP:
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 384u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 384u, TEST_LOCATION);
+ DALI_TEST_CHECK(outStride == outWidth);
// More dimension tests:
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 44u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 44u, TEST_LOCATION);
+ DALI_TEST_CHECK(outStride == outWidth);
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_EQUALS(outWidth, 48u, TEST_LOCATION);
DALI_TEST_EQUALS(outHeight, 48u, TEST_LOCATION);
+ DALI_TEST_CHECK(outStride == outWidth);
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 384, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_CHECK(outWidth == 3u && outHeight == 3u);
+ DALI_TEST_CHECK(outStride == outWidth);
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 320, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_CHECK(outWidth == 5u && outHeight == 5u);
+ DALI_TEST_CHECK(outStride == outWidth);
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 448, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_CHECK(outWidth == 7u && outHeight == 7u);
+ DALI_TEST_CHECK(outStride == outWidth);
- Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight);
+ Dali::Internal::Platform::DownscaleInPlacePow2RGB888(magenta_600_x_600, 352, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight, outStride);
DALI_TEST_CHECK(outWidth == 11u && outHeight == 11u);
+ DALI_TEST_CHECK(outStride == outWidth);
// Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
unsigned int numNonMagenta = 0u;
*/
void TestDownscaleOutputsExpectedDimensionsRGBA8888(uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
{
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
reinterpret_cast<unsigned char*>(pixels),
inputWidth,
inputHeight,
+ inputWidth,
desiredWidth,
desiredHeight,
BoxDimensionTestBoth,
resultingWidth,
- resultingHeight);
+ resultingHeight,
+ resultingStride);
DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+ DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
}
/**
*/
void TestDownscaleOutputsExpectedDimensionsRGB565(uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
{
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
reinterpret_cast<unsigned char*>(pixels),
inputWidth,
inputHeight,
+ inputWidth,
desiredWidth,
desiredHeight,
BoxDimensionTestBoth,
resultingWidth,
- resultingHeight);
+ resultingHeight,
+ resultingStride);
DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+ DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
}
/**
*/
void TestDownscaleOutputsExpectedDimensions2ComponentPair(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
{
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
pixels,
inputWidth,
inputHeight,
+ inputWidth,
desiredWidth,
desiredHeight,
BoxDimensionTestBoth,
resultingWidth,
- resultingHeight);
+ resultingHeight,
+ resultingStride);
DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+ DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
}
/**
*/
void TestDownscaleOutputsExpectedDimensionsSingleComponent(uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char* const location)
{
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
pixels,
inputWidth,
inputHeight,
+ inputWidth,
desiredWidth,
desiredHeight,
BoxDimensionTestBoth,
resultingWidth,
- resultingHeight);
+ resultingHeight,
+ resultingStride);
DALI_TEST_EQUALS(resultingWidth, expectedWidth, location);
DALI_TEST_EQUALS(resultingHeight, expectedHeight, location);
+ DALI_TEST_EQUALS(resultingStride, expectedWidth, location);
}
/**
image[i] = 0xffffffff;
}
unsigned char* const pixels = reinterpret_cast<unsigned char*>(image);
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
// Test downscaling where the input size is an exact multiple of the desired size:
// (We expect a perfect result here)
- DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 512, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 16u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 512, 64, 512, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 16u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 2u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 64, 1024, 64, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 4u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 64u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Test downscaling where the input size is slightly off being an exact multiple of the desired size:
// (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
- DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 601, 603, 601, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 75u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 75u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 736 + 1, 352 + 3, 736 + 1, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 23u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 11u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 384 + 3, 896 + 1, 384 + 3, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 3u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 7u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Test downscales with source dimensions which are under a nice power of two by one:
// The target is hit exactly due to losing spare columns or rows at each iteration:
- DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small.
- DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 63, 31, 63, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 3u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Should stop at almost twice the requested dimensions:
- DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 15, 127, 15, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 7u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 63u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Test downscales to 1 in one or both dimensions:
// Parameters: input-x input-y, desired-x, desired-y, expected-x, expected-y
}
const uint32_t imageHash = HashPixels(image, numPixels);
unsigned char* const pixels = reinterpret_cast<unsigned char*>(image);
- unsigned int resultingWidth = -1, resultingHeight = -1;
+ unsigned int resultingWidth = -1, resultingHeight = -1, resultingStride = -1;
// Test downscales to the same size:
// The point is just to be sure the downscale is a NOP in this case:
- DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 600, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 600u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 600u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 512, 128, 512, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 512u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 128u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
- DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight);
+ DownscaleInPlacePow2RGBA8888(pixels, 17, 1001, 17, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight, resultingStride);
DALI_TEST_EQUALS(resultingWidth, 17u, TEST_LOCATION);
DALI_TEST_EQUALS(resultingHeight, 1001u, TEST_LOCATION);
+ DALI_TEST_EQUALS(resultingStride, resultingWidth, TEST_LOCATION);
// Test downscales that request a larger size (we never upscale so these are NOPs too):
// Parameters: input-x input-y, desired-x, desired-y, expected-x, expected-y
int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
{
// Test that calling with null and zero parameters doesn't blow up:
- unsigned int outWidth, outHeight;
- DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+ unsigned int outWidth, outHeight, outStride;
+ DownscaleInPlacePow2RGB565(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
uint16_t image[608 * 608];
for(unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i)
int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
{
// Simple test that a null pointer does not get dereferenced in the function:
- unsigned int outWidth, outHeight;
- DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+ unsigned int outWidth, outHeight, outStride;
+ DownscaleInPlacePow2ComponentPair(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
// Simple tests of dimensions output:
int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
{
// Simple test that a null pointer does not get dereferenced in the function:
- unsigned int outWidth, outHeight;
- DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight);
+ unsigned int outWidth, outHeight, outStride;
+ DownscaleInPlacePow2SingleBytePerPixel(0, 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight, outStride);
// Tests of output dimensions from downscaling:
uint8_t image[608 * 608];
uint32_t outputImage[desiredWidth * desiredHeight];
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)&image->GetVector()[0], 256, 256, 256, (unsigned char*)outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION); // < Red corner pixel
DALI_TEST_EQUALS(outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION); // < Green corner pixel
buffer.resize(outputBufferSize);
uint32_t* outputImage = &buffer[0];
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, (unsigned char*)outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, inputWidth, inputHeight, inputWidth, (unsigned char*)outputImage, desiredWidth, desiredHeight);
// Check that all the output pixels are the right color:
const uint32_t reference = inputImage[inputWidth * inputHeight / 2];
// Try several different starting image sizes:
// 1x1 -> 1x1:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// Single-pixel wide tall stripe:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// Single-pixel tall, wide strip:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1024, 1, 1024, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// Square mid-size image:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// Wide mid-size image:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// Tall mid-size image:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 467, 53, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, inputImage[0], TEST_LOCATION);
outputImage = 0;
// 0 x 0 input image (make sure output not written to):
outputImage = 0xDEADBEEF;
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)&outputImage, desiredWidth, desiredHeight);
DALI_TEST_EQUALS(outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION);
outputImage = 0;
// Try several different starting image sizes:
// 1x1 -> 1x1:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, (unsigned char*)outputImage, 0, 0);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 1, 1, (unsigned char*)outputImage, 0, 0);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// Single-pixel wide tall stripe:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, (unsigned char*)outputImage, 0, 33);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 1, 102, 1, (unsigned char*)outputImage, 0, 33);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// Single-pixel tall, wide strip:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, (unsigned char*)outputImage, 0, 67);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 102, 1, 102, (unsigned char*)outputImage, 0, 67);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// Square mid-size image:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, (unsigned char*)outputImage, 21, 0);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 103, 103, 103, (unsigned char*)outputImage, 21, 0);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// Wide mid-size image to 0 height
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, (unsigned char*)outputImage, 99, 0);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 313, 79, 313, (unsigned char*)outputImage, 99, 0);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// Tall mid-size image to 0 height, over width
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, (unsigned char*)outputImage, 9999, 0);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 53, 46, 53, (unsigned char*)outputImage, 9999, 0);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
// 0 x 0 input image:
- Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, (unsigned char*)outputImage, 200, 99);
+ Dali::Internal::Platform::PointSample4BPP((const unsigned char*)inputImage, 0, 0, 0, (unsigned char*)outputImage, 200, 99);
DALI_TEST_EQUALS(0xaaaaaaaa, outputImage[0], TEST_LOCATION);
END_TEST;
{
name = uniform.name.substr(0, iter);
auto arrayCount = std::stoi(uniform.name.substr(iter + 1));
+ iter = uniform.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != uniform.name.length())
+ {
+ suffix = uniform.name.substr(iter + 1); // If there is a suffix, it means its an element of an array of struct
+ }
+
for(int i = 0; i < arrayCount; ++i)
{
std::stringstream nss;
- nss << name << "[" << i << "]";
+ nss << name << "[" << i << "]" << suffix;
GetUniformLocation(program, nss.str().c_str()); // Generate a GL loc per element
}
}
for(const auto& data : mCustomUniforms)
{
fprintf(stderr, "\ncustom uniforms: %s\n", data.name.c_str());
- mDefaultUniformBlock.members.emplace_back();
- auto& item = mDefaultUniformBlock.members.back();
auto iter = data.name.find("[", 0);
int numElements = 1;
{
numElements = 1;
}
-
- item.name = baseName;
- item.binding = 0;
- item.bufferIndex = 0;
- item.uniformClass = Graphics::UniformClass::UNIFORM;
- item.type = data.type;
- item.numElements = numElements;
-
- for(int i = 0; i < numElements; ++i)
+ iter = data.name.find("]");
+ std::string suffix;
+ if(iter != std::string::npos && iter + 1 != data.name.length())
{
- std::stringstream elementNameStream;
- elementNameStream << baseName << "[" << i << "]";
+ suffix = data.name.substr(iter + 1); // If there is a suffix, it means it is an element of an array of struct
+ }
- item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
- item.offsets.push_back(offset);
- offset += GetSizeForType(data.type);
+ if(!suffix.empty())
+ {
+ // Write multiple items
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]" << suffix;
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+ item.name = elementNameStream.str();
+ item.binding = 0;
+ item.offsets.push_back(offset);
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ offset += GetSizeForType(data.type);
+ }
+ }
+ else
+ {
+ // Write 1 item with multiple elements
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
+
+ item.name = baseName;
+ item.binding = 0;
+ item.bufferIndex = 0;
+ item.uniformClass = Graphics::UniformClass::UNIFORM;
+ item.type = data.type;
+ item.numElements = numElements;
+
+ for(int i = 0; i < numElements; ++i)
+ {
+ std::stringstream elementNameStream;
+ elementNameStream << baseName << "[" << i << "]";
+ item.locations.push_back(gl.GetUniformLocation(programId, elementNameStream.str().c_str()));
+ item.offsets.push_back(offset);
+ offset += GetSizeForType(data.type);
+ }
}
}
else
{
+ // Write 1 item with 1 element
+ mDefaultUniformBlock.members.emplace_back();
+ auto& item = mDefaultUniformBlock.members.back();
item.name = data.name;
item.binding = 0;
item.offsets.push_back(offset);
{
// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none
static const char* gGif_100_None = TEST_RESOURCE_DIR "/canvas-none.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none for first frame and previous for the rest
-static const char* gGif_100_Prev = TEST_RESOURCE_DIR "/canvas-prev.gif";
-// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: background
-static const char* gGif_100_Bgnd = TEST_RESOURCE_DIR "/canvas-bgnd.gif";
// this image if not exist, for negative test
static const char* gGifNonExist = "non-exist.gif";
-void VerifyLoad(std::vector<Dali::PixelData>& pixelDataList, Dali::Vector<uint32_t>& frameDelayList, uint32_t frameCount, uint32_t width, uint32_t height, uint32_t delay)
-{
- DALI_TEST_EQUALS(pixelDataList.size(), frameCount, TEST_LOCATION);
- DALI_TEST_EQUALS(frameDelayList.Size(), frameCount, TEST_LOCATION);
-
- for(uint32_t idx = 0; idx < frameCount; idx++)
- {
- // Check the image size and delay of each frame
- DALI_TEST_EQUALS(pixelDataList[idx].GetWidth(), width, TEST_LOCATION);
- DALI_TEST_EQUALS(pixelDataList[idx].GetHeight(), height, TEST_LOCATION);
- DALI_TEST_EQUALS(frameDelayList[idx], delay, TEST_LOCATION);
- }
-}
} // namespace
void utc_dali_animated_image_loader_startup(void)
test_return_value = TET_PASS;
}
-int UtcDaliAnimatedImageLoadingP(void)
-{
- std::vector<Dali::PixelData> pixelDataList;
- Dali::Vector<uint32_t> frameDelayList;
-
- Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
- bool succeed = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
- frameDelayList.Clear();
- frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
- for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
- {
- frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
- }
-
- // Check that the loading succeed
- DALI_TEST_CHECK(succeed);
- VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
- pixelDataList.clear();
- animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Prev, true);
- succeed = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
- frameDelayList.Clear();
- frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
- for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
- {
- frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
- }
-
- // Check that the loading succeed
- DALI_TEST_CHECK(succeed);
- VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
- pixelDataList.clear();
- animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_Bgnd, true);
- succeed = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
- frameDelayList.Clear();
- frameDelayList.Resize(animatedImageLoading.GetImageCount(), 0);
- for(uint32_t i = 0; i < animatedImageLoading.GetImageCount(); ++i)
- {
- frameDelayList[i] = animatedImageLoading.GetFrameInterval(i);
- }
-
- // Check that the loading succeed
- DALI_TEST_CHECK(succeed);
- VerifyLoad(pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u);
-
- END_TEST;
-}
-
-int UtcDaliAnimatedImageLoadingN(void)
-{
- std::vector<Dali::PixelData> pixelDataList;
- Dali::Vector<uint32_t> frameDelayList;
-
- Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGifNonExist, true);
- bool succeed = animatedImageLoading.LoadNextNFrames(0u, animatedImageLoading.GetImageCount(), pixelDataList);
-
- // Check that the loading failed
- DALI_TEST_CHECK(!succeed);
-
- // Check that both pixelDataList and frameDelayList are empty
- DALI_TEST_EQUALS(pixelDataList.size(), 0u, TEST_LOCATION);
-
- END_TEST;
-}
-
int UtcDaliAnimatedImageLoadingGetImageSizeP(void)
{
Dali::AnimatedImageLoading animatedImageLoading = Dali::AnimatedImageLoading::New(gGif_100_None, true);
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// resolution: 2000*2560, pixel format: RGB888
const char* IMAGE_LARGE_EXIF3_RGB = TEST_RESOURCE_DIR "/f-large-exif-3.jpg";
+// resolution: 2048*2048, pixel format: RGB888, YUV420
+const char* IMAGE_LARGE_2048_YUV_420 = TEST_RESOURCE_DIR "/lake_front.jpg";
+
// resolution: 55*64, pixel format: RGB888
const char* IMAGE_WIDTH_ODD_EXIF1_RGB = TEST_RESOURCE_DIR "/f-odd-exif-1.jpg";
// resolution: 55*64, pixel format: RGB888
Dali::Vector<uint8_t> FileToMemory(const char* filename)
{
Dali::Vector<uint8_t> buffer;
- FILE *fp;
+ FILE* fp;
fp = fopen(filename, "rb");
if(fp != NULL)
{
END_TEST;
}
+
+int UtcDaliLoadImagePlanesFromFileP(void)
+{
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+
+ Dali::LoadImagePlanesFromFile(IMAGE_LARGE_2048_YUV_420, pixelBuffers);
+ DALI_TEST_EQUALS(pixelBuffers.size(), 3, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 2048u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 2048u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::L8, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[1].GetPixelFormat(), Pixel::CHROMINANCE_U, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[2].GetPixelFormat(), Pixel::CHROMINANCE_V, TEST_LOCATION);
+
+ pixelBuffers.clear();
+
+ // Test not supported image format: png
+ Dali::LoadImagePlanesFromFile(IMAGE_34_RGBA, pixelBuffers);
+ DALI_TEST_EQUALS(pixelBuffers.size(), 1, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 34u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 34u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION);
+
+ pixelBuffers.clear();
+
+ // Test notsupported chrominace subsampling case
+ Dali::LoadImagePlanesFromFile(IMAGE_128_RGB, pixelBuffers);
+ DALI_TEST_EQUALS(pixelBuffers.size(), 1, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetWidth(), 128u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetHeight(), 128u, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelBuffers[0].GetPixelFormat(), Pixel::RGB888, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliLoadImagePlanesFromFileN(void)
+{
+ std::vector<Devel::PixelBuffer> pixelBuffers;
+
+ Dali::LoadImagePlanesFromFile(IMAGENONEXIST, pixelBuffers);
+ DALI_TEST_CHECK(pixelBuffers.empty());
+
+ END_TEST;
+}
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
DALI_TEST_CHECK(pixelData);
DALI_TEST_EQUALS(pixelData.GetWidth(), 10, TEST_LOCATION);
DALI_TEST_EQUALS(pixelData.GetHeight(), 10, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixelData.GetStride(), 10, TEST_LOCATION);
DALI_TEST_EQUALS(pixelData.GetPixelFormat(), Pixel::RGB565, TEST_LOCATION);
// Try drawing it
FillCheckerboard(pixbuf);
DALI_TEST_EQUALS(pixbuf.GetWidth(), 10, TEST_LOCATION);
+ DALI_TEST_EQUALS(pixbuf.GetStride(), 10, TEST_LOCATION);
END_TEST;
}
/*
- * Copyright 2020 Samsung Electronics Co., Ltd
+ * Copyright 2022 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.
#include <dali/devel-api/atspi-interfaces/text.h>
#include <dali/devel-api/atspi-interfaces/value.h>
#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/window-impl.h>
#include <dali/public-api/dali-adaptor-common.h>
using namespace Dali::Accessibility;
bool GrabHighlight() override
{
- return false;
+ if(!IsUp())
+ {
+ return false;
+ }
+
+ // Only window accessible is able to grab and clear highlight
+ if(!mRoot)
+ {
+ return false;
+ }
+
+ auto self = Self();
+ auto oldHighlightedActor = GetCurrentlyHighlightedActor();
+ if(self == oldHighlightedActor)
+ {
+ return true;
+ }
+
+ // Clear the old highlight.
+ if(oldHighlightedActor)
+ {
+ auto oldHighlightedObject = Dali::Accessibility::Component::DownCast(Accessible::Get(oldHighlightedActor));
+ if(oldHighlightedObject)
+ {
+ oldHighlightedObject->ClearHighlight();
+ }
+ }
+
+ SetCurrentlyHighlightedActor(self);
+
+ auto window = Dali::DevelWindow::Get(self);
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+ windowImpl.EmitAccessibilityHighlightSignal(true);
+
+ return true;
}
bool ClearHighlight() override
{
- return false;
+ if(!IsUp())
+ {
+ return false;
+ }
+
+ // Only window accessible is able to grab and clear highlight
+ if(!mRoot)
+ {
+ return false;
+ }
+
+ auto self = Self();
+ if(self != GetCurrentlyHighlightedActor())
+ {
+ return false;
+ }
+
+ SetCurrentlyHighlightedActor({});
+
+ auto window = Dali::DevelWindow::Get(self);
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+ windowImpl.EmitAccessibilityHighlightSignal(false);
+
+ return true;
}
Role GetRole() const override
Attributes GetAttributes() const override
{
+ Attributes attributes;
+
+ if(mRoot)
+ {
+ Dali::Window window = Dali::DevelWindow::Get(Self());
+ Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window);
+ attributes["resID"] = windowImpl.GetNativeResourceId();
+ }
+
Dali::TypeInfo type;
Self().GetTypeInfo(type);
- return {
- {"class", type.GetName()},
- };
+ attributes["class"] = type.GetName();
+
+ return attributes;
}
bool DoGesture(const GestureInfo& gestureInfo) override
MAX_COUNT\r
};\r
\r
-using AtspiInterfaces = EnumBitSet<AtspiInterface, AtspiInterface::MAX_COUNT>;\r
-using ReadingInfoTypes = EnumBitSet<ReadingInfoType, ReadingInfoType::MAX_COUNT>;\r
-using States = EnumBitSet<State, State::MAX_COUNT>;\r
-using Attributes = std::unordered_map<std::string, std::string>;\r
+/**\r
+ * @brief Enumeration of all AT-SPI events.\r
+ */\r
+enum class AtspiEvent\r
+{\r
+ PROPERTY_CHANGED,\r
+ BOUNDS_CHANGED,\r
+ LINK_SELECTED,\r
+ STATE_CHANGED,\r
+ CHILDREN_CHANGED,\r
+ VISIBLE_DATA_CHANGED,\r
+ SELECTION_CHANGED,\r
+ MODEL_CHANGED,\r
+ ACTIVE_DESCENDANT_CHANGED,\r
+ ROW_INSERTED,\r
+ ROW_REORDERED,\r
+ ROW_DELETED,\r
+ COLUMN_INSERTED,\r
+ COLUMN_REORDERED,\r
+ COLUMN_DELETED,\r
+ TEXT_BOUNDS_CHANGED,\r
+ TEXT_SELECTION_CHANGED,\r
+ TEXT_CHANGED,\r
+ TEXT_ATTRIBUTES_CHANGED,\r
+ TEXT_CARET_MOVED,\r
+ ATTRIBUTES_CHANGED,\r
+ MOVED_OUT,\r
+ WINDOW_CHANGED,\r
+ MAX_COUNT\r
+};\r
+\r
+using AtspiInterfaces = EnumBitSet<AtspiInterface, AtspiInterface::MAX_COUNT>;\r
+using AtspiEvents = EnumBitSet<AtspiEvent, AtspiEvent::MAX_COUNT>;\r
+using ReadingInfoTypes = EnumBitSet<ReadingInfoType, ReadingInfoType::MAX_COUNT>;\r
+using States = EnumBitSet<State, State::MAX_COUNT>;\r
+using Attributes = std::unordered_map<std::string, std::string>;\r
\r
namespace Internal\r
{\r
AnimatedImageLoading::~AnimatedImageLoading()
{
}
-
-bool AnimatedImageLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
- return GetImplementation(*this).LoadNextNFrames(frameStartIndex, count, pixelData);
-}
-
Dali::Devel::PixelBuffer AnimatedImageLoading::LoadFrame(uint32_t frameIndex)
{
return GetImplementation(*this).LoadFrame(frameIndex);
~AnimatedImageLoading();
/**
- * @brief Load the next N Frames of the animated image.
- *
- * @note This function will load the entire animated image into memory if not already loaded.
- * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
- * after the previous invocation of this method, or 0 to start.
- * @param[in] count The number of frames to load
- * @param[out] pixelData The vector in which to return the frame data
- * @return True if the frame data was successfully loaded
- */
- bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData);
-
- /**
* @brief Load a frame of the animated image.
*
* @note This function will load the entire animated image into memory if not already loaded.
{
this->data = data;
}
- char* GetData()
+ char* GetData() const
{
return data;
}
{
return mimeType;
}
- void SetData(char* data)
+ void SetData(const char* data)
{
this->data = data;
}
- char* GetData() const
+ const char* GetData() const
{
return data;
}
private:
const char* mimeType{nullptr}; ///<The mime type of drag data.
- char* data{nullptr}; ///<The drag data.
+ const char* data{nullptr}; ///<The drag data.
};
using DragAndDropFunction = std::function<void(const DragEvent&)>;
#define DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
};
using LoadBitmapFunction = bool (*)(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& pixelData);
+using LoadPlanesFunction = bool (*)(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
using LoadBitmapHeaderFunction = bool (*)(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height);
/**
*/
struct BitmapLoader
{
- unsigned char magicByte1; ///< The first byte in the file should be this
- unsigned char magicByte2; ///< The second byte in the file should be this
- LoadBitmapFunction loader; ///< The function which decodes the file
- LoadBitmapHeaderFunction header; ///< The function which decodes the header of the file
- Dali::Integration::Bitmap::Profile profile; ///< The kind of bitmap to be created
- /// (addressable packed pixels or an opaque compressed blob).
+ unsigned char magicByte1; ///< The first byte in the file should be this
+ unsigned char magicByte2; ///< The second byte in the file should be this
+ LoadBitmapFunction loader; ///< The function which decodes the file
+ LoadPlanesFunction planeLoader; ///< The function which decodes the file to each plane
+ LoadBitmapHeaderFunction header; ///< The function which decodes the header of the file
+ Dali::Integration::Bitmap::Profile profile; ///< The kind of bitmap to be created
+ /// (addressable packed pixels or an opaque compressed blob).
};
} // namespace ImageLoader
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return Dali::Devel::PixelBuffer();
}
+void LoadImagePlanesFromFile(const std::string& url, std::vector<Devel::PixelBuffer>& buffers, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection)
+{
+ Integration::BitmapResourceType resourceType(size, fittingMode, samplingMode, orientationCorrection);
+
+ Internal::Platform::FileReader fileReader(url);
+ FILE* const fp = fileReader.GetFile();
+ if(fp != NULL)
+ {
+ TizenPlatform::ImageLoader::ConvertStreamToPlanes(resourceType, url, fp, buffers);
+ }
+}
+
Devel::PixelBuffer LoadImageFromBuffer(const Dali::Vector<uint8_t>& buffer, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection)
{
if(buffer.Empty())
{
Dali::Devel::PixelBuffer bitmap;
// Make path as empty string. Path information just for file format hint.
- bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap(resourceType, std::string(""), fp, bitmap);
+ bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap(resourceType, std::string(""), fp, bitmap);
if(success && bitmap)
{
return bitmap;
#define DALI_IMAGE_LOADING_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
bool orientationCorrection = true);
/**
+ * @brief Load an image and save each plane to a separate buffer synchronously from local file.
+ *
+ * @note This method is thread safe, i.e. can be called from any thread.
+ * If the image file doesn't support to load planes, this method returns a bitmap image instead.
+ *
+ * @param [in] url The URL of the image file to load.
+ * @param [out] buffers The loaded PixelBuffer object list or an empty list in case loading failed.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
+ * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size.
+ * @param [in] orientationCorrection Reorient the image to respect any orientation metadata in its header.
+ */
+DALI_ADAPTOR_API void LoadImagePlanesFromFile(
+ const std::string& url,
+ std::vector<Devel::PixelBuffer>& buffers,
+ ImageDimensions size = ImageDimensions(0, 0),
+ FittingMode::Type fittingMode = FittingMode::DEFAULT,
+ SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR,
+ bool orientationCorrection = true);
+
+/**
* @brief Load an image synchronously from encoded buffer.
*
* @note This method is thread safe, i.e. can be called from any thread.
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return GetImplementation(*this).GetHeight();
}
+unsigned int PixelBuffer::GetStride() const
+{
+ return GetImplementation(*this).GetStride();
+}
+
Pixel::Format PixelBuffer::GetPixelFormat() const
{
return GetImplementation(*this).GetPixelFormat();
#define DALI_PIXEL_BUFFER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
unsigned int GetHeight() const;
/**
+ * @brief Gets the stride of the buffer in pixels.
+ *
+ * @SINCE_2_1.17
+ * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed.
+ */
+ unsigned int GetStride() const;
+
+ /**
* @brief Gets the pixel format.
*
* @SINCE_1_2.46
#include <memory>
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/adaptor-framework/web-engine-hit-test.h>
#include <dali/devel-api/common/bitwise-enum.h>
#include <dali/public-api/adaptor-framework/native-image-source.h>
virtual void ActivateAccessibility(bool activated) = 0;
/**
+ * @brief Get the accessibility address (bus and path) for embedding.
+ * @return Accessibility address of the root web content element.
+ */
+ virtual Accessibility::Address GetAccessibilityAddress() = 0;
+
+ /**
* @brief Request to set the current page's visibility.
* @param[in] visible Visible or not.
*
GetImplementation(*this).ActivateAccessibility(activated);
}
+Accessibility::Address WebEngine::GetAccessibilityAddress()
+{
+ return GetImplementation(*this).GetAccessibilityAddress();
+}
+
bool WebEngine::SetVisibility(bool visible)
{
return GetImplementation(*this).SetVisibility(visible);
#include <dali/public-api/object/base-handle.h>
//INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
#include <dali/public-api/dali-adaptor-common.h>
void ActivateAccessibility(bool activated);
/**
+ * @brief Get the accessibility address (bus and path) for embedding.
+ * @return Accessibility address of the root web content element.
+ */
+ Accessibility::Address GetAccessibilityAddress();
+
+ /**
* @brief Request to set the current page's visibility.
* @param[in] visible Visible or not.
*
return GetImplementation(window).AuxiliaryMessageSignal();
}
+AccessibilityHighlightSignalType& AccessibilityHighlightSignal(Window window)
+{
+ return GetImplementation(window).AccessibilityHighlightSignal();
+}
+
void SetParent(Window window, Window parent)
{
GetImplementation(window).SetParent(parent);
typedef Signal<void(const std::string&, const std::string&, const Property::Array&)> AuxiliaryMessageSignalType; ///< Auxiliary message signal type
+typedef Signal<void(Window, bool)> AccessibilityHighlightSignalType; ///< Accessibility Highlight signal type
+
/**
* @brief Creates an initialized handle to a new Window.
*
DALI_ADAPTOR_API AuxiliaryMessageSignalType& AuxiliaryMessageSignal(Window window);
/**
+ * @brief This signal is emitted when the window needs to grab or clear accessibility highlight.
+ * The highlight indicates that it is an object to interact with the user regardless of focus.
+ * After setting the highlight on the object, you can do things that the object can do, such as
+ * giving or losing focus.
+ *
+ * This signal is emitted by Dali::Accessibility::Component::GrabHighlight
+ * and Dali::Accessibility::Component::ClearHighlight
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * void YourCallbackName( Window window, bool highlight );
+ * @endcode
+ *
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API AccessibilityHighlightSignalType& AccessibilityHighlightSignal(Window window);
+
+/**
* @brief Sets parent window of the window.
*
* After setting that, these windows do together when raise-up, lower and iconified/deiconified.
return mIsOnRootLevel;
}
+ /**
+ * @brief Gets all suppressed events.
+ *
+ * @return All suppressed events
+ */
+ AtspiEvents GetSuppressedEvents() const
+ {
+ return mSuppressedEvents;
+ }
+
+ /**
+ * @brief Gets all suppressed events.
+ *
+ * @return All suppressed events
+ */
+ AtspiEvents& GetSuppressedEvents()
+ {
+ return mSuppressedEvents;
+ }
+
protected:
Accessible();
Accessible(const Accessible&) = delete;
mutable std::weak_ptr<Bridge::Data> mBridgeData;
mutable AtspiInterfaces mInterfaces;
+ AtspiEvents mSuppressedEvents;
bool mIsOnRootLevel = false;
}; // Accessible class
#define DALI_TEXT_ABSTRACTION_FONT_LIST_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
{
}
+ FontDescription(const FontPath& path,
+ const FontFamily& family,
+ const FontWidth::Type& width,
+ const FontWeight::Type& weight,
+ const FontSlant::Type& slant,
+ const Type& type)
+ : path(path),
+ family(family),
+ width(width),
+ weight(weight),
+ slant(slant),
+ type(type)
+ {
+ }
+
~FontDescription()
{
}
BridgeBase::~BridgeBase()
{
mApplication.mChildren.clear();
- mApplication.mWindows.clear();
}
void BridgeBase::AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor)
}
}
-void BridgeBase::OnWindowVisibilityChanged(Dali::Window window, bool visible)
-{
- if(visible)
- {
- // TODO : Should we check 'out of screen' here? -> Then, we need an actor of this change.
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(window); // Called when Window is shown.
- }
- else
- {
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(window); // Called when Window is hidden and iconified.
- }
-}
-
-void BridgeBase::OnWindowFocusChanged(Dali::Window window, bool focusIn)
-{
- if(focusIn)
- {
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowFocused(window); // Called when Window is focused.
- }
- else
- {
- Dali::Accessibility::Bridge::GetCurrentBridge()->WindowUnfocused(window); // Called when Window is out of focus.
- }
-}
-
void BridgeBase::AddTopLevelWindow(Accessible* windowAccessible)
{
if(windowAccessible->GetInternalActor() == nullptr)
SetIsOnRootLevel(windowAccessible);
RegisterDefaultLabel(windowAccessible);
-
- Dali::Window window = Dali::DevelWindow::Get(windowAccessible->GetInternalActor());
- if(window)
- {
- mApplication.mWindows.push_back(window);
- Dali::DevelWindow::VisibilityChangedSignal(window).Connect(this, &BridgeBase::OnWindowVisibilityChanged);
- window.FocusChangeSignal().Connect(this, &BridgeBase::OnWindowFocusChanged);
- }
}
void BridgeBase::RemoveTopLevelWindow(Accessible* windowAccessible)
{
- for(auto i = 0u; i < mApplication.mWindows.size(); ++i)
- {
- if(windowAccessible->GetInternalActor() == mApplication.mWindows[i].GetRootLayer())
- {
- Dali::DevelWindow::VisibilityChangedSignal(mApplication.mWindows[i]).Disconnect(this, &BridgeBase::OnWindowVisibilityChanged);
- mApplication.mWindows[i].FocusChangeSignal().Disconnect(this, &BridgeBase::OnWindowFocusChanged);
- mApplication.mWindows.erase(mApplication.mWindows.begin() + i);
- break;
- }
- }
-
UnregisterDefaultLabel(windowAccessible);
for(auto i = 0u; i < mApplication.mChildren.size(); ++i)
public:
Dali::Accessibility::ProxyAccessible mParent;
std::vector<Dali::Accessibility::Accessible*> mChildren;
- std::vector<Dali::Window> mWindows;
std::string mName;
std::string GetName() const override
mDirectReadingClient = {};
mDirectReadingCallbacks.clear();
mApplication.mChildren.clear();
- mApplication.mWindows.clear();
ClearTimer();
}
mEnabledSignal.Emit();
- if(mIsShown)
- {
- auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
- auto window = Dali::DevelWindow::Get(rootLayer);
- EmitActivate(window); // Currently, sends a signal that the default window is activated here.
- }
-
return ForceUpResult::JUST_STARTED;
}
void BridgeObject::EmitActiveDescendantChanged(Accessible* obj, Accessible* child)
{
- if(!IsUp() || obj->IsHidden() || child->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::ACTIVE_DESCENDANT_CHANGED] || child->IsHidden())
{
return;
}
{ObjectPropertyChangeEvent::ROLE, "accessible-role"},
};
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::PROPERTY_CHANGED])
{
return;
}
{WindowEvent::RESTYLE, "Restyle"},
};
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::WINDOW_CHANGED])
{
return;
}
{State::HIGHLIGHTABLE, "highlightable"},
};
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::STATE_CHANGED]) // separate ?
{
return;
}
void BridgeObject::EmitBoundsChanged(Accessible* obj, Dali::Rect<> rect)
{
- if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden())
+ if(!IsUp() || !IsBoundsChangedEventAllowed || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::BOUNDS_CHANGED])
{
return;
}
void BridgeObject::EmitCursorMoved(Accessible* obj, unsigned int cursorPosition)
{
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CARET_MOVED])
{
return;
}
{TextChangedState::DELETED, "delete"},
};
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::TEXT_CHANGED])
{
return;
}
void BridgeObject::EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type)
{
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden() || obj->GetSuppressedEvents()[AtspiEvent::MOVED_OUT])
{
return;
}
void BridgeObject::EmitSocketAvailable(Accessible* obj)
{
- if(!IsUp() || obj->IsHidden())
+ if(!IsUp() || obj->IsHidden()) //TODO Suppress SocketAvailable event
{
return;
}
// Set Drag Source Data
mMimeType = data.GetMimeType();
- mData = data.GetData();
+ mData = data.GetData();
// Apply Shadow Property
shadow.SetProperty(Dali::Actor::Property::SIZE, Vector2(150, 150));
mimeTypes[0] = mMimeType.c_str();
mimeTypes[1] = NULL;
-
// Set mime type
ecore_wl2_dnd_drag_types_set(input, (const char**)mimeTypes);
(mMimeType.find("markup") != std::string::npos) ||
(mMimeType.find("image") != std::string::npos))
{
- bufferSize += 1;
+ bufferSize += 1;
}
char* buffer = new char[bufferSize];
memcpy(buffer, mData.c_str(), dataLength);
buffer[dataLength] = '\0';
- write(ev->fd, buffer, bufferSize);
+ auto ret = write(ev->fd, buffer, bufferSize);
+ if(DALI_UNLIKELY(ret != bufferSize))
+ {
+ DALI_LOG_ERROR("write(ev->fd) return %d! Pleacse check it\n", static_cast<int>(ret));
+ }
+
close(ev->fd);
if(mDragWindow)
mDragWindow.Hide();
}
- delete [] buffer;
+ delete[] buffer;
}
void DragAndDropEcoreWl::ReceiveData(void* event)
Dali::DragAndDrop::DragEvent dragEvent;
Dali::Vector2 curPosition(ev->x, ev->y);
- for(int i = 0; i < mDropTargets.size(); i++)
+ for(std::size_t i = 0; i < mDropTargets.size(); i++)
{
Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
// Check the target object region
mTargetIndex = -1;
- for(int i = 0; i < mDropTargets.size(); i++)
+ for(std::size_t i = 0; i < mDropTargets.size(); i++)
{
Vector2 position = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::POSITION);
Vector2 size = mDropTargets[i].target.GetProperty<Vector2>(Dali::Actor::Property::SIZE);
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
fprintf(output, "{\"Cmd\":\"DRAW_INDEXED\"}\n");
break;
}
+ case GLES::CommandType::DRAW_NATIVE:
+ {
+ fprintf(output, "{\"Cmd\":\"DRAW_NATIVE\"}\n");
+ break;
+ }
case GLES::CommandType::DRAW_INDEXED_INDIRECT:
{
fprintf(output, "{\"Cmd\":\"DRAW_INDEXED_INDIRECT\"}\n");
}
mGlAbstraction->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ mGlAbstraction->PixelStorei(GL_UNPACK_ROW_LENGTH, info.srcStride);
+
mCurrentContext->BindTexture(bindTarget, texture->GetTextureTypeId(), texture->GetGLTexture());
if(!isSubImage)
}
// If upload buffer exceeds maximum size, flush.
- if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024)
+ if(mTextureUploadTotalCPUMemoryUsed > TEXTURE_UPLOAD_MAX_BUFER_SIZE_MB * 1024 * 1024)
{
Flush();
mTextureUploadTotalCPUMemoryUsed = 0;
namespace
{
+struct StringSize
+{
+ const char* const mString;
+ const uint32_t mLength;
+
+ template<uint32_t kLength>
+ constexpr StringSize(const char (&string)[kLength])
+ : mString(string),
+ mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
+ {
+ }
+
+ operator const char*() const
+ {
+ return mString;
+ }
+};
+
+bool operator==(const StringSize& lhs, const char* rhs)
+{
+ return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
+}
+
+const char* const DELIMITERS = " \t\n";
+constexpr StringSize UNIFORM{"uniform"};
+constexpr StringSize SAMPLER_PREFIX{"sampler"};
+constexpr StringSize SAMPLER_TYPES[] = {"2D", "Cube", "ExternalOES"};
+constexpr auto END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
+
Dali::Graphics::VertexInputAttributeFormat GetVertexAttributeTypeFormat(GLenum type)
{
switch(type)
return a.location < b.location;
}
-struct StringSize
+std::string GetShaderSource(Dali::Graphics::ShaderState shaderState)
{
- const char* const mString;
- const uint32_t mLength;
+ std::vector<uint8_t> data;
+ auto* shader = static_cast<const Dali::Graphics::GLES::Shader*>(shaderState.shader);
+ auto& shaderCreateInfo = shader->GetCreateInfo();
+ data.resize(shaderCreateInfo.sourceSize + 1);
+ std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
+ data[shaderCreateInfo.sourceSize] = 0;
- template<uint32_t kLength>
- constexpr StringSize(const char (&string)[kLength])
- : mString(string),
- mLength(kLength - 1) // remove terminating null; N.B. there should be no other null.
- {
- }
+ return std::string(reinterpret_cast<char*>(&data[0]));
+}
- operator const char*() const
+void ParseShaderSamplers(std::string shaderSource, std::vector<Dali::Graphics::UniformInfo>& uniformOpaques, int& samplerPosition, std::vector<int>& samplerPositions)
+{
+ if(!shaderSource.empty())
{
- return mString;
- }
-};
+ char* shaderStr = strdup(shaderSource.c_str());
+ char* uniform = strstr(shaderStr, UNIFORM);
-bool operator==(const StringSize& lhs, const char* rhs)
-{
- return strncmp(lhs.mString, rhs, lhs.mLength) == 0;
-}
+ while(uniform)
+ {
+ char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
-const char* const DELIMITERS = " \t\n";
-constexpr StringSize UNIFORM{"uniform"};
-constexpr StringSize SAMPLER_PREFIX{"sampler"};
-constexpr StringSize SAMPLER_TYPES[] = {"2D", "Cube", "ExternalOES"};
-constexpr auto END_SAMPLER_TYPES = SAMPLER_TYPES + std::extent<decltype(SAMPLER_TYPES)>::value;
+ char* nextPtr = nullptr;
+ char* token = strtok_r(outerToken, DELIMITERS, &nextPtr);
+ while(token)
+ {
+ if(SAMPLER_PREFIX == token)
+ {
+ token += SAMPLER_PREFIX.mLength;
+ if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
+ {
+ bool found(false);
+ token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+
+ for(uint32_t i = 0; i < static_cast<uint32_t>(uniformOpaques.size()); ++i)
+ {
+ if(samplerPositions[i] == -1 &&
+ strncmp(token, uniformOpaques[i].name.c_str(), uniformOpaques[i].name.size()) == 0)
+ {
+ samplerPositions[i] = uniformOpaques[i].offset = samplerPosition++;
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
+ }
+ break;
+ }
+ }
+
+ token = strtok_r(nullptr, DELIMITERS, &nextPtr);
+ }
+
+ uniform = strstr(uniform, UNIFORM);
+ }
+ free(shaderStr);
+ }
+}
} // anonymous namespace
auto& programCreateInfo = mProgram.GetCreateInfo();
std::vector<uint8_t> data;
+ std::string vertShader;
std::string fragShader;
for(auto& shaderState : *programCreateInfo.shaderState)
{
- if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
+ if(shaderState.pipelineStage == PipelineStage::VERTEX_SHADER)
{
- auto* shader = static_cast<const GLES::Shader*>(shaderState.shader);
- auto& shaderCreateInfo = shader->GetCreateInfo();
- data.resize(shaderCreateInfo.sourceSize + 1);
- std::memcpy(&data[0], shaderCreateInfo.sourceData, shaderCreateInfo.sourceSize);
- data[shaderCreateInfo.sourceSize] = 0;
- fragShader = std::string(reinterpret_cast<char*>(&data[0]));
- break;
+ vertShader = GetShaderSource(shaderState);
}
- }
-
- if(!fragShader.empty())
- {
- char* shaderStr = strdup(fragShader.c_str());
- char* uniform = strstr(shaderStr, UNIFORM);
- int samplerPosition = 0;
- std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
-
- while(uniform)
+ else if(shaderState.pipelineStage == PipelineStage::FRAGMENT_SHADER)
{
- char* outerToken = strtok_r(uniform + UNIFORM.mLength, ";", &uniform);
-
- char* nextPtr = nullptr;
- char* token = strtok_r(outerToken, DELIMITERS, &nextPtr);
- while(token)
- {
- if(SAMPLER_PREFIX == token)
- {
- token += SAMPLER_PREFIX.mLength;
- if(std::find(SAMPLER_TYPES, END_SAMPLER_TYPES, token) != END_SAMPLER_TYPES)
- {
- bool found(false);
- token = strtok_r(nullptr, DELIMITERS, &nextPtr);
-
- for(uint32_t i = 0; i < static_cast<uint32_t>(mUniformOpaques.size()); ++i)
- {
- if(samplerPositions[i] == -1 &&
- strncmp(token, mUniformOpaques[i].name.c_str(), mUniformOpaques[i].name.size()) == 0)
- {
- samplerPositions[i] = mUniformOpaques[i].offset = samplerPosition++;
- found = true;
- break;
- }
- }
+ fragShader = GetShaderSource(shaderState);
+ }
+ }
- if(!found)
- {
- DALI_LOG_ERROR("Sampler uniform %s declared but not used in the shader\n", token);
- }
- break;
- }
- }
+ int samplerPosition = 0;
+ std::vector<int> samplerPositions(mUniformOpaques.size(), -1);
- token = strtok_r(nullptr, DELIMITERS, &nextPtr);
- }
+ ParseShaderSamplers(vertShader, mUniformOpaques, samplerPosition, samplerPositions);
+ ParseShaderSamplers(fragShader, mUniformOpaques, samplerPosition, samplerPositions);
- uniform = strstr(uniform, UNIFORM);
- }
- free(shaderStr);
- }
std::sort(mUniformOpaques.begin(), mUniformOpaques.end(), [](const UniformInfo& a, const UniformInfo& b) { return a.offset < b.offset; });
}
unsigned char* destBuffer = buffer.GetBuffer();
unsigned int destBytesPerPixel = Dali::Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
-
- int srcOffset = 0;
- int destOffset = 0;
+ unsigned int srcStrideBytes = mask.GetStride() * srcBytesPerPixel;
+ unsigned int destStrideBytes = buffer.GetStride() * destBytesPerPixel;
// if image is premultiplied, the other channels of the image need to multiply by alpha.
if(buffer.IsAlphaPreMultiplied())
{
for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
{
+ int srcOffset = 0;
+ int destOffset = 0;
+
for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
{
auto srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
srcOffset += srcBytesPerPixel;
destOffset += destBytesPerPixel;
}
+ srcBuffer += srcStrideBytes;
+ destBuffer += destStrideBytes;
}
}
}
{
for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
{
+ int srcOffset = 0;
+ int destOffset = 0;
+
for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
{
unsigned char srcAlpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
srcOffset += srcBytesPerPixel;
destOffset += destBytesPerPixel;
}
+ srcBuffer += srcStrideBytes;
+ destBuffer += destStrideBytes;
}
}
}
srcAlphaMask = 0xFF;
}
- unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
unsigned char* srcBuffer = mask.GetBuffer();
+ unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcPixelFormat);
+ unsigned int srcStrideBytes = mask.GetStride() * srcBytesPerPixel;
// Set up source color offsets
Dali::Pixel::Format srcColorPixelFormat = buffer.GetPixelFormat();
unsigned int srcColorBytesPerPixel = Dali::Pixel::GetBytesPerPixel(srcColorPixelFormat);
+ unsigned int srcColorStrideBytes = buffer.GetStride() * srcColorBytesPerPixel;
// Setup destination offsets
Dali::Pixel::Format destPixelFormat = Dali::Pixel::RGBA8888;
int destAlphaMask = 0;
Dali::Pixel::GetAlphaOffsetAndMask(destPixelFormat, destAlphaByteOffset, destAlphaMask);
- PixelBufferPtr newPixelBuffer = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat);
- unsigned char* destBuffer = newPixelBuffer->GetBuffer();
- unsigned char* oldBuffer = buffer.GetBuffer();
+ PixelBufferPtr newPixelBuffer = PixelBuffer::New(buffer.GetWidth(), buffer.GetHeight(), destPixelFormat);
+ unsigned char* destBuffer = newPixelBuffer->GetBuffer();
+ unsigned char* oldBuffer = buffer.GetBuffer();
+ unsigned int destStrideBytes = newPixelBuffer->GetStride() * destBytesPerPixel;
- int srcAlphaOffset = 0;
- int srcColorOffset = 0;
- int destOffset = 0;
- bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
+ bool hasAlpha = Dali::Pixel::HasAlpha(buffer.GetPixelFormat());
unsigned char destAlpha = 0;
for(unsigned int row = 0; row < buffer.GetHeight(); ++row)
{
+ int srcAlphaOffset = 0;
+ int srcColorOffset = 0;
+ int destOffset = 0;
for(unsigned int col = 0; col < buffer.GetWidth(); ++col)
{
unsigned char srcAlpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
srcAlphaOffset += srcBytesPerPixel;
destOffset += destBytesPerPixel;
}
+ oldBuffer += srcColorStrideBytes;
+ srcBuffer += srcStrideBytes;
+ destBuffer += destStrideBytes;
}
return newPixelBuffer;
~AnimatedImageLoading() override = default;
/**
- * @copydoc Dali::AnimatedImageLoading::LoadNextNFrames()
- */
- virtual bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) = 0;
-
- /**
* @copydoc Dali::AnimatedImageLoading::LoadFrame()
*/
virtual Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) = 0;
}
dataBuffer.ResizeUninitialized(dataSize);
- size_t offset = 0;
- for(size_t i = 0; i < chunks.size(); ++i)
+ if(DALI_LIKELY(dataSize > 0))
{
- memcpy(&dataBuffer[offset], &chunks[i].data[0], chunks[i].data.capacity());
- offset += chunks[i].data.capacity();
+ std::uint8_t* dataBufferPtr = dataBuffer.Begin();
+ for(size_t i = 0; i < chunks.size(); ++i)
+ {
+ memcpy(dataBufferPtr, &chunks[i].data[0], chunks[i].data.capacity());
+ dataBufferPtr += chunks[i].data.capacity();
+ }
}
return result;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
*/
// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
#include <memory.h>
#include <cmath>
unsigned char* outBuffer,
const unsigned int bufferWidth,
const unsigned int bufferHeight,
+ const unsigned int inBufferStride,
+ const unsigned int outBufferStride,
const float blurRadius)
{
// Calculate the weights for gaussian blur
for(unsigned int y = 0; y < bufferHeight; y++)
{
unsigned int targetPixelIndex = y;
- unsigned int ioffset = y * bufferWidth;
+ unsigned int ioffset = y * inBufferStride;
for(unsigned int x = 0; x < bufferWidth; x++)
{
float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
outBuffer[targetPixelIndex * 4 + 2] = std::max(0, std::min(static_cast<int>(b + 0.5f), 255));
outBuffer[targetPixelIndex * 4 + 3] = std::max(0, std::min(static_cast<int>(a + 0.5f), 255));
- targetPixelIndex += bufferHeight;
+ targetPixelIndex += outBufferStride;
}
}
{
unsigned int bufferWidth = buffer.GetWidth();
unsigned int bufferHeight = buffer.GetHeight();
+ unsigned int bufferStride = buffer.GetStride();
+
+ if(bufferWidth == 0 || bufferHeight == 0 || bufferStride == 0 || buffer.GetPixelFormat() != Pixel::RGBA8888)
+ {
+ DALI_LOG_ERROR("Invalid buffer!\n");
+ return;
+ }
// Create a temporary buffer for the two-pass blur
PixelBufferPtr softShadowImageBuffer = PixelBuffer::New(bufferWidth, bufferHeight, Pixel::RGBA8888);
- memcpy(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), 4u * bufferWidth * bufferHeight);
// We perform the blur first but write its output image buffer transposed, so that we
// can just do it in two passes. The first pass blurs horizontally and transposes, the
// second pass does the same, but as the image is now transposed, it's really doing a
// vertical blur. The second transposition makes the image the right way up again. This
// is much faster than doing a 2D convolution.
- ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, blurRadius);
- ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, blurRadius);
+ ConvoluteAndTranspose(buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, bufferStride, bufferHeight, blurRadius);
+ ConvoluteAndTranspose(softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, bufferHeight, bufferStride, blurRadius);
// On leaving scope, softShadowImageBuffer will get destroyed.
}
const int IMG_MAX_SIZE = 65000;
constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
-constexpr int LOCAL_CACHED_COLOR_GENERATE_THRESHOLD = 16; ///< Generate color map optimize only if colorCount * threshold < width * height, So we don't loop if image is small
+constexpr int LOCAL_CACHED_COLOR_GENERATE_THRESHOLD = 64; ///< Generate color map optimize only if colorCount * threshold < width * height, So we don't loop if image is small
#if GIFLIB_MAJOR < 5
const int DISPOSE_BACKGROUND = 2; /* Set area too background color */
// precalculated colormap table
std::vector<std::uint32_t> globalCachedColor{};
std::vector<std::uint32_t> localCachedColor{};
- ColorMapObject* localCachedColorMap{nullptr}; // Weak-pointer of ColorMapObject. should be nullptr if image changed
};
// Forward declaration
{
LoaderInfo::FileInfo* fi = reinterpret_cast<LoaderInfo::FileInfo*>(gifFileType->UserData);
- if(fi->position >= fi->length)
+ if(DALI_UNLIKELY(fi->position >= fi->length))
{
return 0; // if at or past end - no
}
{
Internal::Platform::FileReader fileReader(fileName);
FILE* fp = fileReader.GetFile();
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
return false;
}
- if(fseek(fp, 0, SEEK_END) <= -1)
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
{
return false;
}
length = ftell(fp);
- if(length <= -1)
+ if(DALI_UNLIKELY(length <= -1))
{
return false;
}
- if((!fseek(fp, 0, SEEK_SET)))
+ if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
{
globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * length));
length = fread(globalMap, sizeof(GifByteType), length, fp);
size_t dataSize;
succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(fileName, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
- if(succeeded)
+ if(DALI_LIKELY(succeeded))
{
size_t blobSize = dataBuffer.Size();
- if(blobSize > 0U)
+ if(DALI_LIKELY(blobSize > 0U))
{
// Open a file handle on the memory buffer:
Dali::Internal::Platform::FileReader fileReader(dataBuffer, blobSize);
FILE* const fp = fileReader.GetFile();
- if(NULL != fp)
+ if(DALI_LIKELY(NULL != fp))
{
- if((!fseek(fp, 0, SEEK_SET)))
+ if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
{
globalMap = reinterpret_cast<GifByteType*>(malloc(sizeof(GifByteType) * blobSize));
length = fread(globalMap, sizeof(GifByteType), blobSize, fp);
*
* @param[in] animated A structure containing GIF animation data
* @param[in] index Frame index to be searched in GIF
- * @return A pointer to the ImageFrame.
+ * @return single 32-bit (ABGR) value.
*/
-inline int CombinePixelABGR(int a, int r, int g, int b)
+inline std::uint32_t CombinePixelABGR(const std::uint32_t& a, const std::uint32_t& r, const std::uint32_t& g, const std::uint32_t& b)
{
return (((a) << 24) + ((b) << 16) + ((g) << 8) + (r));
}
-inline int PixelLookup(ColorMapObject* colorMap, int index)
+inline std::uint32_t PixelLookup(const ColorMapObject* const& colorMap, int index)
{
return CombinePixelABGR(0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue);
}
/**
+ * @brief Get the Background Color from frameInfo
+ *
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @return single 32-bit (ABGR) value. of background color
+ */
+std::uint32_t GetBackgroundColor(GifFileType* gif, FrameInfo* frameInfo)
+{
+ if(frameInfo->transparent < 0)
+ {
+ ColorMapObject* colorMap;
+ int backGroundColor;
+
+ // work out color to use from colorMap
+ if(gif->Image.ColorMap)
+ {
+ colorMap = gif->Image.ColorMap;
+ }
+ else
+ {
+ colorMap = gif->SColorMap;
+ }
+ backGroundColor = gif->SBackGroundColor;
+ // Get background color from colormap
+ return PixelLookup(colorMap, backGroundColor);
+ }
+ else
+ {
+ // transparent
+ return 0;
+ }
+}
+
+/**
* @brief Brute force find frame index - gifs are normally small so ok for now.
*
* @param[in] animated A structure containing GIF animation data
* @brief Fill in an image with a specific rgba color value.
*
* @param[in] data A pointer pointing to an image data
- * @param[in] row A int containing the number of rows in an image
+ * @param[in] stride A int containing the number of stride in an image
* @param[in] val A uint32_t containing rgba color value
* @param[in] x X-coordinate used an offset to calculate pixel position
* @param[in] y Y-coordinate used an offset to calculate pixel position
* @param[in] width Width of the image
* @param[in] height Height of the image
*/
-void FillImage(uint32_t* data, int row, uint32_t val, int x, int y, int width, int height)
+void FillImage(uint32_t* data, int stride, uint32_t val, int x, int y, int width, int height)
{
- int xAxis, yAxis;
uint32_t* pixelPosition;
- for(yAxis = 0; yAxis < height; yAxis++)
+ // Boost time if stride == width and x == 0. We can assume that all pointer is continuous.
+ if(x == 0 && stride == width)
{
- pixelPosition = data + ((y + yAxis) * row) + x;
- for(xAxis = 0; xAxis < width; xAxis++)
+ pixelPosition = data + (y * stride);
+ // Clear as white or transparent
+ // Special case. we can use memset.
+ if(val == 0x00 || val == 0xffffffffu)
{
- *pixelPosition = val;
- pixelPosition++;
- }
- }
-}
-
-/**
- * @brief Fill a rgba data pixle blob with a frame color (bg or trans)
- *
- * @param[in] data A pointer pointing to an image data
- * @param[in] row A int containing the number of rows in an image
- * @param[in] gif A pointer pointing to GIF File Type
- * @param[in] frameInfo A pointer pointing to Frame Information data
- * @param[in] x X-coordinate used an offset to calculate pixel position
- * @param[in] y Y-coordinate used an offset to calculate pixel position
- * @param[in] width Width of the image
- * @param[in] height Height of the image
- */
-void FillFrame(uint32_t* data, int row, GifFileType* gif, FrameInfo* frameInfo, int x, int y, int w, int h)
-{
- // solid color fill for pre frame region
- if(frameInfo->transparent < 0)
- {
- ColorMapObject* colorMap;
- int backGroundColor;
-
- // work out color to use from colorMap
- if(gif->Image.ColorMap)
- {
- colorMap = gif->Image.ColorMap;
+ const std::int8_t setupVal = val & 0xff;
+ memset(pixelPosition, setupVal, width * height * sizeof(std::uint32_t));
}
else
{
- colorMap = gif->SColorMap;
+ for(int byteCount = 0; byteCount < width * height; ++byteCount)
+ {
+ *pixelPosition = val;
+ ++pixelPosition;
+ }
}
- backGroundColor = gif->SBackGroundColor;
- // and do the fill
- FillImage(data, row, CombinePixelABGR(0xff, colorMap->Colors[backGroundColor].Red, colorMap->Colors[backGroundColor].Green, colorMap->Colors[backGroundColor].Blue), x, y, w, h);
}
- // fill in region with 0 (transparent)
else
{
- FillImage(data, row, 0, x, y, w, h);
+ for(int yAxis = 0; yAxis < height; ++yAxis)
+ {
+ pixelPosition = data + ((y + yAxis) * stride) + x;
+ for(int xAxis = 0; xAxis < width; ++xAxis)
+ {
+ *pixelPosition = val;
+ ++pixelPosition;
+ }
+ }
}
}
* @brief Decode a gif image into rows then expand to 32bit into the destination
* data pointer.
*/
-bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill)
+bool DecodeImage(GifFileType* gif, GifCachedColorData& gifCachedColor, uint32_t* data, int rowpix, int xin, int yin, int transparent, int x, int y, int w, int h, bool fill, uint32_t fillColor = 0u)
{
int intoffset[] = {0, 4, 2, 1};
int intjump[] = {8, 8, 4, 2};
gifW = sp->ImageDesc.Width;
gifH = sp->ImageDesc.Height;
- if((gifW < w) || (gifH < h))
+ if(DALI_UNLIKELY((gifW < w) || (gifH < h)))
{
DALI_LOG_ERROR("gifW : %d, w : %d, gifH : %d, h : %d\n", gifW, w, gifH, h);
DALI_ASSERT_DEBUG(false && "Dimensions are bigger than the Gif image size");
// build a blob of memory to have pointers to rows of pixels
// AND store the decoded gif pixels (1 byte per pixel) as welll
rows = static_cast<GifRowType*>(malloc((gifH * sizeof(GifRowType)) + (gifW * gifH * sizeof(GifPixelType))));
- if(!rows)
+ if(DALI_UNLIKELY(!rows))
{
goto on_error;
}
{
for(yy = intoffset[i]; yy < gifH; yy += intjump[i])
{
- if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)
+ if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
{
goto on_error;
}
{
for(yy = 0; yy < gifH; yy++)
{
- if(DGifGetLine(gif, rows[yy], gifW) != GIF_OK)
+ if(DALI_UNLIKELY(DGifGetLine(gif, rows[yy], gifW) != GIF_OK))
{
goto on_error;
}
if(gif->Image.ColorMap)
{
colorMap = gif->Image.ColorMap;
- // use local cached color map without re-calculate cache.
- if(gifCachedColor.localCachedColorMap == colorMap)
- {
- cachedColorPtr = gifCachedColor.localCachedColor.data();
- }
- // else if w * h is big enough, generate local cached color.
- else if(colorMap->ColorCount * LOCAL_CACHED_COLOR_GENERATE_THRESHOLD < w * h)
+ // if w * h is big enough, generate local cached color.
+ if(colorMap->ColorCount * LOCAL_CACHED_COLOR_GENERATE_THRESHOLD < w * h)
{
gifCachedColor.localCachedColor.resize(colorMap->ColorCount);
for(i = 0; i < colorMap->ColorCount; ++i)
{
gifCachedColor.localCachedColor[i] = PixelLookup(colorMap, i);
}
- gifCachedColor.localCachedColorMap = colorMap;
cachedColorPtr = gifCachedColor.localCachedColor.data();
}
}
else
{
- *p = 0;
+ *p = fillColor;
}
p++;
}
}
else
{
- *p = 0;
+ *p = fillColor;
}
p++;
}
*
* @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
* @param[out] prop A ImageProperties structure for storing information about GIF data.
- * @param[out] error Error code
* @return The true or false whether reading was successful or not.
*/
bool ReadHeader(LoaderInfo& loaderInfo,
- ImageProperties& prop, //output struct
- int* error)
+ ImageProperties& prop)
{
GifAnimationData& animated = loaderInfo.animated;
GifCachedColorData& cachedColor = loaderInfo.cachedColor;
bool full = true;
success = fileData.LoadFile();
- if(!success || !fileData.globalMap)
+ if(DALI_UNLIKELY(!success || !fileData.globalMap))
{
success = false;
DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
prop.h = gifAccessor.gif->SHeight;
// if size is invalid - abort here
- if((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h))
+ if(DALI_UNLIKELY((prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h)))
{
if(IMG_TOO_BIG(prop.w, prop.h))
{
GifByteType* img;
// get image desc
- if(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetImageDesc(gifAccessor.gif) == GIF_ERROR))
{
success = false;
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
break;
}
// skip decoding and just walk image to next
- if(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetCode(gifAccessor.gif, &img_code, &img) == GIF_ERROR))
{
success = false;
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
{
// allocate and save frame with field data
frameInfo = NewFrame(animated, -1, 0, 0, imageNumber + 1);
- if(!frameInfo)
+ if(DALI_UNLIKELY(!frameInfo))
{
success = false;
DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
int disposeMode = (ext[1] >> 2) & 0x7;
int delay = (int(ext[3]) << 8) | int(ext[2]);
frameInfo = NewFrame(animated, transparencyIndex, disposeMode, delay, imageNumber + 1);
- if(!frameInfo)
+ if(DALI_UNLIKELY(!frameInfo))
{
success = false;
DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
cachedColor.globalCachedColor[i] = PixelLookup(colorMap, i);
}
}
- cachedColor.localCachedColorMap = nullptr;
-
- // no errors in header scan etc. so set err and return value
- *error = 0;
}
}
}
index = animated.currentFrame;
// if index is invalid for animated image - error out
- if((animated.animated) && ((index <= 0) || (index > animated.frameCount)))
+ if(DALI_UNLIKELY((animated.animated) && ((index <= 0) || (index > animated.frameCount))))
{
DALI_LOG_ERROR("LOAD_ERROR_GENERIC");
return false;
// find the given frame index
frame = FindFrame(animated, index);
- if(!frame)
+ if(DALI_UNLIKELY(!frame))
{
DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
return false;
loaderInfo.fileInfo.map = fileData.globalMap;
loaderInfo.fileInfo.length = fileData.length;
loaderInfo.fileInfo.position = 0;
- if(!loaderInfo.fileInfo.map)
+ if(DALI_UNLIKELY(!loaderInfo.fileInfo.map))
{
DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
return false;
}
std::unique_ptr<GifAccessor> gifAccessor = std::make_unique<GifAccessor>(loaderInfo.fileInfo);
- if(!gifAccessor->gif)
+ if(DALI_UNLIKELY(!gifAccessor->gif))
{
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
return false;
// walk through gif records in file to figure out info
do
{
- if(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetRecordType(loaderInfo.gifAccessor->gif, &rec) == GIF_ERROR))
{
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
return false;
ImageFrame* thisFrame = NULL;
// get image desc
- if(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetImageDesc(loaderInfo.gifAccessor->gif) == GIF_ERROR))
{
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
return false;
// allocate it
thisFrame->data = new uint32_t[prop.w * prop.h];
- if(!thisFrame->data)
+ if(DALI_UNLIKELY(!thisFrame->data))
{
DALI_LOG_ERROR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
return false;
}
+ // Lazy fill background color feature.
+ // DecodeImage function draw range is EQUAL with previous FillImage range,
+ // We don't need to fill background that time.
+ // It will try to reduce the number of FillImage API call
+ // Note : We might check overlapping. But that operation looks expensive
+ // So, just optimize only if EQUAL case.
+ bool updateBackgroundColorLazy = false;
+ uint32_t backgroundColor = 0u;
+ int prevX = 0;
+ int prevY = 0;
+ int prevW = 0;
+ int prevH = 0;
+
// if we have no prior frame OR prior frame data... empty
if((!previousFrame) || (!previousFrame->data))
{
- first = true;
- frameInfo = &(thisFrame->info);
- memset(thisFrame->data, 0, prop.w * prop.h * sizeof(uint32_t));
+ first = true;
+ frameInfo = &(thisFrame->info);
+ updateBackgroundColorLazy = true;
+ backgroundColor = 0u;
+ prevX = 0;
+ prevY = 0;
+ prevW = prop.w;
+ prevH = prop.h;
}
// we have a prior frame to copy data from...
else
// if dispose mode is "background" then fill with bg
if(frameInfo->dispose == DISPOSE_BACKGROUND)
{
- FillFrame(thisFrame->data, prop.w, loaderInfo.gifAccessor->gif, frameInfo, x, y, w, h);
+ updateBackgroundColorLazy = true;
+ backgroundColor = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+ prevX = x;
+ prevY = y;
+ prevW = w;
+ prevH = h;
}
else if(frameInfo->dispose == DISPOSE_PREVIOUS) // GIF_DISPOSE_RESTORE
{
{
// Find last preserved frame.
lastPreservedFrame = FindFrame(animated, imageNumber - prevIndex);
- if(!lastPreservedFrame)
+ if(DALI_UNLIKELY(!lastPreservedFrame))
{
DALI_LOG_ERROR("LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND");
return false;
// now draw this frame on top
frameInfo = &(thisFrame->info);
ClipCoordinates(prop.w, prop.h, &xin, &yin, frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h, &x, &y, &w, &h);
- if(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first))
+
+ if(updateBackgroundColorLazy)
+ {
+ // If this frame's x,y,w,h is not equal with previous x,y,w,h, FillImage. else, don't fill
+ if(prevX != x || prevY != y || prevW != w || prevH != h)
+ {
+ FillImage(thisFrame->data, prop.w, backgroundColor, prevX, prevY, prevW, prevH);
+ // Don't send background color information to DecodeImage function.
+ updateBackgroundColorLazy = false;
+ }
+ }
+ if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, thisFrame->data, prop.w, xin, yin, frameInfo->transparent, x, y, w, h, first || updateBackgroundColorLazy, backgroundColor)))
{
DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
return false;
frameInfo = &(thisFrame->info);
ClipCoordinates(prop.w, prop.h, &xin, &yin, frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h, &x, &y, &w, &h);
- // clear out all pixels
- FillFrame(reinterpret_cast<uint32_t*>(pixels), prop.w, loaderInfo.gifAccessor->gif, frameInfo, 0, 0, prop.w, prop.h);
+ // clear out all pixels only if x,y,w,h is not whole image.
+ if(x != 0 || y != 0 || w != static_cast<int>(prop.w) || h != static_cast<int>(prop.h))
+ {
+ const std::uint32_t backgroundColor = GetBackgroundColor(loaderInfo.gifAccessor->gif, frameInfo);
+ FillImage(reinterpret_cast<uint32_t*>(pixels), prop.w, backgroundColor, 0, 0, prop.w, prop.h);
+ }
// and decode the gif with overwriting
- if(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true))
+ if(DALI_UNLIKELY(!DecodeImage(loaderInfo.gifAccessor->gif, loaderInfo.cachedColor, reinterpret_cast<uint32_t*>(pixels), prop.w, xin, yin, frameInfo->transparent, x, y, w, h, true, 0u)))
{
DALI_LOG_ERROR("LOAD_ERROR_CORRUPT_FILE\n");
return false;
else
{
// skip decoding and just walk image to next
- if(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetCode(loaderInfo.gifAccessor->gif, &img_code, &img) == GIF_ERROR))
{
DALI_LOG_ERROR("LOAD_ERROR_UNKNOWN_FORMAT\n");
return false;
public:
Impl(const std::string& url, bool isLocalResource)
: mUrl(url),
- mLoadSucceeded(true),
+ mLoadSucceeded(false),
mMutex()
{
loaderInfo.gifAccessor = nullptr;
- int error;
loaderInfo.fileData.fileName = mUrl.c_str();
loaderInfo.fileData.isLocalResource = isLocalResource;
+ }
+
+ bool LoadGifInformation()
+ {
+ // Block to do not load this file again.
+ Mutex::ScopedLock lock(mMutex);
+ if(DALI_LIKELY(mLoadSucceeded))
+ {
+ return mLoadSucceeded;
+ }
- mLoadSucceeded = ReadHeader(loaderInfo, imageProperties, &error);
+ mLoadSucceeded = ReadHeader(loaderInfo, imageProperties);
+ return mLoadSucceeded;
}
// Moveable but not copyable
delete mImpl;
}
-bool GifLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
-{
- int error;
- bool ret = false;
-
- Mutex::ScopedLock lock(mImpl->mMutex);
- if(!mImpl->mLoadSucceeded)
- {
- return false;
- }
-
- const int bufferSize = mImpl->imageProperties.w * mImpl->imageProperties.h * sizeof(uint32_t);
-
- DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count);
-
- for(int i = 0; i < count; ++i)
- {
- auto pixelBuffer = new unsigned char[bufferSize];
-
- mImpl->loaderInfo.animated.currentFrame = 1 + ((frameStartIndex + i) % mImpl->loaderInfo.animated.frameCount);
-
- if(ReadNextFrame(mImpl->loaderInfo, mImpl->imageProperties, pixelBuffer, &error))
- {
- if(pixelBuffer)
- {
- pixelData.push_back(Dali::PixelData::New(pixelBuffer, bufferSize, mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY));
- ret = true;
- }
- }
- }
-
- return ret;
-}
-
Dali::Devel::PixelBuffer GifLoading::LoadFrame(uint32_t frameIndex)
{
int error;
Dali::Devel::PixelBuffer pixelBuffer;
- if(!mImpl->mLoadSucceeded)
+
+ DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+
+ // If Gif file is still not loaded, Load the information.
+ if(DALI_UNLIKELY(!mImpl->LoadGifInformation()))
{
return pixelBuffer;
}
Mutex::ScopedLock lock(mImpl->mMutex);
- DALI_LOG_INFO(gGifLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
-
pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->imageProperties.w, mImpl->imageProperties.h, Dali::Pixel::RGBA8888);
mImpl->loaderInfo.animated.currentFrame = 1 + (frameIndex % mImpl->loaderInfo.animated.frameCount);
ImageDimensions GifLoading::GetImageSize() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
return ImageDimensions(mImpl->imageProperties.w, mImpl->imageProperties.h);
}
uint32_t GifLoading::GetImageCount() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
return mImpl->loaderInfo.animated.frameCount;
}
uint32_t GifLoading::GetFrameInterval(uint32_t frameIndex) const
{
- return mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadGifInformation();
+ }
+
+ uint32_t interval = 0u;
+ if(DALI_LIKELY(mImpl->mLoadSucceeded))
+ {
+ interval = mImpl->loaderInfo.animated.frames[frameIndex].info.delay * 10;
+ }
+ return interval;
}
std::string GifLoading::GetUrl() const
~GifLoading() override;
/**
- * @brief Load the next N Frames of the gif.
- *
- * @note This function will load the entire gif into memory if not already loaded.
- * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
- * after the previous invocation of this method, or 0 to start.
- * @param[in] count The number of frames to load
- * @param[out] pixelData The vector in which to return the frame data
- * @return True if the frame data was successfully loaded
- */
- bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
-
- /**
* @brief Load the next Frame of the animated image.
*
* @note This function will load the entire animated image into memory if not already loaded.
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// clang-format off
const Dali::ImageLoader::BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_COUNT] =
{
- {Png::MAGIC_BYTE_1, Png::MAGIC_BYTE_2, LoadBitmapFromPng, LoadPngHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {Bmp::MAGIC_BYTE_1, Bmp::MAGIC_BYTE_2, LoadBitmapFromBmp, LoadBmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {Gif::MAGIC_BYTE_1, Gif::MAGIC_BYTE_2, LoadBitmapFromGif, LoadGifHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {Webp::MAGIC_BYTE_1, Webp::MAGIC_BYTE_2, LoadBitmapFromWebp, LoadWebpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {Ktx::MAGIC_BYTE_1, Ktx::MAGIC_BYTE_2, LoadBitmapFromKtx, LoadKtxHeader, Bitmap::BITMAP_COMPRESSED },
- {Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED },
- {Ico::MAGIC_BYTE_1, Ico::MAGIC_BYTE_2, LoadBitmapFromIco, LoadIcoHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
- {0x0, 0x0, LoadBitmapFromWbmp, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Png::MAGIC_BYTE_1, Png::MAGIC_BYTE_2, LoadBitmapFromPng, nullptr, LoadPngHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadPlanesFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Bmp::MAGIC_BYTE_1, Bmp::MAGIC_BYTE_2, LoadBitmapFromBmp, nullptr, LoadBmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Gif::MAGIC_BYTE_1, Gif::MAGIC_BYTE_2, LoadBitmapFromGif, nullptr, LoadGifHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Webp::MAGIC_BYTE_1, Webp::MAGIC_BYTE_2, LoadBitmapFromWebp, nullptr, LoadWebpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {Ktx::MAGIC_BYTE_1, Ktx::MAGIC_BYTE_2, LoadBitmapFromKtx, nullptr, LoadKtxHeader, Bitmap::BITMAP_COMPRESSED },
+ {Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, nullptr, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED },
+ {Ico::MAGIC_BYTE_1, Ico::MAGIC_BYTE_2, LoadBitmapFromIco, nullptr, LoadIcoHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
+ {0x0, 0x0, LoadBitmapFromWbmp, nullptr, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS},
};
// clang-format on
bool GetBitmapLoaderFunctions(FILE* fp,
FileFormats format,
Dali::ImageLoader::LoadBitmapFunction& loader,
+ Dali::ImageLoader::LoadPlanesFunction& planeLoader,
Dali::ImageLoader::LoadBitmapHeaderFunction& header,
Bitmap::Profile& profile,
const std::string& filename)
// if a loader was found set the outputs
if(loaderFound)
{
- loader = lookupPtr->loader;
- header = lookupPtr->header;
- profile = lookupPtr->profile;
+ loader = lookupPtr->loader;
+ planeLoader = lookupPtr->planeLoader;
+ header = lookupPtr->header;
+ profile = lookupPtr->profile;
}
// Reset to the start of the file.
namespace ImageLoader
{
-bool ConvertStreamToBitmap(const BitmapResourceType& resource, std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer)
+bool ConvertStreamToBitmap(const BitmapResourceType& resource, const std::string& path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer)
{
DALI_LOG_TRACE_METHOD(gLogFilter);
if(fp != NULL)
{
Dali::ImageLoader::LoadBitmapFunction function;
+ Dali::ImageLoader::LoadPlanesFunction planeLoader;
Dali::ImageLoader::LoadBitmapHeaderFunction header;
Bitmap::Profile profile;
if(GetBitmapLoaderFunctions(fp,
GetFormatHint(path),
function,
+ planeLoader,
header,
profile,
path))
return result;
}
+bool ConvertStreamToPlanes(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers)
+{
+ DALI_LOG_TRACE_METHOD(gLogFilter);
+
+ bool result = false;
+
+ if(fp != NULL)
+ {
+ Dali::ImageLoader::LoadBitmapFunction loader;
+ Dali::ImageLoader::LoadPlanesFunction planeLoader;
+ Dali::ImageLoader::LoadBitmapHeaderFunction header;
+
+ Bitmap::Profile profile;
+
+ if(GetBitmapLoaderFunctions(fp,
+ GetFormatHint(path),
+ loader,
+ planeLoader,
+ header,
+ profile,
+ path))
+ {
+ const Dali::ImageLoader::ScalingParameters scalingParameters(resource.size, resource.scalingMode, resource.samplingMode);
+ const Dali::ImageLoader::Input input(fp, scalingParameters, resource.orientationCorrection);
+
+ pixelBuffers.clear();
+
+ // Run the image type decoder:
+ if(planeLoader)
+ {
+ result = planeLoader(input, pixelBuffers);
+ if(!result)
+ {
+ DALI_LOG_ERROR("Unable to convert %s\n", path.c_str());
+ }
+ }
+ else
+ {
+ Dali::Devel::PixelBuffer pixelBuffer;
+ result = loader(input, pixelBuffer);
+ if(!result)
+ {
+ DALI_LOG_ERROR("Unable to convert %s\n", path.c_str());
+ return false;
+ }
+
+ pixelBuffer = Internal::Platform::ApplyAttributesToBitmap(pixelBuffer, resource.size, resource.scalingMode, resource.samplingMode);
+ if(pixelBuffer)
+ {
+ pixelBuffers.push_back(pixelBuffer);
+ }
+ else
+ {
+ DALI_LOG_ERROR("ApplyAttributesToBitmap is failed [%s]\n", path.c_str());
+ return false;
+ }
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR("Image Decoder for %s unavailable\n", path.c_str());
+ }
+ }
+
+ return result;
+}
+
ResourcePointer LoadImageSynchronously(const Integration::BitmapResourceType& resource, const std::string& path)
{
ResourcePointer result;
if(fp != NULL)
{
Dali::ImageLoader::LoadBitmapFunction loaderFunction;
+ Dali::ImageLoader::LoadPlanesFunction planeLoader;
Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
Bitmap::Profile profile;
if(GetBitmapLoaderFunctions(fp,
GetFormatHint(filename),
loaderFunction,
+ planeLoader,
headerFunction,
profile,
filename))
if(fp != NULL)
{
Dali::ImageLoader::LoadBitmapFunction loaderFunction;
+ Dali::ImageLoader::LoadPlanesFunction planeLoader;
Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
Bitmap::Profile profile;
if(GetBitmapLoaderFunctions(fp,
FORMAT_UNKNOWN,
loaderFunction,
+ planeLoader,
headerFunction,
profile,
""))
#define DALI_TIZEN_PLATFORM_IMAGE_LOADER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
* @param[out] bitmap Pointer to write bitmap to
* @return true on success, false on failure
*/
-bool ConvertStreamToBitmap(const Integration::BitmapResourceType& resource, std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
+bool ConvertStreamToBitmap(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
/**
- * Convert a bitmap and write to a file stream.
+ * Convert a file stream into image planes.
+ * @param[in] resource The resource to convert.
* @param[in] path The path to the resource.
* @param[in] fp File Pointer. Closed on exit.
- * @param[out] pixelData Reference to PixelData object.
+ * @param[out] pixelBuffers Pointer to write buffer to
* @return true on success, false on failure
+ * @note If the image file doesn't support to load planes, this method returns one RGB bitmap image.
*/
-bool ConvertBitmapToStream(std::string path, FILE* const fp, Dali::Devel::PixelBuffer& pixelBuffer);
+bool ConvertStreamToPlanes(const Integration::BitmapResourceType& resource, const std::string& path, FILE* const fp, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
/**
* Loads an image synchronously
using Integration::Bitmap;
using Integration::BitmapPtr;
-typedef unsigned char PixelBuffer;
+typedef uint8_t PixelBuffer;
/**
* @brief 4 byte pixel structure.
* @param[in] pixelsIn The input buffer.
* @param[in] widthIn The width of the input buffer.
* @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
* @param[in] pixelSize The size of the pixel.
* @param[out] pixelsOut The rotated output buffer.
* @param[out] widthOut The width of the output buffer.
bool Rotate90(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
uint8_t*& pixelsOut,
unsigned int& widthOut,
heightOut = widthIn;
// Allocate memory for the rotated buffer.
+ // Output buffer is tightly packed
pixelsOut = static_cast<uint8_t*>(malloc(widthOut * heightOut * pixelSize));
if(nullptr == pixelsOut)
{
// Rotate the buffer.
for(unsigned int y = 0u; y < heightIn; ++y)
{
- const unsigned int srcLineIndex = y * widthIn;
+ const unsigned int srcLineIndex = y * strideIn;
const unsigned int dstX = y;
for(unsigned int x = 0u; x < widthIn; ++x)
{
* @param[in] pixelsIn The input buffer.
* @param[in] widthIn The width of the input buffer.
* @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
* @param[in] pixelSize The size of the pixel.
* @param[out] pixelsOut The rotated output buffer.
*
bool Rotate180(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
uint8_t*& pixelsOut)
{
// Allocate memory for the rotated buffer.
+ // Output buffer is tightly packed
pixelsOut = static_cast<uint8_t*>(malloc(widthIn * heightIn * pixelSize));
if(nullptr == pixelsOut)
{
// Rotate the buffer.
for(unsigned int y = 0u; y < heightIn; ++y)
{
- const unsigned int srcLineIndex = y * widthIn;
+ const unsigned int srcLineIndex = y * strideIn;
const unsigned int dstY = heightIn - y - 1u;
for(unsigned int x = 0u; x < widthIn; ++x)
{
* @param[in] pixelsIn The input buffer.
* @param[in] widthIn The width of the input buffer.
* @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
* @param[in] pixelSize The size of the pixel.
* @param[out] pixelsOut The rotated output buffer.
* @param[out] widthOut The width of the output buffer.
bool Rotate270(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
uint8_t*& pixelsOut,
unsigned int& widthOut,
heightOut = widthIn;
// Allocate memory for the rotated buffer.
+ // Output buffer is tightly packed
pixelsOut = static_cast<uint8_t*>(malloc(widthOut * heightOut * pixelSize));
if(nullptr == pixelsOut)
{
// Rotate the buffer.
for(unsigned int y = 0u; y < heightIn; ++y)
{
- const unsigned int srcLineIndex = y * widthIn;
+ const unsigned int srcLineIndex = y * strideIn;
const unsigned int dstX = widthOut - y - 1u;
for(unsigned int x = 0u; x < widthIn; ++x)
{
*
* @param[in] srcBufferPtr Pointer to the input pixel buffer.
* @param[in] srcWidth The width of the input pixel buffer.
+ * @param[in] srcStride The stride of the input pixel buffer.
* @param[in] pixelSize The size of the pixel.
* @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
* @param[in] dstWidth The width of the output pixel buffer.
*/
void HorizontalSkew(const uint8_t* const srcBufferPtr,
int srcWidth,
+ int srcStride,
unsigned int pixelSize,
uint8_t*& dstBufferPtr,
int dstWidth,
for(i = 0u; i < srcWidth; ++i)
{
// Loop through row pixels
- const unsigned int srcIndex = pixelSize * (row * srcWidth + i);
+ const unsigned int srcIndex = pixelSize * (row * srcStride + i);
unsigned char src[4u] = {0u, 0u, 0u, 0u};
for(unsigned int channel = 0u; channel < pixelSize; ++channel)
* @param[in] srcBufferPtr Pointer to the input pixel buffer.
* @param[in] srcWidth The width of the input pixel buffer.
* @param[in] srcHeight The height of the input pixel buffer.
+ * @param[in] srcStride The stride of the input pixel buffer.
* @param[in] pixelSize The size of the pixel.
* @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
* @param[in] dstWidth The width of the output pixel buffer.
void VerticalSkew(const uint8_t* const srcBufferPtr,
int srcWidth,
int srcHeight,
+ int srcStride,
unsigned int pixelSize,
uint8_t*& dstBufferPtr,
int dstWidth,
for(i = 0; i < srcHeight; ++i)
{
// Loop through column pixels
- const unsigned int srcIndex = pixelSize * (i * srcWidth + column);
+ const unsigned int srcIndex = pixelSize * (i * srcStride + column);
unsigned char src[4u] = {0u, 0u, 0u, 0u};
for(unsigned int channel = 0u; channel < pixelSize; ++channel)
{
const unsigned int inputWidth = bitmap.GetWidth();
const unsigned int inputHeight = bitmap.GetHeight();
+ const unsigned int inputStride = bitmap.GetStride();
if(desiredDimensions.GetWidth() < 1u || desiredDimensions.GetHeight() < 1u)
{
// Add some pre-calculated offsets to the bitmap pointers so this is not done within a loop.
// The cropping is added to the source pointer, and the padding is added to the destination.
const auto bytesPerPixel = Pixel::GetBytesPerPixel(pixelFormat);
- const PixelBuffer* const sourcePixels = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputWidth) + (columnsToCrop / 2)) * bytesPerPixel);
+ const PixelBuffer* const sourcePixels = bitmap.GetBuffer() + ((((scanlinesToCrop / 2) * inputStride) + (columnsToCrop / 2)) * bytesPerPixel);
PixelBuffer* const targetPixels = croppedBitmap.GetBuffer();
PixelBuffer* const targetPixelsActive = targetPixels + ((((scanlinesToPad / 2) * desiredWidth) + (columnsToPad / 2)) * bytesPerPixel);
DALI_ASSERT_DEBUG(sourcePixels && targetPixels);
// Copy the image data to the new bitmap.
// Optimize to a single memcpy if the left and right edges don't need a crop or a pad.
unsigned int outputSpan(desiredWidth * bytesPerPixel);
- if(columnsToCrop == 0 && columnsToPad == 0)
+ if(columnsToCrop == 0 && columnsToPad == 0 && inputStride == inputWidth)
{
memcpy(targetPixelsActive, sourcePixels, (desiredHeight - scanlinesToPad) * outputSpan);
}
{
// The width needs to change (due to either a crop or a pad), so we copy a scanline at a time.
// Precalculate any constants to optimize the inner loop.
- const unsigned int inputSpan(inputWidth * bytesPerPixel);
+ const unsigned int inputSpan(inputStride * bytesPerPixel);
const unsigned int copySpan((desiredWidth - columnsToPad) * bytesPerPixel);
const unsigned int scanlinesToCopy(desiredHeight - scanlinesToPad);
// Source dimensions as loaded from resources (e.g. filesystem):
auto bitmapWidth = bitmap.GetWidth();
auto bitmapHeight = bitmap.GetHeight();
+ auto bitmapStride = bitmap.GetStride();
// Desired dimensions (the rectangle to fit the source image to):
auto desiredWidth = desired.GetWidth();
auto desiredHeight = desired.GetHeight();
auto pixelFormat = bitmap.GetPixelFormat();
// Do the fast power of 2 iterated box filter to get to roughly the right side if the filter mode requests that:
- unsigned int shrunkWidth = -1, shrunkHeight = -1;
- DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight);
+ unsigned int shrunkWidth = -1, shrunkHeight = -1, outStride = -1;
+ DownscaleInPlacePow2(bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, bitmapStride, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight, outStride);
// Work out the dimensions of the downscaled bitmap, given the scaling mode and desired dimensions:
const ImageDimensions filteredDimensions = FitToScalingMode(ImageDimensions(desiredWidth, desiredHeight), ImageDimensions(shrunkWidth, shrunkHeight), fittingMode);
{
if(samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR)
{
- LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), pixelFormat, outputBitmap.GetBuffer(), filteredDimensions);
+ LinearSample(bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), outStride, pixelFormat, outputBitmap.GetBuffer(), filteredDimensions);
}
else
{
- PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight);
+ PointSample(bitmap.GetBuffer(), shrunkWidth, shrunkHeight, outStride, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight);
}
filtered = true;
}
// Copy out the 2^x downscaled, box-filtered pixels if no secondary filter (point or linear) was applied:
if(filtered == false && (shrunkWidth < bitmapWidth || shrunkHeight < bitmapHeight))
{
+ // The buffer is downscaled and it is tightly packed. We don't need to set a stride.
outputBitmap = MakePixelBuffer(bitmap.GetBuffer(), pixelFormat, shrunkWidth, shrunkHeight);
}
}
void DownscaleInPlacePow2Generic(unsigned char* const pixels,
const unsigned int inputWidth,
const unsigned int inputHeight,
+ const unsigned int inputStride,
const unsigned int desiredWidth,
const unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned& outWidth,
- unsigned& outHeight)
+ unsigned& outHeight,
+ unsigned& outStride)
{
if(pixels == 0)
{
// Scale the image until it would be smaller than desired, stopping if the
// resulting height or width would be less than 1:
- unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight;
+ unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight, stride = inputStride;
while(ContinueScaling(dimensionTest, scaledWidth, scaledHeight, desiredWidth, desiredHeight))
{
- const unsigned int lastWidth = scaledWidth;
+ const unsigned int lastWidth = scaledWidth;
+ const unsigned int lastStride = stride;
scaledWidth >>= 1u;
scaledHeight >>= 1u;
+ stride = scaledWidth;
DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Scaling to %u\t%u.\n", scaledWidth, scaledHeight);
for(unsigned int y = 0; y <= lastScanlinePair; ++y)
{
// Scale two scanlines horizontally:
- HalveScanlineInPlace(&pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], lastWidth);
- HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], lastWidth);
+ HalveScanlineInPlace(&pixels[y * 2 * lastStride * BYTES_PER_PIXEL], lastWidth);
+ HalveScanlineInPlace(&pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL], lastWidth);
// Scale vertical pairs of pixels while the last two scanlines are still warm in
// the CPU cache(s):
// images but even a 4k wide RGB888 image will use just 24kB of cache (4k pixels
// * 3 Bpp * 2 scanlines) for two scanlines on the first iteration.
AverageScanlines(
- &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL],
- &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL],
+ &pixels[y * 2 * lastStride * BYTES_PER_PIXEL],
+ &pixels[(y * 2 + 1) * lastStride * BYTES_PER_PIXEL],
&pixels[y * scaledWidth * BYTES_PER_PIXEL],
scaledWidth);
}
///@note: we could finish off with one of two mutually exclusive passes, one squashing horizontally as far as possible, and the other vertically, if we knew a following cpu point or bilinear filter would restore the desired aspect ratio.
outWidth = scaledWidth;
outHeight = scaledHeight;
+ outStride = stride;
}
} // namespace
Pixel::Format pixelFormat,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
unsigned& outWidth,
- unsigned& outHeight)
+ unsigned& outHeight,
+ unsigned& outStride)
{
outWidth = inputWidth;
outHeight = inputHeight;
+ outStride = inputStride;
// Perform power of 2 iterated 4:1 box filtering if the requested filter mode requires it:
if(samplingMode == SamplingMode::BOX || samplingMode == SamplingMode::BOX_THEN_NEAREST || samplingMode == SamplingMode::BOX_THEN_LINEAR)
{
{
case Pixel::RGBA8888:
{
- Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ Internal::Platform::DownscaleInPlacePow2RGBA8888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
break;
}
case Pixel::RGB888:
{
- Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ Internal::Platform::DownscaleInPlacePow2RGB888(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
break;
}
case Pixel::RGB565:
{
- Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ Internal::Platform::DownscaleInPlacePow2RGB565(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
break;
}
case Pixel::LA88:
{
- Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ Internal::Platform::DownscaleInPlacePow2ComponentPair(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
break;
}
case Pixel::L8:
case Pixel::A8:
{
- Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
break;
}
default:
void DownscaleInPlacePow2RGB888(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned& outWidth,
- unsigned& outHeight)
+ unsigned& outHeight,
+ unsigned& outStride)
{
- DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
}
void DownscaleInPlacePow2RGBA8888(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned& outWidth,
- unsigned& outHeight)
+ unsigned& outHeight,
+ unsigned& outStride)
{
DALI_ASSERT_DEBUG(((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms.");
- DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
}
void DownscaleInPlacePow2RGB565(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight)
+ unsigned int& outHeight,
+ unsigned int& outStride)
{
- DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
}
/**
void DownscaleInPlacePow2ComponentPair(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned& outWidth,
- unsigned& outHeight)
+ unsigned& outHeight,
+ unsigned& outStride)
{
- DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
}
void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight)
+ unsigned int& outHeight,
+ unsigned int& outStride)
{
- DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight);
+ DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>(pixels, inputWidth, inputHeight, inputStride, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight, outStride);
}
// Point sampling group below
inline void PointSampleAddressablePixels(const uint8_t* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
uint8_t* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight)
{
DALI_ASSERT_DEBUG(((desiredWidth <= inputWidth && desiredHeight <= inputHeight) ||
- outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
+ outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
"The input and output buffers must not overlap for an upscaling.");
DALI_ASSERT_DEBUG(reinterpret_cast<uint64_t>(inPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...).");
DALI_ASSERT_DEBUG(reinterpret_cast<uint64_t>(outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...).");
{
// Round fixed point y coordinate to nearest integer:
const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
- const PIXEL* const inScanline = &inAligned[inputWidth * integerY];
+ const PIXEL* const inScanline = &inAligned[inputStride * integerY];
PIXEL* const outScanline = &outAligned[desiredWidth * outY];
DALI_ASSERT_DEBUG(integerY < inputHeight);
- DALI_ASSERT_DEBUG(reinterpret_cast<const uint8_t*>(inScanline) < (inPixels + inputWidth * inputHeight * sizeof(PIXEL)));
+ DALI_ASSERT_DEBUG(reinterpret_cast<const uint8_t*>(inScanline) < (inPixels + inputStride * inputHeight * sizeof(PIXEL)));
DALI_ASSERT_DEBUG(reinterpret_cast<uint8_t*>(outScanline) < (outPixels + desiredWidth * desiredHeight * sizeof(PIXEL)));
unsigned int inX = 0;
void PointSample4BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight)
{
- PointSampleAddressablePixels<uint32_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSampleAddressablePixels<uint32_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
}
// RGB565, LA88
void PointSample2BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight)
{
- PointSampleAddressablePixels<uint16_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSampleAddressablePixels<uint16_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
}
// L8, A8
void PointSample1BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight)
{
- PointSampleAddressablePixels<uint8_t>(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSampleAddressablePixels<uint8_t>(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
}
/* RGB888
void PointSample3BPP(const uint8_t* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
uint8_t* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight)
for(unsigned int outY = 0; outY < desiredHeight; ++outY)
{
const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
- const uint8_t* const inScanline = &inPixels[inputWidth * integerY * BYTES_PER_PIXEL];
+ const uint8_t* const inScanline = &inPixels[inputStride * integerY * BYTES_PER_PIXEL];
uint8_t* const outScanline = &outPixels[desiredWidth * outY * BYTES_PER_PIXEL];
unsigned int inX = 0; //< 16.16 fixed-point input image x-coord.
void PointSample(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
Pixel::Format pixelFormat,
unsigned char* outPixels,
unsigned int desiredWidth,
{
case Pixel::RGB888:
{
- PointSample3BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSample3BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
break;
}
case Pixel::RGBA8888:
{
- PointSample4BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSample4BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
break;
}
case Pixel::RGB565:
case Pixel::LA88:
{
- PointSample2BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSample2BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
break;
}
case Pixel::L8:
case Pixel::A8:
{
- PointSample1BPP(inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight);
+ PointSample1BPP(inPixels, inputWidth, inputHeight, inputStride, outPixels, desiredWidth, desiredHeight);
break;
}
default:
bool DEBUG_ASSERT_ALIGNMENT>
inline void LinearSampleGeneric(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
const unsigned int desiredWidth = desiredDimensions.GetWidth();
const unsigned int desiredHeight = desiredDimensions.GetHeight();
- DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL)) ||
+ DALI_ASSERT_DEBUG(((outPixels >= inPixels + inputStride * inputHeight * sizeof(PIXEL)) ||
(inPixels >= outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))) &&
"Input and output buffers cannot overlap.");
if(DEBUG_ASSERT_ALIGNMENT)
DALI_ASSERT_DEBUG(integerY1 < inputHeight);
DALI_ASSERT_DEBUG(integerY2 < inputHeight);
- const PIXEL* const inScanline1 = &inAligned[inputWidth * integerY1];
- const PIXEL* const inScanline2 = &inAligned[inputWidth * integerY2];
+ const PIXEL* const inScanline1 = &inAligned[inputStride * integerY1];
+ const PIXEL* const inScanline2 = &inAligned[inputStride * integerY2];
unsigned int inX = 0;
for(unsigned int outX = 0; outX < desiredWidth; ++outX)
void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>(inPixels, inputDimensions, outPixels, desiredDimensions);
+ LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
}
void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+ LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
}
void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+ LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
}
void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>(inPixels, inputDimensions, outPixels, desiredDimensions);
+ LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
}
void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>(inPixels, inputDimensions, outPixels, desiredDimensions);
+ LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions);
}
void Resample(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions,
Resampler::Filter filterType,
samples[i].ResizeUninitialized(srcWidth);
}
- const int srcPitch = srcWidth * numChannels;
+ const int srcPitch = inputStride * numChannels;
const int dstPitch = dstWidth * numChannels;
int dstY = 0;
void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
- Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true);
+ Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true);
}
void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions)
{
// For L8 images
- Resample(inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false);
+ Resample(inPixels, inputDimensions, inputStride, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false);
}
// Dispatch to a format-appropriate linear sampling function:
void LinearSample(const unsigned char* __restrict__ inPixels,
ImageDimensions inDimensions,
+ unsigned int inStride,
Pixel::Format pixelFormat,
unsigned char* __restrict__ outPixels,
ImageDimensions outDimensions)
{
case Pixel::RGB888:
{
- LinearSample3BPP(inPixels, inDimensions, outPixels, outDimensions);
+ LinearSample3BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
break;
}
case Pixel::RGBA8888:
{
- LinearSample4BPP(inPixels, inDimensions, outPixels, outDimensions);
+ LinearSample4BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
break;
}
case Pixel::L8:
case Pixel::A8:
{
- LinearSample1BPP(inPixels, inDimensions, outPixels, outDimensions);
+ LinearSample1BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
break;
}
case Pixel::LA88:
{
- LinearSample2BPP(inPixels, inDimensions, outPixels, outDimensions);
+ LinearSample2BPP(inPixels, inDimensions, inStride, outPixels, outDimensions);
break;
}
case Pixel::RGB565:
{
- LinearSampleRGB565(inPixels, inDimensions, outPixels, outDimensions);
+ LinearSampleRGB565(inPixels, inDimensions, inStride, outPixels, outDimensions);
break;
}
default:
void RotateByShear(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
float radians,
uint8_t*& pixelsOut,
fastRotationPerformed = Rotate90(pixelsIn,
widthIn,
heightIn,
+ strideIn,
pixelSize,
pixelsOut,
widthOut,
fastRotationPerformed = Rotate180(pixelsIn,
widthIn,
heightIn,
+ strideIn,
pixelSize,
pixelsOut);
fastRotationPerformed = Rotate270(pixelsIn,
widthIn,
heightIn,
+ strideIn,
pixelSize,
pixelsOut,
widthOut,
const uint8_t* const firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn;
std::unique_ptr<uint8_t, void (*)(void*)> tmpPixelsInPtr((fastRotationPerformed ? pixelsOut : nullptr), free);
+ unsigned int stride = fastRotationPerformed ? widthOut : strideIn;
+
// Reset the input/output
widthIn = widthOut;
heightIn = heightOut;
const float shear = angleTangent * ((angleTangent >= 0.f) ? (0.5f + static_cast<float>(y)) : (0.5f + static_cast<float>(y) - static_cast<float>(heightOut)));
const int intShear = static_cast<int>(floor(shear));
- HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
+ HorizontalSkew(firstHorizontalSkewPixelsIn, widthIn, stride, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
}
// Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'.
for(column = 0u; column < widthOut; ++column, offset -= angleSinus)
{
const int shear = static_cast<int>(floor(offset));
- VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>(shear));
+ VerticalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>(shear));
}
// Reset the 'pixel in' pointer with the output of the 'Vertical Skew' and free the memory allocated by the 'First Horizontal Skew'.
// Reset the input/output
for(unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent)
{
const int shear = static_cast<int>(floor(offset));
- HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>(shear));
+ HorizontalSkew(tmpPixelsInPtr.get(), tmpWidthIn, tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>(shear));
}
// The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
void HorizontalShear(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
float radians,
uint8_t*& pixelsOut,
const float shear = radians * ((radians >= 0.f) ? (0.5f + static_cast<float>(y)) : (0.5f + static_cast<float>(y) - static_cast<float>(heightOut)));
const int intShear = static_cast<int>(floor(shear));
- HorizontalSkew(pixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
+ HorizontalSkew(pixelsIn, widthIn, strideIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>(intShear));
}
}
* @param[in] pixelFormat The format of the image pointed at by pixels.
* @param[in] inputWidth The width of the input image.
* @param[in] inputHeight The height of the input image.
+ * @param[in] inputStride The stride of the input image.
* @param[in] desiredWidth The width the client is requesting.
* @param[in] desiredHeight The height the client is requesting.
* @param[out] outWidth The resulting width after downscaling.
* @param[out] outHeight The resulting height after downscaling.
+ * @param[out] outStride The resulting stride after downscaling.
*/
void DownscaleInPlacePow2(unsigned char* const pixels,
Pixel::Format pixelFormat,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
FittingMode::Type fittingMode,
SamplingMode::Type samplingMode,
unsigned& outWidth,
- unsigned& outHeight);
+ unsigned& outHeight,
+ unsigned& outStride);
/**
* @brief Destructive in-place downscaling by a power of 2 factor.
* @param[in,out] pixels The buffer both to read from and write the result to.
* @param[in] inputWidth The width of the input image.
* @param[in] inputHeight The height of the input image.
+ * @param[in] inputStride The stride of the input image.
* @param[in] desiredWidth The width the client is requesting.
* @param[in] desiredHeight The height the client is requesting.
* @param[out] outWidth The resulting width after downscaling.
* @param[out] outHeight The resulting height after downscaling.
+ * @param[out] outStride The resulting stride after downscaling.
*/
void DownscaleInPlacePow2RGB888(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight);
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
void DownscaleInPlacePow2RGBA8888(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight);
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
void DownscaleInPlacePow2RGB565(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight);
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
void DownscaleInPlacePow2ComponentPair(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight);
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @copydoc DownscaleInPlacePow2RGB888
void DownscaleInPlacePow2SingleBytePerPixel(unsigned char* pixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned int desiredWidth,
unsigned int desiredHeight,
BoxDimensionTest dimensionTest,
unsigned int& outWidth,
- unsigned int& outHeight);
+ unsigned int& outHeight,
+ unsigned int& outStride);
/**
* @brief Rescales an input image into the exact output dimensions passed-in.
void PointSample(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
Pixel::Format pixelFormat,
unsigned char* outPixels,
unsigned int desiredWidth,
void PointSample4BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight);
void PointSample3BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight);
void PointSample2BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight);
void PointSample1BPP(const unsigned char* inPixels,
unsigned int inputWidth,
unsigned int inputHeight,
+ unsigned int inputStride,
unsigned char* outPixels,
unsigned int desiredWidth,
unsigned int desiredHeight);
*/
void LinearSample(const unsigned char* __restrict__ inPixels,
ImageDimensions inDimensions,
+ unsigned int inStride,
Pixel::Format pixelFormat,
unsigned char* __restrict__ outPixels,
ImageDimensions outDimensions);
*/
void LinearSample1BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*/
void LinearSample2BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*/
void LinearSampleRGB565(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*/
void LinearSample3BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*/
void LinearSample4BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
* @param[out] outPixels Pointer to the output image buffer.
* @param[in] desiredDimensions The output dimensions of the image.
*/
void LanczosSample4BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
* @param[out] outPixels Pointer to the output image buffer.
* @param[in] desiredDimensions The output dimensions of the image.
*/
void LanczosSample1BPP(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions);
*
* @param[in] inPixels Pointer to the input image buffer.
* @param[in] inputDimensions The input dimensions of the image.
+ * @param[in] inputStride The input stride of the image.
* @param[out] outPixels Pointer to the output image buffer.
* @param[in] desiredDimensions The output dimensions of the image.
*/
void Resample(const unsigned char* __restrict__ inPixels,
ImageDimensions inputDimensions,
+ unsigned int inputStride,
unsigned char* __restrict__ outPixels,
ImageDimensions desiredDimensions,
Resampler::Filter filterType,
* @param[in] pixelsIn The input buffer.
* @param[in] widthIn The width of the input buffer.
* @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
* @param[in] pixelSize The size of the pixel.
* @param[in] radians The rotation angle in radians.
* @param[out] pixelsOut The rotated output buffer.
void RotateByShear(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
float radians,
uint8_t*& pixelsOut,
* @param[in] pixelsIn The input buffer.
* @param[in] widthIn The width of the input buffer.
* @param[in] heightIn The height of the input buffer.
+ * @param[in] strideIn The stride of the input buffer.
* @param[in] pixelSize The size of the pixel.
* @param[in] radians The shear angle in radians.
* @param[out] pixelsOut The rotated output buffer.
void HorizontalShear(const uint8_t* const pixelsIn,
unsigned int widthIn,
unsigned int heightIn,
+ unsigned int strideIn,
unsigned int pixelSize,
float radians,
uint8_t*& pixelsOut,
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
{
// Pull the bytes of the file header in as a block:
const unsigned int readLength = sizeof(AstcFileHeader);
- if(fread(&fileHeader, 1, readLength, filePointer) != readLength)
+ if(DALI_UNLIKELY(fread(&fileHeader, 1, readLength, filePointer) != readLength))
{
return false;
}
// Check the header contains the ASTC native file identifier.
bool headerIsValid = memcmp(fileHeader.magic, FileIdentifier, sizeof(fileHeader.magic)) == 0;
- if(!headerIsValid)
+ if(DALI_UNLIKELY(!headerIsValid))
{
DALI_LOG_ERROR("File is not a valid ASTC native file\n");
// Return here as otherwise, if not a valid ASTC file, we are likely to pick up other header errors spuriously.
const unsigned int zDepth = static_cast<unsigned int>(fileHeader.zsize[0]) + (static_cast<unsigned int>(fileHeader.zsize[1]) << 8) + (static_cast<unsigned int>(fileHeader.zsize[2]) << 16);
// Check image dimensions are within limits.
- if((width > MAX_TEXTURE_DIMENSION) || (height > MAX_TEXTURE_DIMENSION))
+ if(DALI_UNLIKELY((width > MAX_TEXTURE_DIMENSION) || (height > MAX_TEXTURE_DIMENSION)))
{
DALI_LOG_ERROR("ASTC file has larger than supported dimensions: %d,%d\n", width, height);
headerIsValid = false;
}
// Confirm the ASTC block does not have any Z depth.
- if(zDepth != 1)
+ if(DALI_UNLIKELY(zDepth != 1))
{
DALI_LOG_ERROR("ASTC files with z size other than 1 are not supported. Z size is: %d\n", zDepth);
headerIsValid = false;
bool LoadBitmapFromAstc(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
{
FILE* const filePointer = input.file;
- if(!filePointer)
+ if(DALI_UNLIKELY(!filePointer))
{
DALI_LOG_ERROR("Null file handle passed to ASTC compressed bitmap file loader.\n");
return false;
AstcFileHeader fileHeader;
unsigned int width, height;
- if(!LoadAstcHeader(filePointer, width, height, fileHeader))
+ if(DALI_UNLIKELY(!LoadAstcHeader(filePointer, width, height, fileHeader)))
{
DALI_LOG_ERROR("Could not load ASTC Header from file.\n");
return false;
// Retrieve the pixel format from the ASTC block size.
Pixel::Format pixelFormat = GetAstcPixelFormat(fileHeader);
- if(pixelFormat == Pixel::INVALID)
+ if(DALI_UNLIKELY(pixelFormat == Pixel::INVALID))
{
DALI_LOG_ERROR("No internal pixel format supported for ASTC file pixel format.\n");
return false;
}
// Retrieve the file size.
- if(fseek(filePointer, 0L, SEEK_END))
+ if(DALI_UNLIKELY(fseek(filePointer, 0L, SEEK_END)))
{
DALI_LOG_ERROR("Could not seek through file.\n");
return false;
}
off_t fileSize = ftell(filePointer);
- if(fileSize == -1L)
+ if(DALI_UNLIKELY(fileSize == -1L))
{
DALI_LOG_ERROR("Could not determine ASTC file size.\n");
return false;
}
- if(fseek(filePointer, sizeof(AstcFileHeader), SEEK_SET))
+ if(DALI_UNLIKELY(fseek(filePointer, sizeof(AstcFileHeader), SEEK_SET)))
{
DALI_LOG_ERROR("Could not seek through file.\n");
return false;
size_t imageByteCount = fileSize - sizeof(AstcFileHeader);
// Sanity-check the image data is not too large and that it is at less than 2 bytes per texel:
- if((imageByteCount > MAX_IMAGE_DATA_SIZE) || (imageByteCount > ((static_cast<size_t>(width) * height) << 1)))
+ if(DALI_UNLIKELY((imageByteCount > MAX_IMAGE_DATA_SIZE) || (imageByteCount > ((static_cast<size_t>(width) * height) << 1))))
{
DALI_LOG_ERROR("ASTC file has too large image-data field.\n");
return false;
const size_t bytesRead = fread(pixels, 1, imageByteCount, filePointer);
// Check the size of loaded data is what we expected.
- if(bytesRead != imageByteCount)
+ if(DALI_UNLIKELY(bytesRead != imageByteCount))
{
DALI_LOG_ERROR("Read of image pixel data failed.\n");
return false;
const unsigned int readLength = sizeof(T);
// Load the information directly into our structure
- if(fread(&header, 1, readLength, fp) != readLength)
+ if(DALI_UNLIKELY(fread(&header, 1, readLength, fp) != readLength))
{
return false;
}
bool LoadBmpHeader(FILE* fp, unsigned int& width, unsigned int& height, BmpFileHeader& fileHeader, BmpInfoHeader& infoHeader)
{
- if(!ReadHeader(fp, fileHeader))
+ if(DALI_UNLIKELY(!ReadHeader(fp, fileHeader)))
{
DALI_LOG_ERROR("File header read failed\n");
return false;
}
- if(!ReadHeader(fp, infoHeader))
+ if(DALI_UNLIKELY(!ReadHeader(fp, infoHeader)))
{
DALI_LOG_ERROR("Info header read failed\n");
return false;
width = infoHeader.width;
height = abs(infoHeader.height);
- if(infoHeader.width == 0)
+ if(DALI_UNLIKELY(infoHeader.width == 0))
{
DALI_LOG_ERROR("Invalid header size\n");
return false;
unsigned int rowStride,
unsigned int padding)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
return false;
{
pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
}
- if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+ if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
if(padding)
{
// move past the padding.
- if(fseek(fp, padding, SEEK_CUR))
+ if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
{
DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
}
unsigned int rowStride,
unsigned int padding)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
return false;
{
pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
}
- if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+ if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
if(padding)
{
// move past the padding.
- if(fseek(fp, padding, SEEK_CUR))
+ if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
{
DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
}
unsigned int rowStride,
unsigned int padding)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
return false;
pixelsPtr = pixels + (((height - 1) - yPos) * rowStride);
}
- if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+ if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
if(padding)
{
// move past the padding.
- if(fseek(fp, padding, SEEK_CUR))
+ if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR)))
{
DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding RGB565 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking RGB565 data\n");
return false;
// the data in the file is bottom up, and we store the data top down
pixelsPtr = pixels + (((height - 1) - i) * rowStride);
}
- if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+ if(DALI_UNLIKELY(fread(pixelsPtr, 1, rowStride, fp) != rowStride))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
return false;
for(std::uint32_t j = 0; j < height; ++j)
{
rawPtr = &raw[0] + (j * rawStride);
- if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+ if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
return false;
for(std::uint32_t j = 0; j < height; ++j)
{
rawPtr = &raw[0] + (j * rawStride);
- if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+ if(DALI_UNLIKELY(fread(rawPtr, 1, rawStride, fp) != rawStride))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
return false;
std::vector<std::uint8_t> colorIndex(fillw * height);
std::uint32_t rowStride = fillw * 3; // RGB
- if(fread(colorTable, 1, 8, fp) != 8)
+ if(DALI_UNLIKELY(fread(colorTable, 1, 8, fp) != 8))
{
return false;
}
for(std::uint32_t i = 0; i < fillw * height; i += 8)
{
- if(fread(&cmd, 1, 1, fp) != 1)
+ if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
return false;
std::vector<std::uint8_t> colorIndex(fillw * height);
std::uint32_t rowStride = fillw * 3;
- if(fread(colorTable, 1, 64, fp) != 64)
+ if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
{
return false;
}
for(std::uint32_t i = 0; i < fillw * height; i += 2)
{
- if(fread(&cmd, 1, 1, fp) != 1)
+ if(DALI_UNLIKELY(fread(&cmd, 1, 1, fp) != 1))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
return false;
}
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
return false;
std::vector<std::uint8_t> colorIndex(width * height);
std::uint32_t rowStride = width * 3; //RGB8->RGB24
- if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+ if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
{
return false;
}
- if(fread(&colorIndex[0], 1, width * height, fp) != width * height)
+ if(DALI_UNLIKELY(fread(&colorIndex[0], 1, width * height, fp) != width * height))
{
return false;
}
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
return false;
bool finish = false;
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
return false;
}
- if(fread(colorTable, 1, 64, fp) != 64)
+ if(DALI_UNLIKELY(fread(colorTable, 1, 64, fp) != 64))
{
return false;
}
{
break;
}
- if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+ if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
{
return false;
}
y++;
break;
case 2: // delta
- if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+ if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
bytesize >>= 1;
bytesize += (bytesize & 1);
run.resize(bytesize);
- if(fread(&run[0], 1, bytesize, fp) != bytesize)
+ if(DALI_UNLIKELY(fread(&run[0], 1, bytesize, fp) != bytesize))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
unsigned int offset,
bool topDown)
{
- if(fp == NULL || pixels == NULL)
+ if(DALI_UNLIKELY(fp == NULL || pixels == NULL))
{
DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
return false;
std::uint8_t cmd[2];
std::vector<std::uint8_t> colorIndex(width * height);
- if(fseek(fp, offset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, offset, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
return false;
}
- if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+ if(DALI_UNLIKELY(fread(&colorTable[0], 1, 1024, fp) != 1024))
{
return false;
}
std::vector<std::uint8_t> run;
while((x + y * width) < width * height)
{
- if(finish)
+ if(DALI_UNLIKELY(finish))
{
break;
}
- if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+ if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
{
return false;
}
y++;
break;
case 2: // delta
- if(fread(cmd, 1, cmdStride, fp) != cmdStride)
+ if(DALI_UNLIKELY(fread(cmd, 1, cmdStride, fp) != cmdStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
//absolute mode must be word-aligned
length += (length & 1);
run.resize(length);
- if(fread(&run[0], 1, length, fp) != length)
+ if(DALI_UNLIKELY(fread(&run[0], 1, length, fp) != length))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
return false;
{
//DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
FILE* const fp = input.file;
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
DALI_LOG_ERROR("Error loading bitmap\n");
return false;
// Load the header info
unsigned int width, height;
- if(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
+ if(DALI_UNLIKELY(!LoadBmpHeader(fp, width, height, fileHeader, infoHeader)))
{
return false;
}
{
if(infoHeader.bitsPerPixel == 16)
{
- if(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET)))
{
return false;
}
char mask;
- if(fread(&mask, 1, 1, fp) != 1)
+ if(DALI_UNLIKELY(fread(&mask, 1, 1, fp) != 1))
{
return false;
}
pixelsIterator = pixels + (((height - 1) - yPos) * rowStride);
}
- if(fread(pixelsIterator, 1, rowStride, fp) != rowStride)
+ if(DALI_UNLIKELY(fread(pixelsIterator, 1, rowStride, fp) != rowStride))
{
DALI_LOG_ERROR("Error reading the BMP image\n");
break;
if(padding)
{
- if(fseek(fp, padding, SEEK_CUR)) // move past the padding.
+ if(DALI_UNLIKELY(fseek(fp, padding, SEEK_CUR))) // move past the padding.
{
DALI_LOG_ERROR("Error moving past BMP padding\n");
}
}
} // switch
- if(!decodeResult)
+ if(DALI_UNLIKELY(!decodeResult))
{
DALI_LOG_ERROR("Decoding failed\n");
return false;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
*gifInfo = DGifOpen(reinterpret_cast<void*>(fp), ReadDataFromGif);
#endif
- if(!(*gifInfo) || errorCode)
+ if(DALI_UNLIKELY(!(*gifInfo) || errorCode))
{
DALI_LOG_ERROR("GIF Loader: DGifOpen Error. Code: %d\n", errorCode);
return false;
height = (*gifInfo)->SHeight;
// No proper size in GIF.
- if(width <= 0 || height <= 0)
+ if(DALI_UNLIKELY(width <= 0 || height <= 0))
{
return false;
}
for(unsigned int currentByte = interlacePairPtr->startingByte; currentByte < height; currentByte += interlacePairPtr->incrementalByte)
{
unsigned char* row = decodedData + currentByte * bytesPerRow;
- if(DGifGetLine(gifInfo, row, width) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetLine(gifInfo, row, width) == GIF_ERROR))
{
DALI_LOG_ERROR("GIF Loader: Error reading Interlaced GIF\n");
return false;
for(unsigned int row = 0; row < height; ++row)
{
- if(DGifGetLine(gifInfo, decodedDataPtr, width) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetLine(gifInfo, decodedDataPtr, width) == GIF_ERROR))
{
DALI_LOG_ERROR("GIF Loader: Error reading non-interlaced GIF\n");
return false;
/// Called when we want to handle IMAGE_DESC_RECORD_TYPE
bool HandleImageDescriptionRecordType(Dali::Devel::PixelBuffer& bitmap, GifFileType* gifInfo, unsigned int width, unsigned int height, bool& finished)
{
- if(DGifGetImageDesc(gifInfo) == GIF_ERROR)
+ if(DALI_UNLIKELY(DGifGetImageDesc(gifInfo) == GIF_ERROR))
{
DALI_LOG_ERROR("GIF Loader: Error getting Image Description\n");
return false;
}
// Ensure there is at least 1 image in the GIF.
- if(gifInfo->ImageCount < 1)
+ if(DALI_UNLIKELY(gifInfo->ImageCount < 1))
{
DALI_LOG_ERROR("GIF Loader: No Images\n");
return false;
bitmap = Dali::Devel::PixelBuffer::New(actualWidth, actualHeight, pixelFormat);
// Decode the GIF Image
- if(!DecodeImage(gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow))
+ if(DALI_UNLIKELY(!DecodeImage(gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow)))
{
return false;
}
extensionByte != NULL;
extRetCode = DGifGetExtensionNext(gifInfo, &extensionByte))
{
- if(extRetCode == GIF_ERROR)
+ if(DALI_UNLIKELY(extRetCode == GIF_ERROR))
{
DALI_LOG_ERROR("GIF Loader: Error reading GIF Extension record.\n");
return false;
GifFileType* gifInfo(NULL);
unsigned int width(0);
unsigned int height(0);
- if(!LoadGifHeader(fp, width, height, &gifInfo))
+ if(DALI_UNLIKELY(!LoadGifHeader(fp, width, height, &gifInfo)))
{
return false;
}
!finished && recordType != TERMINATE_RECORD_TYPE;
returnCode = DGifGetRecordType(gifInfo, &recordType))
{
- if(returnCode == GIF_ERROR)
+ if(DALI_UNLIKELY(returnCode == GIF_ERROR))
{
DALI_LOG_ERROR("GIF Loader: Error getting Record Type\n");
return false;
if(IMAGE_DESC_RECORD_TYPE == recordType)
{
- if(!HandleImageDescriptionRecordType(bitmap, gifInfo, width, height, finished))
+ if(DALI_UNLIKELY(!HandleImageDescriptionRecordType(bitmap, gifInfo, width, height, finished)))
{
return false;
}
}
else if(EXTENSION_RECORD_TYPE == recordType)
{
- if(!HandleExtensionRecordType(gifInfo))
+ if(DALI_UNLIKELY(!HandleExtensionRecordType(gifInfo)))
{
return false;
}
#define ARGB_JOIN(a, r, g, b) \
(((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
-bool read_ushort(unsigned char* map, size_t length, size_t* position, unsigned short* ret)
+bool read_ushort(const unsigned char* const& map, size_t length, size_t* position, unsigned short* ret)
{
unsigned char b[2];
- if(*position + 2 > length)
+ if(DALI_UNLIKELY(*position + 2 > length))
{
return false;
}
return true;
}
-bool read_uint(unsigned char* map, size_t length, size_t* position, unsigned int* ret)
+bool read_uint(const unsigned char* const& map, size_t length, size_t* position, unsigned int* ret)
{
unsigned char b[4];
unsigned int i;
- if(*position + 4 > length)
+ if(DALI_UNLIKELY(*position + 4 > length))
{
return false;
}
return true;
}
-bool read_uchar(unsigned char* map, size_t length, size_t* position, unsigned char* ret)
+bool read_uchar(const unsigned char* const& map, size_t length, size_t* position, unsigned char* ret)
{
- if(*position + 1 > length)
+ if(DALI_UNLIKELY(*position + 1 > length))
{
return false;
}
return true;
}
-bool read_mem(unsigned char* map, size_t length, size_t* position, void* buffer, int size)
+bool read_mem(const unsigned char* const& map, size_t length, size_t* position, void* buffer, int size)
{
- if(*position + size > length)
+ if(DALI_UNLIKELY(*position + size > length))
{
return false;
}
{
memset(&chosen, 0, sizeof(chosen));
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
DALI_LOG_ERROR("Error loading bitmap\n");
return false;
unsigned short word;
unsigned char byte;
- if(fseek(fp, 0, SEEK_END))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
{
DALI_LOG_ERROR("Error seeking ICO data\n");
return false;
fsize = static_cast<unsigned int>(positionIndicator);
}
- if(0u == fsize)
+ if(DALI_UNLIKELY(0u == fsize))
{
return false;
}
- if(fseek(fp, 0, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking ICO data\n");
return false;
}
- if(fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
+ if(DALI_UNLIKELY(fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER))) //6 + 16 + 40
{
return false;
}
map.ResizeUninitialized(fsize);
-
- if(fread(&map[0], 1, fsize, fp) != fsize)
+ if(DALI_UNLIKELY(fread(&map[0], 1, fsize, fp) != fsize))
{
DALI_LOG_WARNING("image file read opeation error!\n");
return false;
}
+ const std::uint8_t* const inputBufferPtr = &map[0];
+
int search = BIGGEST;
unsigned short reserved, type, count;
- if(!read_ushort(&map[0], fsize, &position, &reserved))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &reserved)))
{
return false;
}
- if(!read_ushort(&map[0], fsize, &position, &type))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &type)))
{
return false;
}
- if(!read_ushort(&map[0], fsize, &position, &count))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &count)))
{
return false;
}
- if(!((reserved == 0) &&
- ((type == ICON) || (type == CURSOR)) && (count != 0)))
+ if(DALI_UNLIKELY(!((reserved == 0) &&
+ ((type == ICON) || (type == CURSOR)) && (count != 0))))
{
return false;
}
for(unsigned short i = 0; i < count; i++)
{
unsigned char tw = 0, th = 0, tcols = 0;
- if(!read_uchar(&map[0], fsize, &position, &tw))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &tw)))
{
return false;
}
{
w = 256;
}
- if(!read_uchar(&map[0], fsize, &position, &th))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &th)))
{
return false;
}
{
h = 256;
}
- if(!read_uchar(&map[0], fsize, &position, &tcols))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &tcols)))
{
return false;
}
int cols = tcols;
- if(!read_uchar(&map[0], fsize, &position, &byte))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &byte)))
{
return false;
}
- if(!read_ushort(&map[0], fsize, &position, &word))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
{
return false;
}
planes = word;
}
//else hot_x = word;
- if(!read_ushort(&map[0], fsize, &position, &word))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
{
return false;
}
//else hot_y = word;
unsigned int bmoffset, bmsize;
- if(!read_uint(&map[0], fsize, &position, &bmsize))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &bmsize)))
{
return false;
}
- if(!read_uint(&map[0], fsize, &position, &bmoffset))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &bmoffset)))
{
return false;
}
- if((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
+ if(DALI_UNLIKELY((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize)))
{
return false;
}
}
}
- if(chosen.bmoffset == 0)
+ if(DALI_UNLIKELY(chosen.bmoffset == 0))
{
return false;
}
/**
* @brief Handle the different bits per pixel
* @param[in] bitcount The bit count
- * @param[in/out] map The map to use/set
+ * @param[in] inputBufferPtr The map to use
* @param[in/out] pix A reference to the pointer to the pix buffer
- * @param[in/out] surface A reference to the surface buffer
+ * @param[in/out] outputBufferPtr A reference to the surface buffer
* @param[in] width The width
* @param[in] height The height
* @param[in] fsize The file size
*/
bool HandleBitsPerPixel(
const unsigned int bitcount,
- Dali::Vector<unsigned char>& map,
+ const std::uint8_t* const& inputBufferPtr,
unsigned int*& pix,
- Dali::Vector<unsigned int>& surface,
+ std::uint32_t* const& outputBufferPtr,
const unsigned int width,
const unsigned int height,
const unsigned int fsize,
size_t& position,
- Dali::Vector<unsigned char>& pixbuf,
const unsigned int stride,
const Dali::Vector<unsigned int>& palette)
{
+ // Pixbuf only ever contains one scanline worth of data.
+ Dali::Vector<std::uint8_t> pixbuf;
+ pixbuf.ResizeUninitialized(stride);
+ std::uint8_t* lineBufferPtr = &pixbuf[0];
+
// Note: Switch is in order of most common format first.
switch(bitcount)
{
case 32:
{
- unsigned char* p = &map[position];
- pix = &surface[0] + ((height - 1) * width);
+ const std::uint8_t* p = inputBufferPtr + position;
+ pix = outputBufferPtr + ((height - 1) * width);
for(unsigned int i = 0; i < height; i++)
{
{
for(unsigned int i = 0; i < height; i++)
{
- pix = &surface[0] + ((height - 1 - i) * width);
- if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+ pix = outputBufferPtr + ((height - 1 - i) * width);
+ if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
{
return false;
}
- unsigned char* p = &pixbuf[0];
+ const std::uint8_t* p = lineBufferPtr;
for(unsigned int j = 0; j < width; j++)
{
*pix++ = ARGB_JOIN(0xff, p[0], p[1], p[2]);
{
for(unsigned int i = 0; i < height; i++)
{
- pix = &surface[0] + ((height - 1 - i) * width);
- if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+ pix = outputBufferPtr + ((height - 1 - i) * width);
+ if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
{
return false;
}
- unsigned char* p = &pixbuf[0];
+ const std::uint8_t* p = lineBufferPtr;
for(unsigned int j = 0; j < width; j++)
{
*pix++ = palette[*p++];
{
for(unsigned int i = 0; i < height; i++)
{
- pix = &surface[0] + ((height - 1 - i) * width);
- if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+ pix = outputBufferPtr + ((height - 1 - i) * width);
+ if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
{
return false;
}
- unsigned char* p = &pixbuf[0];
+ const std::uint8_t* p = lineBufferPtr;
for(unsigned int j = 0; j < width; j++)
{
if(j & 0x1)
case 1:
{
+ const std::uint32_t bytesPerWidth = width / 8;
+ const std::uint32_t bytesRemainingPerWidth = width & 7;
for(unsigned int i = 0; i < height; i++)
{
- pix = &surface[0] + ((height - 1 - i) * width);
- if(!read_mem(&map[0], fsize, &position, &pixbuf[0], stride))
+ pix = outputBufferPtr + ((height - 1 - i) * width);
+ if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, stride)))
{
return false;
}
- unsigned char* p = &pixbuf[0];
- for(unsigned int j = 0; j < width; j += 8)
+ const std::uint8_t* p = lineBufferPtr;
+ for(unsigned int j = 0; j < bytesPerWidth; ++j)
{
*pix++ = palette[*p >> 7];
*pix++ = palette[*p >> 6 & 0x01];
*pix++ = palette[*p >> 1 & 0x01];
*pix++ = palette[*p >> 0 & 0x01];
- p++;
+ ++p;
+ }
+ if(bytesRemainingPerWidth > 0)
+ {
+ for(std::uint32_t j = 0; j < bytesRemainingPerWidth; ++j)
+ {
+ *pix++ = palette[(*p >> (7 - j)) & 0x01];
+ }
+ ++p;
}
}
break;
/**
* @brief Apply the mask if required
- * @param[in/out] map The map to use/set
+ * @param[in] inputBufferPtr The map to use
* @param[in] fsize The file size
* @param[in/out] position The position in the file
- * @param[in//out] maskbuf The mask buffer
* @param[in] bitStride The stride
* @param[in] width The width
* @param[in] height The height
* @param[in/out] pix A reference to the pointer to the pix buffer
- * @param[in/out] surface A reference to the surface buffer
+ * @param[in/out] outputBufferPtr A reference to the surface buffer
*/
bool ApplyMask(
- Dali::Vector<unsigned char>& map,
- const unsigned int fsize,
- size_t& position,
- Dali::Vector<unsigned char>& maskbuf,
- const unsigned int bitStride,
- const unsigned int width,
- const unsigned int height,
- unsigned int*& pix,
- Dali::Vector<unsigned int>& surface)
+ const std::uint8_t* const& inputBufferPtr,
+ const unsigned int fsize,
+ size_t& position,
+ const unsigned int bitStride,
+ const unsigned int width,
+ const unsigned int height,
+ unsigned int*& pix,
+ std::uint32_t* const& outputBufferPtr)
{
- if(!read_mem(&map[0], fsize, &position, &maskbuf[0], bitStride * height))
- {
- return false;
- }
+ Dali::Vector<std::uint8_t> maskbuf;
+ maskbuf.ResizeUninitialized(bitStride);
+ std::uint8_t* lineBufferPtr = &maskbuf[0];
// Apply mask.
// Precalc to save time in the loops.
// Loop for each line of the image.
for(unsigned int i = 0; i < height; ++i)
{
- unsigned char* m = &maskbuf[0] + (bitStride * i);
- pix = &surface[0] + ((height - 1 - i) * width);
+ pix = outputBufferPtr + ((height - 1 - i) * width);
+ if(DALI_UNLIKELY(!read_mem(inputBufferPtr, fsize, &position, lineBufferPtr, bitStride)))
+ {
+ return false;
+ }
+ const std::uint8_t* m = lineBufferPtr;
// Do chunks of 8 pixels first so mask operations can be unrolled.
for(unsigned int j = 0; j < bytesPerWidth; ++j)
unsigned int fsize;
FILE* const fp = input.file;
- if(false == LoadIcoHeaderHelper(fp, chosen, map, fsize))
+ if(DALI_UNLIKELY(false == LoadIcoHeaderHelper(fp, chosen, map, fsize)))
{
return false;
}
unsigned int fsize;
FILE* const fp = input.file;
- if(false == LoadIcoHeaderHelper(fp, chosen, map, fsize))
+ if(DALI_UNLIKELY(false == LoadIcoHeaderHelper(fp, chosen, map, fsize)))
{
return false;
}
- Dali::Vector<unsigned int> pal;
- Dali::Vector<unsigned int> surface;
- Dali::Vector<unsigned char> maskbuf;
- Dali::Vector<unsigned char> pixbuf;
- pal.Resize(256 * 4);
-
unsigned int dword;
unsigned short word;
unsigned int h = chosen.h;
unsigned int cols = chosen.cols;
+ const std::uint8_t* const inputBufferPtr = &map[0];
+
// read bmp header time... let's do some checking
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // headersize - dont care
}
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // width
}
diff_size = 1;
}
}
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // height
}
DALI_LOG_WARNING("Broken ICO file!\n");
}
- // Set up the surface as soon as we have the width and height, so we have a black image if there are any further errors.
- surface.ResizeUninitialized(w * h * 4);
- memset(&surface[0], 0, w * h * 4);
-
- if(!read_ushort(&map[0], fsize, &position, &word))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
{
return false; // planes
}
//planes2 = word;
- if(!read_ushort(&map[0], fsize, &position, &word))
+ if(DALI_UNLIKELY(!read_ushort(inputBufferPtr, fsize, &position, &word)))
{
return false; // bitcount
}
unsigned int bitcount = word;
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // compression
}
//compression = dword;
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // imagesize
}
//imagesize = dword;
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // z pixels per m
}
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // y pizels per m
}
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // colors used
}
//colorsused = dword;
- if(!read_uint(&map[0], fsize, &position, &dword))
+ if(DALI_UNLIKELY(!read_uint(inputBufferPtr, fsize, &position, &dword)))
{
return false; // colors important
}
+ Dali::Vector<unsigned int> pal;
+ pal.Resize(256 * 4);
for(unsigned int i = 0; i < cols; i++)
{
unsigned char a, r, g, b;
- if(!read_uchar(&map[0], fsize, &position, &b))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &b)))
{
return false;
}
- if(!read_uchar(&map[0], fsize, &position, &g))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &g)))
{
return false;
}
- if(!read_uchar(&map[0], fsize, &position, &r))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &r)))
{
return false;
}
- if(!read_uchar(&map[0], fsize, &position, &a))
+ if(DALI_UNLIKELY(!read_uchar(inputBufferPtr, fsize, &position, &a)))
{
return false;
}
pal[i] = ARGB_JOIN(0xff, b, g, r);
}
+ Dali::Vector<std::uint32_t> surface;
+
// This is the reference way of calculating the total number of bytes necessary to store one row of pixels.
unsigned int stride = (((bitcount * w) + 31) / 32) * 4;
unsigned int bitStride = ((w + 31) / 32) * 4;
+ // Set up the surface as soon as we have the width and height.
+ surface.ResizeUninitialized(w * h);
- // Pixbuf only ever contains one scanline worth of data.
- pixbuf.ResizeUninitialized(stride);
- maskbuf.ResizeUninitialized(bitStride * h);
+ std::uint32_t* const outputBufferPtr = &surface[0];
// Handle different bits-per-pixel.
- if(!HandleBitsPerPixel(bitcount, map, pix, surface, w, h, fsize, position, pixbuf, stride, pal))
+ if(DALI_UNLIKELY(!HandleBitsPerPixel(bitcount, inputBufferPtr, pix, outputBufferPtr, w, h, fsize, position, stride, pal)))
{
return false;
}
// From the spec: If bpp is less than 32, there will be a 1bpp mask bitmap also.
- if((bitcount < 32) && !ApplyMask(map, fsize, position, maskbuf, bitStride, w, h, pix, surface))
+ if(bitcount < 32)
{
- // Return false if not able to apply mask when the bpp is less than 32
- return false;
+ if(DALI_UNLIKELY(!ApplyMask(inputBufferPtr, fsize, position, bitStride, w, h, pix, outputBufferPtr)))
+ {
+ // Return false if not able to apply mask when the bpp is less than 32
+ return false;
+ }
}
bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::Format::RGBA8888);
auto pixels = bitmap.GetBuffer();
- memcpy(pixels, &surface[0], w * h * 4);
+ memcpy(pixels, outputBufferPtr, w * h * 4);
return true;
}
return true;
}
+bool IsJpegDecodingFailed()
+{
+ std::string errorString = tjGetErrorStr();
+
+ if(DALI_UNLIKELY(IsJpegErrorFatal(errorString)))
+ {
+ DALI_LOG_ERROR("%s\n", errorString.c_str());
+ return true;
+ }
+ else
+ {
+ DALI_LOG_WARNING("%s\n", errorString.c_str());
+ return false;
+ }
+}
+
// helpers for safe exif memory handling
using ExifHandle = std::unique_ptr<ExifData, decltype(exif_data_free)*>;
}
}
+void GetJpegPixelFormat(int jpegColorspace, TJPF& pixelLibJpegType, Pixel::Format& pixelFormat)
+{
+ pixelLibJpegType = TJPF_RGB;
+ pixelFormat = Pixel::RGB888;
+
+ switch(jpegColorspace)
+ {
+ case TJCS_RGB:
+ // YCbCr is not an absolute colorspace but rather a mathematical transformation of RGB designed solely for storage and transmission.
+ // YCbCr images must be converted to RGB before they can actually be displayed.
+ case TJCS_YCbCr:
+ {
+ pixelLibJpegType = TJPF_RGB;
+ pixelFormat = Pixel::RGB888;
+ break;
+ }
+ case TJCS_GRAY:
+ {
+ pixelLibJpegType = TJPF_GRAY;
+ pixelFormat = Pixel::L8;
+ break;
+ }
+ case TJCS_CMYK:
+ case TJCS_YCCK:
+ {
+ pixelLibJpegType = TJPF_CMYK;
+ pixelFormat = Pixel::RGBA8888;
+ break;
+ }
+ default:
+ {
+ pixelLibJpegType = TJPF_RGB;
+ pixelFormat = Pixel::RGB888;
+ break;
+ }
+ }
+}
+
+bool TransformBitmap(int scaledPreXformWidth, int scaledPreXformHeight, JpegTransform transform, uint8_t* bitmapPixelBuffer, Pixel::Format pixelFormat)
+{
+ const unsigned int bufferWidth = Dali::TizenPlatform::GetTextureDimension(scaledPreXformWidth);
+ const unsigned int bufferHeight = Dali::TizenPlatform::GetTextureDimension(scaledPreXformHeight);
+
+ bool result = false;
+
+ switch(transform)
+ {
+ case JpegTransform::NONE:
+ {
+ result = true;
+ break;
+ }
+ // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
+ case JpegTransform::ROTATE_180:
+ {
+ static auto rotate180Functions = TransformFunctionArray{
+ &Rotate180<1>,
+ &Rotate180<3>,
+ &Rotate180<4>,
+ };
+ result = Transform(rotate180Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ case JpegTransform::ROTATE_270:
+ {
+ static auto rotate270Functions = TransformFunctionArray{
+ &Rotate270<1>,
+ &Rotate270<3>,
+ &Rotate270<4>,
+ };
+ result = Transform(rotate270Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ case JpegTransform::ROTATE_90:
+ {
+ static auto rotate90Functions = TransformFunctionArray{
+ &Rotate90<1>,
+ &Rotate90<3>,
+ &Rotate90<4>,
+ };
+ result = Transform(rotate90Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ case JpegTransform::FLIP_VERTICAL:
+ {
+ static auto flipVerticalFunctions = TransformFunctionArray{
+ &FlipVertical<1>,
+ &FlipVertical<3>,
+ &FlipVertical<4>,
+ };
+ result = Transform(flipVerticalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ // Less-common orientation changes, since they don't correspond to a camera's physical orientation:
+ case JpegTransform::FLIP_HORIZONTAL:
+ {
+ static auto flipHorizontalFunctions = TransformFunctionArray{
+ &FlipHorizontal<1>,
+ &FlipHorizontal<3>,
+ &FlipHorizontal<4>,
+ };
+ result = Transform(flipHorizontalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ case JpegTransform::TRANSPOSE:
+ {
+ static auto transposeFunctions = TransformFunctionArray{
+ &Transpose<1>,
+ &Transpose<3>,
+ &Transpose<4>,
+ };
+ result = Transform(transposeFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ case JpegTransform::TRANSVERSE:
+ {
+ static auto transverseFunctions = TransformFunctionArray{
+ &Transverse<1>,
+ &Transverse<3>,
+ &Transverse<4>,
+ };
+ result = Transform(transverseFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
+ break;
+ }
+ default:
+ {
+ DALI_LOG_ERROR("Unsupported JPEG Orientation transformation: %x.\n", transform);
+ break;
+ }
+ }
+ return result;
+}
+
+bool LoadJpegFile(const Dali::ImageLoader::Input& input, Vector<uint8_t>& jpegBuffer, unsigned int& jpegBufferSize)
+{
+ FILE* const fp = input.file;
+
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
+ {
+ DALI_LOG_ERROR("Error seeking to end of file\n");
+ return false;
+ }
+
+ long positionIndicator = ftell(fp);
+ jpegBufferSize = 0u;
+ if(positionIndicator > -1L)
+ {
+ jpegBufferSize = static_cast<unsigned int>(positionIndicator);
+ }
+
+ if(DALI_UNLIKELY(0u == jpegBufferSize))
+ {
+ DALI_LOG_ERROR("Jpeg buffer size error\n");
+ return false;
+ }
+
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
+ {
+ DALI_LOG_ERROR("Error seeking to start of file\n");
+ return false;
+ }
+
+ try
+ {
+ jpegBuffer.ResizeUninitialized(jpegBufferSize);
+ }
+ catch(...)
+ {
+ DALI_LOG_ERROR("Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U);
+ return false;
+ }
+ unsigned char* const jpegBufferPtr = jpegBuffer.Begin();
+
+ // Pull the compressed JPEG image bytes out of a file and into memory:
+ if(DALI_UNLIKELY(fread(jpegBufferPtr, 1, jpegBufferSize, fp) != jpegBufferSize))
+ {
+ DALI_LOG_ERROR("Error on image file read.\n");
+ return false;
+ }
+
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
+ {
+ DALI_LOG_ERROR("Error seeking to start of file\n");
+ return false;
+ }
+
+ return true;
+}
+
} // namespace
namespace Dali
{
namespace TizenPlatform
{
+bool DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers, bool decodeToYuv);
JpegTransform ConvertExifOrientation(ExifData* exifData);
bool TransformSize(int requiredWidth, int requiredHeight, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, JpegTransform transform, int& preXformImageWidth, int& preXformImageHeight, int& postXformImageWidth, int& postXformImageHeight);
// On error exit from the JPEG lib, control will pass via JpegErrorHandler
// into this branch body for cleanup and error return:
- if(setjmp(jerr.jumpBuffer))
+ if(DALI_UNLIKELY(setjmp(jerr.jumpBuffer)))
{
DALI_LOG_ERROR("setjmp failed\n");
jpeg_destroy_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
// Check header to see if it is JPEG file
- if(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK)
+ if(DALI_UNLIKELY(jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK))
{
DALI_LOG_ERROR("jpeg_read_header failed\n");
width = height = 0;
bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
{
- const int flags = 0;
- FILE* const fp = input.file;
+ std::vector<Dali::Devel::PixelBuffer> pixelBuffers;
- if(fseek(fp, 0, SEEK_END))
+ bool result = DecodeJpeg(input, pixelBuffers, false);
+ if(!result && pixelBuffers.empty())
{
- DALI_LOG_ERROR("Error seeking to end of file\n");
- return false;
+ bitmap.Reset();
}
-
- long positionIndicator = ftell(fp);
- unsigned int jpegBufferSize = 0u;
- if(positionIndicator > -1L)
- {
- jpegBufferSize = static_cast<unsigned int>(positionIndicator);
- }
-
- if(0u == jpegBufferSize)
+ else
{
- DALI_LOG_ERROR("Jpeg buffer size error\n");
- return false;
+ bitmap = pixelBuffers[0];
}
+ return result;
+}
- if(fseek(fp, 0, SEEK_SET))
- {
- DALI_LOG_ERROR("Error seeking to start of file\n");
- return false;
- }
+bool LoadPlanesFromJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers)
+{
+ return DecodeJpeg(input, pixelBuffers, true);
+}
- Vector<unsigned char> jpegBuffer;
- try
- {
- jpegBuffer.ResizeUninitialized(jpegBufferSize);
- }
- catch(...)
- {
- DALI_LOG_ERROR("Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U);
- return false;
- }
- unsigned char* const jpegBufferPtr = jpegBuffer.Begin();
+bool DecodeJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers, bool decodeToYuv)
+{
+ Vector<uint8_t> jpegBuffer;
+ unsigned int jpegBufferSize = 0u;
- // Pull the compressed JPEG image bytes out of a file and into memory:
- if(fread(jpegBufferPtr, 1, jpegBufferSize, fp) != jpegBufferSize)
+ if(!LoadJpegFile(input, jpegBuffer, jpegBufferSize))
{
- DALI_LOG_ERROR("Error on image file read.\n");
+ DALI_LOG_ERROR("LoadJpegFile failed\n");
return false;
}
- if(fseek(fp, 0, SEEK_SET))
- {
- DALI_LOG_ERROR("Error seeking to start of file\n");
- }
-
auto jpeg = MakeJpegDecompressor();
-
- if(!jpeg)
+ if(DALI_UNLIKELY(!jpeg))
{
DALI_LOG_ERROR("%s\n", tjGetErrorStr());
return false;
}
- auto transform = JpegTransform::NONE;
+ uint8_t* const jpegBufferPtr = jpegBuffer.Begin();
+ auto transform = JpegTransform::NONE;
// extract exif data
auto exifData = MakeExifDataFromData(jpegBufferPtr, jpegBufferSize);
transform = ConvertExifOrientation(exifData.get());
}
- std::unique_ptr<Property::Map> exifMap;
- exifMap.reset(new Property::Map());
-
- if(DALI_LIKELY(exifData))
- {
- for(auto k = 0u; k < EXIF_IFD_COUNT; ++k)
- {
- auto content = exifData->ifd[k];
- for(auto i = 0u; i < content->count; ++i)
- {
- auto&& tag = content->entries[i];
- const char* shortName = exif_tag_get_name_in_ifd(tag->tag, static_cast<ExifIfd>(k));
- if(shortName)
- {
- AddExifFieldPropertyMap(*exifMap, *tag, static_cast<ExifIfd>(k));
- }
- }
- }
- }
-
// Push jpeg data in memory buffer through TurboJPEG decoder to make a raw pixel array:
int chrominanceSubsampling = -1;
int preXformImageWidth = 0, preXformImageHeight = 0;
-
- // In Ubuntu, the turbojpeg version is not correct. so build error occurs.
- // Temporarily separate Ubuntu and other profiles.
-#ifndef DALI_PROFILE_UBUNTU
int jpegColorspace = -1;
+
if(tjDecompressHeader3(jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling, &jpegColorspace) == -1)
{
DALI_LOG_ERROR("%s\n", tjGetErrorStr());
// Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
}
-#else
- if(tjDecompressHeader2(jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling) == -1)
- {
- DALI_LOG_ERROR("%s\n", tjGetErrorStr());
- // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
- }
-#endif
- if(preXformImageWidth == 0 || preXformImageHeight == 0)
+ if(DALI_UNLIKELY(preXformImageWidth == 0 || preXformImageHeight == 0))
{
DALI_LOG_ERROR("Invalid Image!\n");
return false;
TransformSize(requiredWidth, requiredHeight, input.scalingParameters.scalingMode, input.scalingParameters.samplingMode, transform, scaledPreXformWidth, scaledPreXformHeight, scaledPostXformWidth, scaledPostXformHeight);
- // Colorspace conversion options
- TJPF pixelLibJpegType = TJPF_RGB;
- Pixel::Format pixelFormat = Pixel::RGB888;
-#ifndef DALI_PROFILE_UBUNTU
- switch(jpegColorspace)
+ bool result = false;
+
+ // Now we support YUV420 only
+ if(decodeToYuv && chrominanceSubsampling == TJSAMP_420 && transform == JpegTransform::NONE)
{
- case TJCS_RGB:
- // YCbCr is not an absolute colorspace but rather a mathematical transformation of RGB designed solely for storage and transmission.
- // YCbCr images must be converted to RGB before they can actually be displayed.
- case TJCS_YCbCr:
- {
- pixelLibJpegType = TJPF_RGB;
- pixelFormat = Pixel::RGB888;
- break;
- }
- case TJCS_GRAY:
- {
- pixelLibJpegType = TJPF_GRAY;
- pixelFormat = Pixel::L8;
- break;
- }
- case TJCS_CMYK:
- case TJCS_YCCK:
- {
- pixelLibJpegType = TJPF_CMYK;
- pixelFormat = Pixel::RGBA8888;
- break;
- }
- default:
+ unsigned char* planes[3];
+
+ // Allocate buffers for each plane and decompress the jpeg buffer into the buffers
+ for(int i = 0; i < 3; i++)
{
- pixelLibJpegType = TJPF_RGB;
- pixelFormat = Pixel::RGB888;
- break;
- }
- }
-#endif
- // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
- bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
+ auto planeSize = tjPlaneSizeYUV(i, scaledPostXformWidth, 0, scaledPostXformHeight, chrominanceSubsampling);
- // set metadata
- GetImplementation(bitmap).SetMetadata(std::move(exifMap));
+ unsigned char* buffer = static_cast<unsigned char*>(malloc(planeSize));
+ if(!buffer)
+ {
+ DALI_LOG_ERROR("Buffer allocation is failed [%d]\n", planeSize);
+ pixelBuffers.clear();
+ return false;
+ }
- auto bitmapPixelBuffer = bitmap.GetBuffer();
+ int width, height, planeWidth;
+ Pixel::Format pixelFormat = Pixel::RGB888;
- if(tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags) == -1)
- {
- std::string errorString = tjGetErrorStr();
+ if(i == 0)
+ {
+ // luminance plane
+ width = scaledPostXformWidth;
+ height = scaledPostXformHeight;
+ planeWidth = tjPlaneWidth(i, scaledPostXformWidth, chrominanceSubsampling);
+ pixelFormat = Pixel::L8;
+ }
+ else
+ {
+ // chrominance plane
+ width = tjPlaneWidth(i, scaledPostXformWidth, chrominanceSubsampling);
+ height = tjPlaneHeight(i, scaledPostXformHeight, chrominanceSubsampling);
+ planeWidth = width;
+ pixelFormat = (i == 1 ? Pixel::CHROMINANCE_U : Pixel::CHROMINANCE_V);
+ }
- if(IsJpegErrorFatal(errorString))
- {
- DALI_LOG_ERROR("%s\n", errorString.c_str());
- return false;
+ Internal::Adaptor::PixelBufferPtr internal = Internal::Adaptor::PixelBuffer::New(buffer, planeSize, width, height, planeWidth, pixelFormat);
+ Dali::Devel::PixelBuffer bitmap = Devel::PixelBuffer(internal.Get());
+ planes[i] = buffer;
+ pixelBuffers.push_back(bitmap);
}
- else
+
+ const int flags = 0;
+
+ int decodeResult = tjDecompressToYUVPlanes(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char**>(&planes), scaledPostXformWidth, nullptr, scaledPostXformHeight, flags);
+ if(decodeResult == -1 && IsJpegDecodingFailed())
{
- DALI_LOG_WARNING("%s\n", errorString.c_str());
+ pixelBuffers.clear();
+ return false;
}
+
+ result = true;
}
+ else
+ {
+ // Colorspace conversion options
+ TJPF pixelLibJpegType = TJPF_RGB;
+ Pixel::Format pixelFormat = Pixel::RGB888;
- const unsigned int bufferWidth = GetTextureDimension(scaledPreXformWidth);
- const unsigned int bufferHeight = GetTextureDimension(scaledPreXformHeight);
+ GetJpegPixelFormat(jpegColorspace, pixelLibJpegType, pixelFormat);
- bool result = false;
- switch(transform)
- {
- case JpegTransform::NONE:
- {
- result = true;
- break;
- }
- // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
- case JpegTransform::ROTATE_180:
- {
- static auto rotate180Functions = TransformFunctionArray{
- &Rotate180<1>,
- &Rotate180<3>,
- &Rotate180<4>,
- };
- result = Transform(rotate180Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- case JpegTransform::ROTATE_270:
- {
- static auto rotate270Functions = TransformFunctionArray{
- &Rotate270<1>,
- &Rotate270<3>,
- &Rotate270<4>,
- };
- result = Transform(rotate270Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- case JpegTransform::ROTATE_90:
- {
- static auto rotate90Functions = TransformFunctionArray{
- &Rotate90<1>,
- &Rotate90<3>,
- &Rotate90<4>,
- };
- result = Transform(rotate90Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- case JpegTransform::FLIP_VERTICAL:
- {
- static auto flipVerticalFunctions = TransformFunctionArray{
- &FlipVertical<1>,
- &FlipVertical<3>,
- &FlipVertical<4>,
- };
- result = Transform(flipVerticalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- // Less-common orientation changes, since they don't correspond to a camera's physical orientation:
- case JpegTransform::FLIP_HORIZONTAL:
- {
- static auto flipHorizontalFunctions = TransformFunctionArray{
- &FlipHorizontal<1>,
- &FlipHorizontal<3>,
- &FlipHorizontal<4>,
- };
- result = Transform(flipHorizontalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- case JpegTransform::TRANSPOSE:
- {
- static auto transposeFunctions = TransformFunctionArray{
- &Transpose<1>,
- &Transpose<3>,
- &Transpose<4>,
- };
- result = Transform(transposeFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
- }
- case JpegTransform::TRANSVERSE:
+ // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
+ Dali::Devel::PixelBuffer bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
+
+ // Set metadata
+ if(DALI_LIKELY(exifData))
{
- static auto transverseFunctions = TransformFunctionArray{
- &Transverse<1>,
- &Transverse<3>,
- &Transverse<4>,
- };
- result = Transform(transverseFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat);
- break;
+ std::unique_ptr<Property::Map> exifMap = std::make_unique<Property::Map>();
+
+ for(auto k = 0u; k < EXIF_IFD_COUNT; ++k)
+ {
+ auto content = exifData->ifd[k];
+ for(auto i = 0u; i < content->count; ++i)
+ {
+ auto&& tag = content->entries[i];
+ const char* shortName = exif_tag_get_name_in_ifd(tag->tag, static_cast<ExifIfd>(k));
+ if(shortName)
+ {
+ AddExifFieldPropertyMap(*exifMap, *tag, static_cast<ExifIfd>(k));
+ }
+ }
+ }
+
+ GetImplementation(bitmap).SetMetadata(std::move(exifMap));
}
- default:
+
+ auto bitmapPixelBuffer = bitmap.GetBuffer();
+ const int flags = 0;
+
+ int decodeResult = tjDecompress2(jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>(bitmapPixelBuffer), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags);
+ if(decodeResult == -1 && IsJpegDecodingFailed())
{
- DALI_LOG_ERROR("Unsupported JPEG Orientation transformation: %x.\n", transform);
- break;
+ return false;
}
+ pixelBuffers.push_back(bitmap);
+
+ // Transform bitmap
+ result = TransformBitmap(scaledPreXformWidth, scaledPreXformHeight, transform, bitmapPixelBuffer, pixelFormat);
}
return result;
// Initialise a JPEG codec:
{
auto jpeg = MakeJpegCompressor();
- if(!jpeg)
+ if(DALI_UNLIKELY(!jpeg))
{
DALI_LOG_ERROR("JPEG Compressor init failed: %s\n", tjGetErrorStr());
return false;
unsigned long dstBufferSize = 0;
const int flags = 0;
- if(tjCompress2(jpeg.get(),
- const_cast<unsigned char*>(pixelBuffer),
- width,
- 0,
- height,
- jpegPixelFormat,
- SetPointer(dstBuffer),
- &dstBufferSize,
- TJSAMP_444,
- quality,
- flags))
+ if(DALI_UNLIKELY(tjCompress2(jpeg.get(),
+ const_cast<unsigned char*>(pixelBuffer),
+ width,
+ 0,
+ height,
+ jpegPixelFormat,
+ SetPointer(dstBuffer),
+ &dstBufferSize,
+ TJSAMP_444,
+ quality,
+ flags)))
{
DALI_LOG_ERROR("JPEG Compression failed: %s\n", tjGetErrorStr());
return false;
int numFactors = 0;
tjscalingfactor* factors = tjGetScalingFactors(&numFactors);
- if(factors == NULL)
+ if(DALI_UNLIKELY(factors == NULL))
{
DALI_LOG_WARNING("TurboJpeg tjGetScalingFactors error!\n");
success = false;
auto exifData = MakeNullExifData();
unsigned char dataBuffer[1024];
- if(fseek(fp, 0, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking to start of file\n");
}
unsigned int headerHeight;
success = LoadJpegHeader(fp, headerWidth, headerHeight);
- if(success)
+ if(DALI_LIKELY(success))
{
auto transform = JpegTransform::NONE;
#define DALI_TIZEN_PLATFORM_LOADER_JPEG_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
bool LoadBitmapFromJpeg(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap);
/**
+ * Loads the image planes from an JPEG file. This function checks the header first
+ * and if it is not a JPEG file, then it returns straight away.
+ * @param[in] input Information about the input image (including file pointer)
+ * @param[out] pixelBuffers The buffer list where the each plane will be stored
+ * @return true if file decoded successfully, false otherwise
+ * @note If the image file doesn't support to load planes, this method returns one RGB bitmap image.
+ */
+bool LoadPlanesFromJpeg(const Dali::ImageLoader::Input& input, std::vector<Dali::Devel::PixelBuffer>& pixelBuffers);
+
+/**
* Loads the header of a JPEG file and fills in the width and height appropriately.
* If the width and height are set on entry, it will set the width and height
* to the closest scaled size (exactly as will be loaded by LoadBitmapFromJpeg with the same
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
const unsigned int readLength = sizeof(KtxFileHeader);
// Load the information directly into our structure
- if(fread(&header, 1, readLength, filePointer) != readLength)
+ if(DALI_UNLIKELY(fread(&header, 1, readLength, filePointer) != readLength))
{
return false;
}
bool LoadKtxHeader(FILE* const fp, unsigned int& width, unsigned int& height, KtxFileHeader& fileHeader)
{
// Pull the bytes of the file header in as a block:
- if(!ReadHeader(fp, fileHeader))
+ if(DALI_UNLIKELY(!ReadHeader(fp, fileHeader)))
{
return false;
}
width = fileHeader.pixelWidth;
height = fileHeader.pixelHeight;
- if(width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION)
+ if(DALI_UNLIKELY(width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION))
{
return false;
}
static_assert(sizeof(uint32_t) == 4);
FILE* const fp = input.file;
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
DALI_LOG_ERROR("Null file handle passed to KTX compressed bitmap file loader.\n");
return false;
// Load the header info
unsigned int width, height;
- if(!LoadKtxHeader(fp, width, height, fileHeader))
+ if(DALI_UNLIKELY(!LoadKtxHeader(fp, width, height, fileHeader)))
{
return false;
}
// Skip the key-values:
const long int imageSizeOffset = sizeof(KtxFileHeader) + fileHeader.bytesOfKeyValueData;
- if(fseek(fp, imageSizeOffset, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, imageSizeOffset, SEEK_SET)))
{
DALI_LOG_ERROR("Seek past key/vals in KTX compressed bitmap file failed.\n");
return false;
// Load the size of the image data:
uint32_t imageByteCount = 0;
- if(fread(&imageByteCount, 1, 4, fp) != 4)
+ if(DALI_UNLIKELY(fread(&imageByteCount, 1, 4, fp) != 4))
{
DALI_LOG_ERROR("Read of image size failed.\n");
return false;
}
// Sanity-check the image size:
- if(imageByteCount > MAX_IMAGE_DATA_SIZE ||
- // A compressed texture should certainly be less than 2 bytes per texel:
- imageByteCount > width * height * 2)
+ if(DALI_UNLIKELY(imageByteCount > MAX_IMAGE_DATA_SIZE ||
+ // A compressed texture should certainly be less than 2 bytes per texel:
+ imageByteCount > width * height * 2))
{
DALI_LOG_ERROR("KTX file with too-large image-data field.\n");
return false;
Pixel::Format pixelFormat;
const bool pixelFormatKnown = ConvertPixelFormat(fileHeader.glInternalFormat, pixelFormat);
- if(!pixelFormatKnown)
+ if(DALI_UNLIKELY(!pixelFormatKnown))
{
DALI_LOG_ERROR("No internal pixel format supported for KTX file pixel format.\n");
return false;
pixels = bitmap.GetBuffer();
}
- if(!pixels)
+ if(DALI_UNLIKELY(!pixels))
{
DALI_LOG_ERROR("Unable to reserve a pixel buffer to load the requested bitmap into.\n");
return false;
}
const size_t bytesRead = fread(pixels, 1, imageByteCount, fp);
- if(bytesRead != imageByteCount)
+ if(DALI_UNLIKELY(bytesRead != imageByteCount))
{
DALI_LOG_ERROR("Read of image pixel data failed.\n");
return false;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// Check header to see if it is a PNG file
size_t size = fread(header, 1, 8, fp);
- if(size != 8)
+ if(DALI_UNLIKELY(size != 8))
{
DALI_LOG_ERROR("fread failed\n");
return false;
}
- if(png_sig_cmp(header, 0, 8))
+ if(DALI_UNLIKELY(png_sig_cmp(header, 0, 8)))
{
DALI_LOG_ERROR("png_sig_cmp failed\n");
return false;
png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if(!png)
+ if(DALI_UNLIKELY(!png))
{
DALI_LOG_ERROR("Can't create PNG read structure\n");
return false;
}
info = png_create_info_struct(png);
- if(!info)
+ if(DALI_UNLIKELY(!info))
{
DALI_LOG_ERROR("png_create_info_struct failed\n");
return false;
png_set_expand(png);
- if(setjmp(png_jmpbuf(png)))
+ if(DALI_UNLIKELY(setjmp(png_jmpbuf(png))))
{
DALI_LOG_ERROR("error during png_init_io\n");
return false;
bool valid = false;
// Load info from the header
- if(!LoadPngHeader(input.file, width, height, png, info))
+ if(DALI_UNLIKELY(!LoadPngHeader(input.file, width, height, png, info)))
{
return false;
}
}
}
- if(!valid)
+ if(DALI_UNLIKELY(!valid))
{
DALI_LOG_ERROR("Unsupported png format\n");
return false;
png_read_update_info(png, info);
- if(setjmp(png_jmpbuf(png)))
+ if(DALI_UNLIKELY(setjmp(png_jmpbuf(png))))
{
DALI_LOG_ERROR("error during png_read_image\n");
return false;
break;
}
}
-
- // decode the whole image into bitmap buffer
- auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat)).GetBuffer();
-
- DALI_ASSERT_DEBUG(pixels);
rows = reinterpret_cast<png_bytep*>(malloc(sizeof(png_bytep) * height));
- if(!rows)
+ if(DALI_UNLIKELY(!rows))
{
DALI_LOG_ERROR("malloc is failed\n");
return false;
}
+ // decode the whole image into bitmap buffer
+ auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat)).GetBuffer();
+
+ DALI_ASSERT_DEBUG(pixels);
+
for(y = 0; y < height; y++)
{
rows[y] = pixels + y * stride;
((1ULL << (29)) - 2048))
//extract multiple bytes integer , and saved in *data
-int extractMultiByteInteger(unsigned int* data, void* map, size_t length, size_t* position)
+int extractMultiByteInteger(unsigned int* data, const std::uint8_t* const& map, size_t length, size_t* position)
{
// the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
//, a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
// for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
// first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
// second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
- if((readBufCount++) == 4)
+ if(DALI_UNLIKELY((readBufCount++) == 4))
{
return -1;
}
- if(*position > length)
+ if(DALI_UNLIKELY(*position > length))
{
return -1;
}
- buf = reinterpret_cast<unsigned char*>(map)[(*position)++];
+ buf = map[(*position)++];
targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
if((buf & 0x80) == 0)
bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
{
FILE* const fp = input.file;
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
DALI_LOG_ERROR("Error loading bitmap\n");
return false;
std::uint32_t type;
std::uint32_t lineByteLength;
- if(fseek(fp, 0, SEEK_END))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
{
DALI_LOG_ERROR("Error seeking WBMP data\n");
return false;
fsize = static_cast<unsigned int>(positionIndicator);
}
- if(0u == fsize)
+ if(DALI_UNLIKELY(0u == fsize))
{
DALI_LOG_ERROR("Error: filesize is 0!\n");
return false;
}
- if(fseek(fp, 0, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking WBMP data\n");
return false;
}
- if(fsize <= 4)
+ if(DALI_UNLIKELY(fsize <= 4))
{
DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
return false;
}
- if(fsize > 4096 * 4096 * 4)
+ if(DALI_UNLIKELY(fsize > 4096 * 4096 * 4))
{
DALI_LOG_ERROR("Error: WBMP size is too large!\n");
return false;
}
map.ResizeUninitialized(fsize);
- if(fread(&map[0], 1, fsize, fp) != fsize)
+ if(DALI_UNLIKELY(fread(&map[0], 1, fsize, fp) != fsize))
{
DALI_LOG_WARNING("image file read opeation error!\n");
return false;
}
- if(extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
+ const std::uint8_t* const inputBufferPtr = &map[0];
+
+ if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, fsize, &position) < 0))
{
return false;
}
position++; /* skipping one byte */
- if(extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
+ if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, fsize, &position) < 0))
{
return false;
}
- if(extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
+ if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, fsize, &position) < 0))
{
return false;
}
- if(type != 0)
+ if(DALI_UNLIKELY(type != 0))
{
DALI_LOG_ERROR("Unknown Format!\n");
return false;
}
- if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+ if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
{
return false;
}
// w >= 1 and h >= 1. So we can assume that outputPixels is not null.
auto outputPixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
+
/**
* @code
* std::uint8_t* line = NULL;
* @endcode
*/
- const std::uint8_t* inputPixels = &map[0] + position;
+ const std::uint8_t* inputPixels = inputBufferPtr + position;
const std::uint32_t lineByteLengthWithoutPadding = w >> 3;
const std::uint8_t linePadding = w & 0x07;
- for(std::uint32_t y = 0; y < h; y++)
+ for(std::uint32_t y = 0; y < h; ++y)
{
- for(std::uint32_t x = 0; x < lineByteLengthWithoutPadding; x++)
+ for(std::uint32_t x = 0; x < lineByteLengthWithoutPadding; ++x)
{
// memset whole 8 bits
// outputPixels filled 4 bytes in one operation.
bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
{
FILE* const fp = input.file;
- if(fp == NULL)
+ if(DALI_UNLIKELY(fp == NULL))
{
DALI_LOG_ERROR("Error loading bitmap\n");
return false;
unsigned int w, h;
unsigned int type;
- if(fseek(fp, 0, SEEK_END))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END)))
{
DALI_LOG_ERROR("Error seeking WBMP data\n");
return false;
fsize = static_cast<unsigned int>(positionIndicator);
}
- if(0u == fsize)
+ if(DALI_UNLIKELY(0u == fsize))
{
return false;
}
- if(fseek(fp, 0, SEEK_SET))
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_SET)))
{
DALI_LOG_ERROR("Error seeking WBMP data\n");
return false;
}
- if(fsize <= 4)
+ if(DALI_UNLIKELY(fsize <= 4))
{
DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
return false;
headerSize = std::min(headerSize, fsize);
map.ResizeUninitialized(headerSize);
- if(fread(&map[0], 1, headerSize, fp) != headerSize)
+ if(DALI_UNLIKELY(fread(&map[0], 1, headerSize, fp) != headerSize))
{
DALI_LOG_WARNING("image file read opeation error!\n");
return false;
}
- if(extractMultiByteInteger(&type, &map[0], headerSize, &position) < 0)
+ const std::uint8_t* const inputBufferPtr = &map[0];
+
+ if(DALI_UNLIKELY(extractMultiByteInteger(&type, inputBufferPtr, headerSize, &position) < 0))
{
DALI_LOG_ERROR("Error: unable to read type!\n");
return false;
}
position++; /* skipping one byte */
- if(type != 0)
+ if(DALI_UNLIKELY(type != 0))
{
DALI_LOG_ERROR("Error: unknown format!\n");
return false;
}
- if(extractMultiByteInteger(&w, &map[0], headerSize, &position) < 0)
+ if(DALI_UNLIKELY(extractMultiByteInteger(&w, inputBufferPtr, headerSize, &position) < 0))
{
DALI_LOG_ERROR("Error: can not read width!\n");
return false;
}
- if(extractMultiByteInteger(&h, &map[0], headerSize, &position) < 0)
+ if(DALI_UNLIKELY(extractMultiByteInteger(&h, inputBufferPtr, headerSize, &position) < 0))
{
DALI_LOG_ERROR("Error: can not read height!\n");
return false;
}
- if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+ if(DALI_UNLIKELY((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE)))
{
DALI_LOG_ERROR("Error: file size is not supported!\n");
return false;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
*
*/
+// HEADER
#include <dali/internal/imaging/common/loader-webp.h>
-// EXTERNAL INCLUDES
-#ifdef DALI_WEBP_AVAILABLE
-#include <webp/decode.h>
-#include <webp/demux.h>
-
-#if WEBP_DEMUX_ABI_VERSION > 0x0101
-#define DALI_ANIMATED_WEBP_ENABLED 1
-#endif
-#endif
+// INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
-#include <dali/integration-api/debug.h>
-#include <cstring>
-#include <memory>
-
-typedef unsigned char WebPByteType;
+#include <dali/internal/imaging/common/webp-loading.h>
namespace Dali
{
namespace TizenPlatform
{
-#ifdef DALI_ANIMATED_WEBP_ENABLED
-bool ReadWebPInformation(FILE* const fp, WebPData& webPData)
-{
- if(fp == NULL)
- {
- return false;
- }
-
- if(fseek(fp, 0, SEEK_END) <= -1)
- {
- return false;
- }
- WebPDataInit(&webPData);
- webPData.size = ftell(fp);
-
- if((!fseek(fp, 0, SEEK_SET)))
- {
- unsigned char* WebPDataBuffer;
- WebPDataBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * webPData.size));
- webPData.size = fread(WebPDataBuffer, sizeof(WebPByteType), webPData.size, fp);
- webPData.bytes = WebPDataBuffer;
- }
- else
- {
- return false;
- }
- return true;
-}
-
-void ReleaseResource(WebPData& webPData, WebPAnimDecoder* webPAnimDecoder)
+namespace
{
- free((void*)webPData.bytes);
- webPData.bytes = nullptr;
- WebPDataInit(&webPData);
- if(webPAnimDecoder)
- {
- WebPAnimDecoderDelete(webPAnimDecoder);
- }
+constexpr uint32_t FIRST_FRAME_INDEX = 0u;
}
-#endif
-
bool LoadWebpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
{
- FILE* const fp = input.file;
- if(fp == NULL)
- {
- return false;
- }
-
- if(fseek(fp, 0, SEEK_END) <= -1)
- {
- return false;
- }
-
- // If the image is non-animated webp
-#ifdef DALI_WEBP_AVAILABLE
- size_t webPSize = ftell(fp);
- if((!fseek(fp, 0, SEEK_SET)))
- {
- std::vector<uint8_t> encodedImage;
- encodedImage.resize(webPSize, 0);
- size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
- if(readCount != encodedImage.size())
- {
- return false;
- }
- int32_t imageWidth, imageHeight;
- if(WebPGetInfo(&encodedImage[0], encodedImage.size(), &imageWidth, &imageHeight))
- {
- width = static_cast<uint32_t>(imageWidth);
- height = static_cast<uint32_t>(imageHeight);
- return true;
- }
- }
-#endif
-
- // If the image is animated webp
-#ifdef DALI_ANIMATED_WEBP_ENABLED
- WebPData webPData;
- WebPAnimDecoder* webPAnimDecoder = nullptr;
- WebPAnimInfo webPAnimInfo;
- if(ReadWebPInformation(fp, webPData))
+ FILE* const fp = input.file;
+ Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+ if(webPLoading)
{
- WebPAnimDecoderOptions webPAnimDecoderOptions;
- WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
- webPAnimDecoderOptions.color_mode = MODE_RGBA;
- webPAnimDecoder = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
- if(webPAnimDecoder != nullptr)
+ ImageDimensions imageSize = webPLoading.GetImageSize();
+ if(webPLoading.HasLoadingSucceeded())
{
- WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
- width = webPAnimInfo.canvas_width;
- height = webPAnimInfo.canvas_height;
- ReleaseResource(webPData, webPAnimDecoder);
+ width = imageSize.GetWidth();
+ height = imageSize.GetHeight();
return true;
}
}
- ReleaseResource(webPData, webPAnimDecoder);
-#endif
- DALI_LOG_ERROR("WebP file open failed.\n");
return false;
}
bool LoadBitmapFromWebp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
{
- FILE* const fp = input.file;
- if(fp == NULL)
- {
- return false;
- }
-
- if(fseek(fp, 0, SEEK_END) <= -1)
- {
- return false;
- }
-
- // If the image is non-animated webp
-#ifdef DALI_WEBP_AVAILABLE
- size_t webPSize = ftell(fp);
- if((!fseek(fp, 0, SEEK_SET)))
- {
- std::vector<uint8_t> encodedImage;
- encodedImage.resize(webPSize, 0);
- size_t readCount = fread(&encodedImage[0], sizeof(uint8_t), encodedImage.size(), fp);
- if(readCount != encodedImage.size())
- {
- DALI_LOG_ERROR("WebP image loading failed.\n");
- return false;
- }
-
- int32_t width, height;
- if(!WebPGetInfo(&encodedImage[0], encodedImage.size(), &width, &height))
- {
- DALI_LOG_ERROR("Cannot retrieve WebP image size information.\n");
- return false;
- }
-
- WebPBitstreamFeatures features;
- if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(&encodedImage[0], encodedImage.size(), &features))
- {
- DALI_LOG_ERROR("Cannot retrieve WebP image features.\n");
- return false;
- }
-
- uint32_t channelNumber = (features.has_alpha) ? 4 : 3;
- Pixel::Format pixelFormat = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
- bitmap = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
- uint8_t* frameBuffer = nullptr;
- if(channelNumber == 4)
- {
- frameBuffer = WebPDecodeRGBA(&encodedImage[0], encodedImage.size(), &width, &height);
- }
- else
- {
- frameBuffer = WebPDecodeRGB(&encodedImage[0], encodedImage.size(), &width, &height);
- }
-
- if(frameBuffer != nullptr)
- {
- const int32_t bufferSize = width * height * sizeof(uint8_t) * channelNumber;
- memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
- free((void*)frameBuffer);
- return true;
- }
- }
-#endif
-
- // If the image is animated webp
-#ifdef DALI_ANIMATED_WEBP_ENABLED
- WebPData webPData;
- WebPAnimDecoder* webPAnimDecoder = nullptr;
- WebPAnimInfo webPAnimInfo;
- if(ReadWebPInformation(fp, webPData))
+ FILE* const fp = input.file;
+ Dali::AnimatedImageLoading webPLoading = Dali::AnimatedImageLoading(Dali::Internal::Adaptor::WebPLoading::New(fp).Get());
+ if(webPLoading)
{
- WebPAnimDecoderOptions webPAnimDecoderOptions;
- WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
- webPAnimDecoderOptions.color_mode = MODE_RGBA;
- webPAnimDecoder = WebPAnimDecoderNew(&webPData, &webPAnimDecoderOptions);
- if(webPAnimDecoder != nullptr)
+ Dali::Devel::PixelBuffer pixelBuffer = webPLoading.LoadFrame(FIRST_FRAME_INDEX);
+ if(pixelBuffer && webPLoading.HasLoadingSucceeded())
{
- uint8_t* frameBuffer;
- int timestamp;
- WebPAnimDecoderGetInfo(webPAnimDecoder, &webPAnimInfo);
- WebPAnimDecoderReset(webPAnimDecoder);
- WebPAnimDecoderGetNext(webPAnimDecoder, &frameBuffer, ×tamp);
-
- bitmap = Dali::Devel::PixelBuffer::New(webPAnimInfo.canvas_width, webPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
- const int32_t bufferSize = webPAnimInfo.canvas_width * webPAnimInfo.canvas_height * sizeof(uint32_t);
- memcpy(bitmap.GetBuffer(), frameBuffer, bufferSize);
- ReleaseResource(webPData, webPAnimDecoder);
+ bitmap = pixelBuffer;
return true;
}
}
- ReleaseResource(webPData, webPAnimDecoder);
-#endif
-
- DALI_LOG_ERROR("WebP image loading failed.\n");
return false;
}
unsigned int bufferSize,
unsigned int width,
unsigned int height,
+ unsigned int stride,
Dali::Pixel::Format pixelFormat)
: mMetadata(),
mBuffer(buffer),
mBufferSize(bufferSize),
mWidth(width),
mHeight(height),
+ mStride(stride ? stride : width),
mPixelFormat(pixelFormat),
mPreMultiplied(false)
{
{
buffer = static_cast<unsigned char*>(malloc(bufferSize));
}
- return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
+ return new PixelBuffer(buffer, bufferSize, width, height, width, pixelFormat);
}
PixelBufferPtr PixelBuffer::New(unsigned char* buffer,
unsigned int bufferSize,
unsigned int width,
unsigned int height,
+ unsigned int stride,
Dali::Pixel::Format pixelFormat)
{
- return new PixelBuffer(buffer, bufferSize, width, height, pixelFormat);
+ return new PixelBuffer(buffer, bufferSize, width, height, stride, pixelFormat);
}
Dali::PixelData PixelBuffer::Convert(PixelBuffer& pixelBuffer)
pixelBuffer.mBufferSize,
pixelBuffer.mWidth,
pixelBuffer.mHeight,
+ pixelBuffer.mStride,
pixelBuffer.mPixelFormat,
Dali::PixelData::FREE);
pixelBuffer.mBuffer = NULL;
pixelBuffer.mWidth = 0;
pixelBuffer.mHeight = 0;
pixelBuffer.mBufferSize = 0;
+ pixelBuffer.mStride = 0;
return pixelData;
}
return mHeight;
}
+uint32_t PixelBuffer::GetStride() const
+{
+ return mStride;
+}
+
Dali::Pixel::Format PixelBuffer::GetPixelFormat() const
{
return mPixelFormat;
memcpy(destBuffer, mBuffer, mBufferSize);
}
- Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mPixelFormat, Dali::PixelData::FREE);
+ Dali::PixelData pixelData = Dali::PixelData::New(destBuffer, mBufferSize, mWidth, mHeight, mStride, mPixelFormat, Dali::PixelData::FREE);
return pixelData;
}
mBufferSize = pixelBuffer.mBufferSize;
mWidth = pixelBuffer.mWidth;
mHeight = pixelBuffer.mHeight;
+ mStride = pixelBuffer.mStride;
mPixelFormat = pixelBuffer.mPixelFormat;
}
Platform::RotateByShear(mBuffer,
mWidth,
mHeight,
+ mStride,
pixelSize,
radians,
pixelsOut,
mBuffer = pixelsOut;
pixelsOut = nullptr;
mBufferSize = mWidth * mHeight * pixelSize;
+ mStride = mWidth; // The buffer is tightly packed.
}
return success;
{
PixelBufferPtr outBuffer = PixelBuffer::New(cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat());
int bytesPerPixel = Pixel::GetBytesPerPixel(inBuffer.mPixelFormat);
- int srcStride = inBuffer.mWidth * bytesPerPixel;
- int destStride = cropDimensions.GetWidth() * bytesPerPixel;
+ int srcStride = inBuffer.mStride * bytesPerPixel;
+ int destStride = cropDimensions.GetWidth() * bytesPerPixel; // The destination buffer is tightly packed
// Clamp crop to right edge
if(x + cropDimensions.GetWidth() > inBuffer.mWidth)
inBuffer.mPixelFormat == Pixel::RGBA8888 ||
inBuffer.mPixelFormat == Pixel::BGRA8888)
{
- Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
+ Dali::Internal::Platform::Resample(inBuffer.mBuffer, inDimensions, inBuffer.mStride, outBuffer->GetBuffer(), outDimensions, filterType, bytesPerPixel, hasAlpha);
}
else
{
// must be skipped in such case
if(Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat))
{
- unsigned char* pixel = mBuffer;
- const unsigned int bufferSize = mWidth * mHeight;
+ unsigned char* pixel = mBuffer;
+ const unsigned int strideBytes = mStride * bytesPerPixel;
+ const unsigned int widthBytes = mWidth * bytesPerPixel;
// Collect all valid channel list before lookup whole buffer
std::vector<Channel> validChannelList;
if(DALI_LIKELY(!validChannelList.empty()))
{
- for(unsigned int i = 0; i < bufferSize; ++i)
+ for(unsigned int y = 0; y < mHeight; y++)
{
- unsigned int alpha = ReadChannel(pixel, mPixelFormat, Adaptor::ALPHA);
- if(alpha < 255)
+ for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel)
{
- // If alpha is 255, we don't need to change color. Skip current pixel
- // But if alpha is not 255, we should change color.
- if(alpha > 0)
+ unsigned int alpha = ReadChannel(&pixel[x], mPixelFormat, Adaptor::ALPHA);
+ if(alpha < 255)
{
- for(const Channel& channel : validChannelList)
+ // If alpha is 255, we don't need to change color. Skip current pixel
+ // But if alpha is not 255, we should change color.
+ if(alpha > 0)
{
- auto color = ReadChannel(pixel, mPixelFormat, channel);
- WriteChannel(pixel, mPixelFormat, channel, color * alpha / 255);
+ for(const Channel& channel : validChannelList)
+ {
+ auto color = ReadChannel(&pixel[x], mPixelFormat, channel);
+ WriteChannel(&pixel[x], mPixelFormat, channel, color * alpha / 255);
+ }
+ }
+ else
+ {
+ // If alpha is 0, just set all pixel as zero.
+ memset(&pixel[x], 0, bytesPerPixel);
}
- }
- else
- {
- // If alpha is 0, just set all pixel as zero.
- memset(pixel, 0, bytesPerPixel);
}
}
- pixel += bytesPerPixel;
+ pixel += strideBytes;
}
}
+ mPreMultiplied = true;
}
- mPreMultiplied = true;
}
bool PixelBuffer::IsAlphaPreMultiplied() const
uint32_t PixelBuffer::GetBrightness() const
{
- uint32_t brightness = 0;
-
+ uint32_t brightness = 0;
uint32_t bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
- if(bytesPerPixel)
+
+ if(bytesPerPixel && mWidth && mHeight)
{
- unsigned char* pixel = mBuffer;
- const uint32_t bufferSize = mWidth * mHeight;
+ unsigned char* pixel = mBuffer;
+ const uint32_t strideBytes = mStride * bytesPerPixel;
+ const uint32_t widthBytes = mWidth * bytesPerPixel;
+ const uint32_t bufferSize = mWidth * mHeight;
- if(bufferSize) // avoid division by zero to calculate brightness
- {
- uint64_t red = 0;
- uint64_t green = 0;
- uint64_t blue = 0;
+ uint64_t red = 0;
+ uint64_t green = 0;
+ uint64_t blue = 0;
- for(uint32_t i = 0; i < bufferSize; ++i)
+ for(unsigned int y = 0; y < mHeight; y++)
+ {
+ for(unsigned int x = 0; x < widthBytes; x += bytesPerPixel)
{
- red += ReadChannel(pixel, mPixelFormat, Adaptor::RED);
- green += ReadChannel(pixel, mPixelFormat, Adaptor::GREEN);
- blue += ReadChannel(pixel, mPixelFormat, Adaptor::BLUE);
- pixel += bytesPerPixel;
+ red += ReadChannel(&pixel[x], mPixelFormat, Adaptor::RED);
+ green += ReadChannel(&pixel[x], mPixelFormat, Adaptor::GREEN);
+ blue += ReadChannel(&pixel[x], mPixelFormat, Adaptor::BLUE);
}
- // http://www.w3.org/TR/AERT#color-contrast
- brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize);
+ pixel += strideBytes;
}
+
+ // http://www.w3.org/TR/AERT#color-contrast
+ brightness = (red * BRIGHTNESS_CONSTANT_R + green * BRIGHTNESS_CONSTANT_G + blue * BRIGHTNESS_CONSTANT_B) / (1000uLL * bufferSize);
}
return brightness;
#define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
* @param [in] bufferSize The size of the buffer in bytes
* @param [in] width Buffer width in pixels
* @param [in] height Buffer height in pixels
+ * @param [in] stride Buffer stride in pixels, 0 means the buffer is tightly packed
* @param [in] pixelFormat The pixel format
- * @param [in] releaseFunction The function used to release the memory.
*/
static PixelBufferPtr New(unsigned char* buffer,
unsigned int bufferSize,
unsigned int width,
unsigned int height,
+ unsigned int stride,
Pixel::Format pixelFormat);
/**
* @param [in] bufferSize The size of the buffer in bytes
* @param [in] width Buffer width in pixels
* @param [in] height Buffer height in pixels
+ * @param [in] stride Buffer stride in pixels, 0 means the buffer is tightly packed
* @param [in] pixelFormat The pixel format
*/
PixelBuffer(unsigned char* buffer,
unsigned int bufferSize,
unsigned int width,
unsigned int height,
+ unsigned int stride,
Pixel::Format pixelFormat);
protected:
unsigned int GetHeight() const;
/**
+ * @brief Gets the stride of the buffer in pixels.
+ * @return The stride of the buffer in pixels. 0 means the buffer is tightly packed.
+ */
+ unsigned int GetStride() const;
+
+ /**
* Get the pixel format
* @return The pixel format
*/
private:
std::unique_ptr<Property::Map> mMetadata; ///< Metadata fields
- unsigned char* mBuffer; ///< The raw pixel data
- unsigned int mBufferSize; ///< Buffer sized in bytes
- unsigned int mWidth; ///< Buffer width in pixels
- unsigned int mHeight; ///< Buffer height in pixels
+ uint8_t* mBuffer; ///< The raw pixel data
+ uint32_t mBufferSize; ///< Buffer sized in bytes
+ uint32_t mWidth; ///< Buffer width in pixels
+ uint32_t mHeight; ///< Buffer height in pixels
+ uint32_t mStride; ///< Buffer stride in bytes, 0 means the buffer is tightly packed
Pixel::Format mPixelFormat; ///< Pixel format
bool mPreMultiplied; ///< PreMultiplied
};
DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple channels.\n");
break;
}
+
+ case Dali::Pixel::CHROMINANCE_U:
+ case Dali::Pixel::CHROMINANCE_V:
+ {
+ DALI_LOG_ERROR("Pixel formats for chrominance are not compatible with simple channels.\n");
+ break;
+ }
}
return false;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
// INTERNAL INCLUDES
#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
-typedef unsigned char WebPByteType;
+typedef uint8_t WebPByteType;
namespace Dali
{
Debug::Filter* gWebPLoadingLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_GIF_LOADING");
#endif
-constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
+static constexpr int32_t INITIAL_INDEX = -1;
+static constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE = 50 * 1024 * 1024;
} // namespace
{
public:
Impl(const std::string& url, bool isLocalResource)
- : mUrl(url),
+ : mFile(nullptr),
+ mUrl(url),
mFrameCount(1u),
mMutex(),
mBuffer(nullptr),
mBufferSize(0u),
mImageSize(),
- mLoadSucceeded(true)
+ mLoadSucceeded(false),
+ mIsAnimatedImage(false),
+ mIsLocalResource(isLocalResource)
{
+ }
+
+ Impl(FILE* const fp)
+ : mFile(fp),
+ mUrl(),
+ mFrameCount(1u),
+ mMutex(),
+ mBuffer(nullptr),
+ mBufferSize(0u),
+ mImageSize(),
+ mLoadSucceeded(false),
+ mIsAnimatedImage(false),
+ mIsLocalResource(true)
+ {
+ }
+
+ bool LoadWebPInformation()
+ {
+ // Block to do not load this file again.
+ Mutex::ScopedLock lock(mMutex);
+ if(DALI_UNLIKELY(mLoadSucceeded))
+ {
+ return mLoadSucceeded;
+ }
+
+#ifndef DALI_WEBP_AVAILABLE
+ // If the system doesn't support webp, loading will be failed.
+ mFrameCount = 0u;
+ mLoadSucceeded = false;
+ return mLoadSucceeded;
+#endif
+
// mFrameCount will be 1 if the input image is non-animated image or animated image with single frame.
- if(ReadWebPInformation(isLocalResource))
+ if(DALI_LIKELY(ReadWebPInformation()))
{
#ifdef DALI_ANIMATED_WEBP_ENABLED
- WebPDataInit(&mWebPData);
- mWebPData.size = mBufferSize;
- mWebPData.bytes = mBuffer;
- WebPAnimDecoderOptions webPAnimDecoderOptions;
- WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
- webPAnimDecoderOptions.color_mode = MODE_RGBA;
- mWebPAnimDecoder = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
- WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
- mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
- mFrameCount = mWebPAnimInfo.frame_count;
- mImageSize = ImageDimensions(mWebPAnimInfo.canvas_width, mWebPAnimInfo.canvas_height);
-#elif DALI_WEBP_AVAILABLE
- int32_t imageWidth, imageHeight;
- if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+ if(mIsAnimatedImage)
{
- mImageSize = ImageDimensions(imageWidth, imageHeight);
+ WebPDataInit(&mWebPData);
+ mWebPData.size = mBufferSize;
+ mWebPData.bytes = mBuffer;
+ WebPAnimDecoderOptions webPAnimDecoderOptions;
+ WebPAnimDecoderOptionsInit(&webPAnimDecoderOptions);
+ webPAnimDecoderOptions.color_mode = MODE_RGBA;
+ mWebPAnimDecoder = WebPAnimDecoderNew(&mWebPData, &webPAnimDecoderOptions);
+ WebPAnimDecoderGetInfo(mWebPAnimDecoder, &mWebPAnimInfo);
+ mTimeStamp.assign(mWebPAnimInfo.frame_count, 0);
+ mFrameCount = mWebPAnimInfo.frame_count;
+ mImageSize = ImageDimensions(mWebPAnimInfo.canvas_width, mWebPAnimInfo.canvas_height);
}
#endif
-#ifndef DALI_WEBP_AVAILABLE
- // If the system doesn't support webp, loading will be failed.
- mFrameCount = 0u;
- mLoadSucceeded = false;
+#ifdef DALI_WEBP_AVAILABLE
+ if(!mIsAnimatedImage)
+ {
+ int32_t imageWidth, imageHeight;
+ if(WebPGetInfo(mBuffer, mBufferSize, &imageWidth, &imageHeight))
+ {
+ mImageSize = ImageDimensions(imageWidth, imageHeight);
+ }
+ }
#endif
+ mLoadSucceeded = true;
}
else
{
mLoadSucceeded = false;
DALI_LOG_ERROR("Image loading failed for: \"%s\".\n", mUrl.c_str());
}
+
+ return mLoadSucceeded;
}
- bool ReadWebPInformation(bool isLocalResource)
+ bool ReadWebPInformation()
{
- FILE* fp = nullptr;
- if(isLocalResource)
+ mBufferSize = 0;
+
+ FILE* fp = mFile;
+ std::unique_ptr<Internal::Platform::FileReader> fileReader;
+ Dali::Vector<uint8_t> dataBuffer;
+ if(fp == nullptr)
{
- Internal::Platform::FileReader fileReader(mUrl);
- fp = fileReader.GetFile();
- if(fp == nullptr)
+ if(mIsLocalResource)
{
- return false;
+ fileReader = std::make_unique<Internal::Platform::FileReader>(mUrl);
}
-
- if(fseek(fp, 0, SEEK_END) <= -1)
+ else
{
- return false;
+ size_t dataSize;
+ if(DALI_LIKELY(TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE)))
+ {
+ mBufferSize = dataBuffer.Size();
+ if(DALI_LIKELY(mBufferSize > 0U))
+ {
+ // Open a file handle on the memory buffer:
+ fileReader = std::make_unique<Internal::Platform::FileReader>(dataBuffer, mBufferSize);
+ }
+ }
}
- mBufferSize = ftell(fp);
- if(!fseek(fp, 0, SEEK_SET))
- {
- mBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
- mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
- return true;
- }
+ fp = fileReader->GetFile();
}
- else
- {
- // remote file
- bool succeeded;
- Dali::Vector<uint8_t> dataBuffer;
- size_t dataSize;
- succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory(mUrl, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE);
- if(succeeded)
+ if(DALI_LIKELY(fp != nullptr))
+ {
+ if(DALI_LIKELY(!fseek(fp, 12, SEEK_SET)))
{
- mBufferSize = dataBuffer.Size();
- if(mBufferSize > 0U)
+ uint8_t mHeaderBuffer[5];
+ fread(mHeaderBuffer, sizeof(WebPByteType), 5, fp);
+ unsigned char VP8X[4] = {'V', 'P', '8', 'X'};
+ bool isExtended = true;
+ for(uint32_t i = 0; i < 4; ++i)
{
- // Open a file handle on the memory buffer:
- Internal::Platform::FileReader fileReader(dataBuffer, mBufferSize);
- fp = fileReader.GetFile();
- if(fp != nullptr)
+ if(mHeaderBuffer[i] != VP8X[i])
{
- if(!fseek(fp, 0, SEEK_SET))
- {
- mBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
- mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
- return true;
- }
+ isExtended = false;
+ break;
}
}
+ if(isExtended)
+ {
+ unsigned char extension = mHeaderBuffer[4];
+ mIsAnimatedImage = ((extension >> 1) & 1) ? true : false;
+ }
+ }
+
+ if(mBufferSize == 0)
+ {
+ if(DALI_UNLIKELY(fseek(fp, 0, SEEK_END) <= -1))
+ {
+ return false;
+ }
+ mBufferSize = ftell(fp);
+ }
+
+ if(DALI_LIKELY(!fseek(fp, 0, SEEK_SET)))
+ {
+ mBuffer = reinterpret_cast<WebPByteType*>(malloc(sizeof(WebPByteType) * mBufferSize));
+ mBufferSize = fread(mBuffer, sizeof(WebPByteType), mBufferSize, fp);
+ return true;
}
}
return false;
void ReleaseResource()
{
#ifdef DALI_ANIMATED_WEBP_ENABLED
- if(&mWebPData != nullptr)
+ if(mIsAnimatedImage)
{
- mWebPData.bytes = nullptr;
- WebPDataInit(&mWebPData);
- }
- if(mWebPAnimDecoder != nullptr)
- {
- WebPAnimDecoderDelete(mWebPAnimDecoder);
- mWebPAnimDecoder = nullptr;
+ if(&mWebPData != nullptr)
+ {
+ mWebPData.bytes = nullptr;
+ WebPDataInit(&mWebPData);
+ }
+ if(mWebPAnimDecoder != nullptr)
+ {
+ WebPAnimDecoderDelete(mWebPAnimDecoder);
+ mWebPAnimDecoder = nullptr;
+ }
}
#endif
if(mBuffer != nullptr)
ReleaseResource();
}
+ FILE* mFile;
std::string mUrl;
std::vector<uint32_t> mTimeStamp;
- uint32_t mLoadingFrame{0};
+ int32_t mLatestLoadedFrame{INITIAL_INDEX};
uint32_t mFrameCount;
Mutex mMutex;
// For the case the system doesn't support DALI_ANIMATED_WEBP_ENABLED
uint32_t mBufferSize;
ImageDimensions mImageSize;
bool mLoadSucceeded;
+ bool mIsAnimatedImage;
+ bool mIsLocalResource;
#ifdef DALI_ANIMATED_WEBP_ENABLED
- WebPData mWebPData{0};
- WebPAnimDecoder* mWebPAnimDecoder{nullptr};
- WebPAnimInfo mWebPAnimInfo{0};
+ WebPData mWebPData{0};
+ WebPAnimDecoder* mWebPAnimDecoder{nullptr};
+ WebPAnimInfo mWebPAnimInfo{0};
+ Dali::Devel::PixelBuffer mPreLoadedFrame{};
#endif
};
return AnimatedImageLoadingPtr(new WebPLoading(url, isLocalResource));
}
+AnimatedImageLoadingPtr WebPLoading::New(FILE* const fp)
+{
+#ifndef DALI_ANIMATED_WEBP_ENABLED
+ DALI_LOG_ERROR("The system does not support Animated WebP format.\n");
+#endif
+ return AnimatedImageLoadingPtr(new WebPLoading(fp));
+}
+
WebPLoading::WebPLoading(const std::string& url, bool isLocalResource)
: mImpl(new WebPLoading::Impl(url, isLocalResource))
{
}
-WebPLoading::~WebPLoading()
+WebPLoading::WebPLoading(FILE* const fp)
+: mImpl(new WebPLoading::Impl(fp))
{
- delete mImpl;
}
-bool WebPLoading::LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData)
+WebPLoading::~WebPLoading()
{
- for(int i = 0; i < count; ++i)
- {
- Dali::Devel::PixelBuffer pixelBuffer = LoadFrame((frameStartIndex + i) % mImpl->mFrameCount);
- Dali::PixelData imageData = Devel::PixelBuffer::Convert(pixelBuffer);
- pixelData.push_back(imageData);
- }
- if(pixelData.size() != static_cast<uint32_t>(count))
- {
- return false;
- }
- return true;
+ delete mImpl;
}
Dali::Devel::PixelBuffer WebPLoading::LoadFrame(uint32_t frameIndex)
{
Dali::Devel::PixelBuffer pixelBuffer;
+ // If WebP file is still not loaded, Load the information.
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ if(DALI_UNLIKELY(!mImpl->LoadWebPInformation()))
+ {
+ mImpl->ReleaseResource();
+ return pixelBuffer;
+ }
+ }
+
// WebPDecodeRGBA is faster than to use demux API for loading non-animated image.
// If frame count is 1, use WebPDecodeRGBA api.
#ifdef DALI_WEBP_AVAILABLE
- if(mImpl->mFrameCount == 1)
+ if(!mImpl->mIsAnimatedImage)
{
int32_t width, height;
- if(!WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height))
+ if(DALI_LIKELY(WebPGetInfo(mImpl->mBuffer, mImpl->mBufferSize, &width, &height)))
{
- return pixelBuffer;
- }
+ WebPBitstreamFeatures features;
+ if(DALI_LIKELY(VP8_STATUS_NOT_ENOUGH_DATA != WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features)))
+ {
+ uint32_t channelNumber = (features.has_alpha) ? 4 : 3;
+ uint8_t* frameBuffer = nullptr;
+ if(channelNumber == 4)
+ {
+ frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+ }
+ else
+ {
+ frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+ }
- WebPBitstreamFeatures features;
- if(VP8_STATUS_NOT_ENOUGH_DATA == WebPGetFeatures(mImpl->mBuffer, mImpl->mBufferSize, &features))
- {
- return pixelBuffer;
+ if(frameBuffer != nullptr)
+ {
+ Pixel::Format pixelFormat = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
+ int32_t bufferSize = width * height * Dali::Pixel::GetBytesPerPixel(pixelFormat);
+ Internal::Adaptor::PixelBufferPtr internal =
+ Internal::Adaptor::PixelBuffer::New(frameBuffer, bufferSize, width, height, width, pixelFormat);
+ pixelBuffer = Devel::PixelBuffer(internal.Get());
+ }
+ }
}
+ // The single frame resource should be released after loading.
+ mImpl->ReleaseResource();
+ }
+#endif
- uint32_t channelNumber = (features.has_alpha) ? 4 : 3;
- Pixel::Format pixelFormat = (channelNumber == 4) ? Pixel::RGBA8888 : Pixel::RGB888;
- pixelBuffer = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
- uint8_t* frameBuffer = nullptr;
- if(channelNumber == 4)
+#ifdef DALI_ANIMATED_WEBP_ENABLED
+ if(mImpl->mIsAnimatedImage && mImpl->mBuffer != nullptr)
+ {
+ Mutex::ScopedLock lock(mImpl->mMutex);
+ if(DALI_LIKELY(frameIndex < mImpl->mWebPAnimInfo.frame_count && mImpl->mLoadSucceeded))
{
- frameBuffer = WebPDecodeRGBA(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+ DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
+
+ if(mImpl->mPreLoadedFrame && mImpl->mLatestLoadedFrame == static_cast<int32_t>(frameIndex))
+ {
+ pixelBuffer = mImpl->mPreLoadedFrame;
+ }
+ else
+ {
+ pixelBuffer = DecodeFrame(frameIndex);
+ }
+ mImpl->mPreLoadedFrame.Reset();
+
+ // If time stamp of next frame is unknown, load a frame more to know it.
+ if(frameIndex + 1 < mImpl->mWebPAnimInfo.frame_count && mImpl->mTimeStamp[frameIndex + 1] == 0u)
+ {
+ mImpl->mPreLoadedFrame = DecodeFrame(frameIndex + 1);
+ }
}
else
{
- frameBuffer = WebPDecodeRGB(mImpl->mBuffer, mImpl->mBufferSize, &width, &height);
+ mImpl->ReleaseResource();
}
-
- if(frameBuffer != nullptr)
- {
- const int32_t imageBufferSize = width * height * sizeof(uint8_t) * channelNumber;
- memcpy(pixelBuffer.GetBuffer(), frameBuffer, imageBufferSize);
- free((void*)frameBuffer);
- }
- mImpl->ReleaseResource();
- return pixelBuffer;
}
#endif
+ return pixelBuffer;
+}
+Dali::Devel::PixelBuffer WebPLoading::DecodeFrame(uint32_t frameIndex)
+{
+ Dali::Devel::PixelBuffer pixelBuffer;
#ifdef DALI_ANIMATED_WEBP_ENABLED
- Mutex::ScopedLock lock(mImpl->mMutex);
- if(frameIndex >= mImpl->mWebPAnimInfo.frame_count || !mImpl->mLoadSucceeded)
- {
- return pixelBuffer;
- }
-
- DALI_LOG_INFO(gWebPLoadingLogFilter, Debug::Concise, "LoadFrame( frameIndex:%d )\n", frameIndex);
-
- if(mImpl->mLoadingFrame > frameIndex)
+ if(mImpl->mLatestLoadedFrame > static_cast<int32_t>(frameIndex))
{
- mImpl->mLoadingFrame = 0;
+ mImpl->mLatestLoadedFrame = INITIAL_INDEX;
WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
}
- for(; mImpl->mLoadingFrame < frameIndex; ++mImpl->mLoadingFrame)
+ uint8_t* frameBuffer = nullptr;
+ int32_t timestamp = 0u;
+ for(; mImpl->mLatestLoadedFrame < static_cast<int32_t>(frameIndex);)
{
- uint8_t* frameBuffer;
- int timestamp;
WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
- mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
+ mImpl->mTimeStamp[++mImpl->mLatestLoadedFrame] = timestamp;
}
- const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
- uint8_t* frameBuffer;
- int timestamp;
- WebPAnimDecoderGetNext(mImpl->mWebPAnimDecoder, &frameBuffer, ×tamp);
-
- pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
- memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
- mImpl->mTimeStamp[mImpl->mLoadingFrame] = timestamp;
-
- mImpl->mLoadingFrame++;
- if(mImpl->mLoadingFrame >= mImpl->mWebPAnimInfo.frame_count)
+ if(frameBuffer != nullptr)
{
- mImpl->mLoadingFrame = 0;
- WebPAnimDecoderReset(mImpl->mWebPAnimDecoder);
+ const int bufferSize = mImpl->mWebPAnimInfo.canvas_width * mImpl->mWebPAnimInfo.canvas_height * sizeof(uint32_t);
+ pixelBuffer = Dali::Devel::PixelBuffer::New(mImpl->mWebPAnimInfo.canvas_width, mImpl->mWebPAnimInfo.canvas_height, Dali::Pixel::RGBA8888);
+ memcpy(pixelBuffer.GetBuffer(), frameBuffer, bufferSize);
}
+
#endif
return pixelBuffer;
}
ImageDimensions WebPLoading::GetImageSize() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadWebPInformation();
+ }
return mImpl->mImageSize;
}
uint32_t WebPLoading::GetImageCount() const
{
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ mImpl->LoadWebPInformation();
+ }
return mImpl->mFrameCount;
}
uint32_t WebPLoading::GetFrameInterval(uint32_t frameIndex) const
{
- // If frameIndex is above the value of ImageCount or current frame is not loading yet, return 0u.
- if(frameIndex >= GetImageCount() || (frameIndex > 0 && mImpl->mTimeStamp[frameIndex - 1] > mImpl->mTimeStamp[frameIndex]))
+ if(DALI_UNLIKELY(!mImpl->mLoadSucceeded))
+ {
+ DALI_LOG_ERROR("WebP file is still not loaded, this frame interval could not be correct value.\n");
+ }
+ if(frameIndex >= GetImageCount())
{
+ DALI_LOG_ERROR("Input frameIndex exceeded frame count of the WebP.");
return 0u;
}
else
{
- if(frameIndex > 0)
+ int32_t interval = 0u;
+ if(GetImageCount() == 1u)
+ {
+ return 0u;
+ }
+ else if(frameIndex + 1 == GetImageCount())
+ {
+ // For the interval between last frame and first frame, use last interval again.
+ interval = mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+ }
+ else
+ {
+ interval = mImpl->mTimeStamp[frameIndex + 1] - mImpl->mTimeStamp[frameIndex];
+ }
+
+ if(DALI_UNLIKELY(interval < 0))
{
- return mImpl->mTimeStamp[frameIndex] - mImpl->mTimeStamp[frameIndex - 1];
+ DALI_LOG_ERROR("This interval value is not correct, because the frame still hasn't ever been decoded.");
+ return 0u;
}
- return mImpl->mTimeStamp[frameIndex];
+ return static_cast<uint32_t>(interval);
}
}
static AnimatedImageLoadingPtr New(const std::string& url, bool isLocalResource);
/**
+ * Create a WebPLoading with the given url and resourceType.
+ * @param[in] fp The file pointer to be load.
+ * @return A newly created WebPLoading.
+ */
+ static AnimatedImageLoadingPtr New(FILE* const fp);
+
+ /**
* @brief Constructor
*
* Construct a Loader with the given URL
WebPLoading(const std::string& url, bool isLocalResource);
/**
- * @brief Destructor
+ * @brief Constructor
+ *
+ * Construct a Loader with the given URL
+ * @param[in] fp The file pointer to be load.
*/
- ~WebPLoading() override;
+ WebPLoading(FILE* const fp);
/**
- * @brief Load the next N Frames of the webp.
- *
- * @note This function will load the entire webp into memory if not already loaded.
- * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
- * after the previous invocation of this method, or 0 to start.
- * @param[in] count The number of frames to load
- * @param[out] pixelData The vector in which to return the frame data
- * @return True if the frame data was successfully loaded
+ * @brief Destructor
*/
- bool LoadNextNFrames(uint32_t frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData) override;
+ ~WebPLoading() override;
/**
* @brief Load the next Frame of the animated image.
* @param[in] frameIndex The frame counter to load. Will usually be the next frame.
* @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
*/
-
Dali::Devel::PixelBuffer LoadFrame(uint32_t frameIndex) override;
/**
*
* @note The frame is needed to be loaded before this function is called.
*
- * @return The time interval of the frame(microsecond).
+ * @return The time interval between frameIndex and frameIndex + 1(microsecond).
*/
uint32_t GetFrameInterval(uint32_t frameIndex) const override;
bool HasLoadingSucceeded() const override;
private:
+ /**
+ * @brief Decode Frame of the animated image.
+ *
+ * @param[in] frameIndex The frame counter to load. Will usually be the next frame.
+ * @return Dali::Devel::PixelBuffer The loaded PixelBuffer. If loading is fail, return empty handle.
+ */
+ Dali::Devel::PixelBuffer DecodeFrame(uint32_t frameIndex);
+
+private:
struct Impl;
Impl* mImpl;
};
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
Dali::Internal::Platform::RotateByShear(data.buffer,
data.width,
data.height,
+ data.width,
pixelSize,
radians,
pixelsOut,
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
FcDefaultSubstitute(matchPattern);
FcCharSet* characterSet = nullptr;
- MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+ bool matched = MatchFontDescriptionToPattern(matchPattern, mDefaultFontDescription, &characterSet);
+
+ // Caching the default font description
+ if(matched)
+ {
+ // Copy default font description info.
+ // Due to the type changed, we need to make some temperal font description.
+ FontDescription tempFontDescription = mDefaultFontDescription;
+
+ // Add the path to the cache.
+ tempFontDescription.type = FontDescription::FACE_FONT;
+ mFontDescriptionCache.push_back(tempFontDescription);
+
+ // Set the index to the vector of paths to font file names.
+ const FontDescriptionId validatedFontId = mFontDescriptionCache.size();
+
+ FONT_LOG_DESCRIPTION(tempFontDescription, "default platform font");
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font validatedFontId : %d\n", validatedFontId);
+
+ // Cache the index and the matched font's description.
+ FontDescriptionCacheItem item(tempFontDescription,
+ validatedFontId);
+
+ mValidatedFontCache.push_back(std::move(item));
+ }
+ else
+ {
+ DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " default font validation failed for font [%s]\n", mDefaultFontDescription.family.c_str());
+ }
+
// Decrease the reference counter of the character set as it's not stored.
+ // Note. the cached default font description will increase reference counter by
+ // mFontDescriptionCache. So we can decrease reference counter here.
FcCharSetDestroy(characterSet);
// Destroys the pattern created.
{
DALI_LOG_TRACE_METHOD(gFontClientLogFilter);
FONT_LOG_DESCRIPTION(fontDescription, "");
+
+ // Special case when font Description don't have family information.
+ // In this case, we just use default description family and path.
+ const FontDescription& realFontDescription = fontDescription.family.empty() ? FontDescription(mDefaultFontDescription.path,
+ mDefaultFontDescription.family,
+ fontDescription.width,
+ fontDescription.weight,
+ fontDescription.slant,
+ fontDescription.type)
+ : fontDescription;
+
+ FONT_LOG_DESCRIPTION(realFontDescription, "");
DALI_LOG_INFO(gFontClientLogFilter, Debug::General, " requestedPointSize : %d\n", requestedPointSize);
// This method uses three vectors which caches:
FontId fontId = 0u;
// Check first if the font description matches with a previously loaded bitmap font.
- if(FindBitmapFont(fontDescription.family, fontId))
+ if(FindBitmapFont(realFontDescription.family, fontId))
{
return fontId;
}
// Check if the font's description have been validated before.
FontDescriptionId validatedFontId = 0u;
- if(!FindValidatedFont(fontDescription,
+ if(!FindValidatedFont(realFontDescription,
validatedFontId))
{
// Use font config to validate the font's description.
- ValidateFont(fontDescription,
+ ValidateFont(realFontDescription,
validatedFontId);
}
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
{
Dali::Internal::Platform::LanczosSample4BPP(srcBuffer,
inputDimensions,
+ srcWidth,
data.buffer,
desiredDimensions);
}
Dali::Internal::Platform::HorizontalShear(pixelsIn,
width,
height,
+ width,
1u,
-TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
pixelsOut,
mPlugin->ActivateAccessibility(activated);
}
+Accessibility::Address WebEngine::GetAccessibilityAddress()
+{
+ return mPlugin->GetAccessibilityAddress();
+}
+
bool WebEngine::SetVisibility(bool visible)
{
return mPlugin->SetVisibility(visible);
#include <dali/public-api/object/base-object.h>
// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility.h>
#include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
#include <dali/devel-api/adaptor-framework/web-engine.h>
void ActivateAccessibility(bool activated);
/**
+ * @copydoc Dali::WebEngine::GetAccessibilityAddress()
+ */
+ Accessibility::Address GetAccessibilityAddress();
+
+ /**
* @copydoc Dali::WebEngine::SetVisibility()
*/
bool SetVisibility(bool visible);
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return 0;
}
+std::string WindowBaseAndroid::GetNativeWindowResourceId()
+{
+ return std::string();
+}
+
EGLNativeWindowType WindowBaseAndroid::CreateEglWindow(int width, int height)
{
// from eglplatform.h header
#define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_BASE_ANDROID_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std::string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_BASE_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
virtual int GetNativeWindowId() = 0;
/**
+ * @brief Get the native window resource id assinged by window manager
+ * @return The native window resource id
+ */
+ virtual std::string GetNativeWindowResourceId() = 0;
+
+ /**
* @brief Create the egl window
*/
virtual EGLNativeWindowType CreateEglWindow(int width, int height) = 0;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
mIconified(false),
mOpaqueState(false),
mWindowRotationAcknowledgement(false),
+ mFocused(false),
mParentWindow(NULL),
mPreferredAngle(static_cast<int>(WindowOrientation::NO_ORIENTATION_PREFERENCE)),
mRotationAngle(0),
Window::~Window()
{
- auto bridge = Accessibility::Bridge::GetCurrentBridge();
- auto rootLayer = mScene.GetRootLayer();
- auto accessible = Accessibility::Accessible::Get(rootLayer, true);
- bridge->RemoveTopLevelWindow(accessible);
+ if(mScene)
+ {
+ auto bridge = Accessibility::Bridge::GetCurrentBridge();
+ auto rootLayer = mScene.GetRootLayer();
+ auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+ bridge->RemoveTopLevelWindow(accessible);
+ }
if(mAdaptor)
{
mEventHandler->AddObserver(*this);
// Add Window to bridge for ATSPI
- auto bridge = Accessibility::Bridge::GetCurrentBridge();
- auto rootLayer = mScene.GetRootLayer();
- auto accessible = Accessibility::Accessible::Get(rootLayer, true);
- bridge->AddTopLevelWindow(accessible);
+ auto bridge = Accessibility::Bridge::GetCurrentBridge();
+ if (bridge->IsUp())
+ {
+ auto rootLayer = mScene.GetRootLayer();
+ auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+ bridge->AddTopLevelWindow(accessible);
+ }
bridge->EnabledSignal().Connect(this, &Window::OnAccessibilityEnabled);
bridge->DisabledSignal().Connect(this, &Window::OnAccessibilityDisabled);
return mScene.GetRenderTaskList();
}
+std::string Window::GetNativeResourceId() const
+{
+ return mWindowBase->GetNativeWindowResourceId();
+}
+
void Window::AddAvailableOrientation(WindowOrientation orientation)
{
if(IsOrientationAvailable(orientation) == false)
mWindowBase->SetPositionSizeWithAngle(positionSize, angle);
}
+void Window::EmitAccessibilityHighlightSignal(bool highlight)
+{
+ Dali::Window handle(this);
+ mAccessibilityHighlightSignal.Emit(handle, highlight);
+}
+
void Window::SetAvailableAnlges(const std::vector<int>& angles)
{
if(angles.size() > 4)
{
Dali::Window handle(this);
mVisibilityChangedSignal.Emit(handle, true);
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(handle);
WindowVisibilityObserver* observer(mAdaptor);
observer->OnWindowShown();
{
Dali::Window handle(this);
mVisibilityChangedSignal.Emit(handle, false);
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(handle);
WindowVisibilityObserver* observer(mAdaptor);
observer->OnWindowHidden();
{
Dali::Window handle(this);
mVisibilityChangedSignal.Emit(handle, false);
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowHidden(handle);
WindowVisibilityObserver* observer(mAdaptor);
observer->OnWindowHidden();
{
Dali::Window handle(this);
mVisibilityChangedSignal.Emit(handle, true);
+ Dali::Accessibility::Bridge::GetCurrentBridge()->WindowShown(handle);
WindowVisibilityObserver* observer(mAdaptor);
observer->OnWindowShown();
bridge->WindowUnfocused(handle);
}
}
+ mFocused = focusIn;
}
void Window::OnOutputTransformed()
auto rootLayer = mScene.GetRootLayer();
auto accessible = Accessibility::Accessible::Get(rootLayer, true);
bridge->AddTopLevelWindow(accessible);
+
+ if(mFocused)
+ {
+ Dali::Window handle(this);
+ bridge->WindowFocused(handle);
+ }
}
void Window::OnAccessibilityDisabled()
#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_IMPL_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
typedef Dali::DevelWindow::TransitionEffectEventSignalType TransitionEffectEventSignalType;
typedef Dali::DevelWindow::KeyboardRepeatSettingsChangedSignalType KeyboardRepeatSettingsChangedSignalType;
typedef Dali::DevelWindow::AuxiliaryMessageSignalType AuxiliaryMessageSignalType;
+ typedef Dali::DevelWindow::AccessibilityHighlightSignalType AccessibilityHighlightSignalType;
typedef Signal<void()> SignalType;
/**
Dali::RenderTaskList GetRenderTaskList() const;
/**
+ * @brief Get window resource ID assigned by window manager
+ * @return The resource ID of the window
+ */
+ std::string GetNativeResourceId() const;
+
+ /**
* @copydoc Dali::Window::AddAvailableOrientation()
*/
void AddAvailableOrientation(WindowOrientation orientation);
*/
void SetPositionSizeWithOrientation(PositionSize positionSize, WindowOrientation orientation);
+ /**
+ * @brief Emit the accessibility highlight signal.
+ * The highlight indicates that it is an object to interact with the user regardless of focus.
+ * After setting the highlight on the object, you can do things that the object can do, such as
+ * giving or losing focus.
+ *
+ * @param[in] highlight If window needs to grab or clear highlight.
+ */
+ void EmitAccessibilityHighlightSignal(bool highlight);
+
public: // Dali::Internal::Adaptor::SceneHolder
/**
* @copydoc Dali::Internal::Adaptor::SceneHolder::GetNativeHandle
return mAuxiliaryMessageSignal;
}
+ /**
+ * @copydoc Dali::DevelWindow::AccessibilityHighlightSignal()
+ */
+ AccessibilityHighlightSignalType& AccessibilityHighlightSignal()
+ {
+ return mAccessibilityHighlightSignal;
+ }
+
private:
WindowRenderSurface* mWindowSurface; ///< The window rendering surface
WindowBase* mWindowBase;
bool mIconified : 1;
bool mOpaqueState : 1;
bool mWindowRotationAcknowledgement : 1;
+ bool mFocused : 1;
Dali::Window mParentWindow;
OrientationPtr mOrientation;
TransitionEffectEventSignalType mTransitionEffectEventSignal;
KeyboardRepeatSettingsChangedSignalType mKeyboardRepeatSettingsChangedSignal;
AuxiliaryMessageSignalType mAuxiliaryMessageSignal;
+ AccessibilityHighlightSignalType mAccessibilityHighlightSignal;
};
} // namespace Adaptor
#pragma once
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std::string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return mImpl->mWindow.windowNumber;
}
+std::string WindowBaseCocoa::GetNativeWindowResourceId()
+{
+ return std::string();
+}
+
EGLNativeWindowType WindowBaseCocoa::CreateEglWindow(int width, int height)
{
// XXX: this method is called from a secondary thread, but
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return ecore_wl_window_id_get(mEcoreWindow);
}
+std::string WindowBaseEcoreWl::GetNativeWindowResourceId()
+{
+ return std::string();
+}
+
EGLNativeWindowType WindowBaseEcoreWl::CreateEglWindow(int width, int height)
{
mEglWindow = wl_egl_window_create(mWlSurface, width, height);
#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std::string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
static Eina_Bool EcoreEventSeatKeyboardRepeatChanged(void* data, int type, void* event)
{
- Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed* keyboardRepeat = static_cast<Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed*>(event);
- WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
- DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventSeatKeyboardRepeatChanged, id[ %d ]\n", keyboardRepeat->id);
+ WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
+ DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventSeatKeyboardRepeatChanged, id[ %d ]\n", static_cast<Ecore_Wl2_Event_Seat_Keyboard_Repeat_Changed*>(event)->id);
if(windowBase)
{
windowBase->OnKeyboardRepeatSettingsChanged();
static Eina_Bool EcoreEventWindowRedrawRequest(void* data, int type, void* event)
{
- Ecore_Wl2_Event_Window_Redraw_Request* windowRedrawRequest = static_cast<Ecore_Wl2_Event_Window_Redraw_Request*>(event);
- WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
- DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventWindowRedrawRequest, window[ %d ]\n", windowRedrawRequest->win);
+ WindowBaseEcoreWl2* windowBase = static_cast<WindowBaseEcoreWl2*>(data);
+ DALI_LOG_INFO(gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventWindowRedrawRequest, window[ %d ]\n", static_cast<Ecore_Wl2_Event_Window_Redraw_Request*>(event)->win);
if(windowBase)
{
windowBase->OnEcoreEventWindowRedrawRequest();
return ecore_wl2_window_id_get(mEcoreWindow);
}
+std::string WindowBaseEcoreWl2::GetNativeWindowResourceId()
+{
+#ifdef OVER_TIZEN_VERSION_7
+ return std::to_string(ecore_wl2_window_resource_id_get(mEcoreWindow));
+#else
+ return std::string();
+#endif
+}
+
EGLNativeWindowType WindowBaseEcoreWl2::CreateEglWindow(int width, int height)
{
int totalAngle = (mWindowRotationAngle + mScreenRotationAngle) % 360;
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std::string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return mEcoreWindow;
}
+std::string WindowBaseEcoreX::GetNativeWindowResourceId()
+{
+ return std::string();
+}
+
EGLNativeWindowType WindowBaseEcoreX::CreateEglWindow(int width, int height)
{
// need to create X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_BASE_ECORE_X_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std::string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
return mWin32Window;
}
+std::string WindowBaseWin::GetNativeWindowResourceId()
+{
+ return std::string();
+}
+
EGLNativeWindowType WindowBaseWin::CreateEglWindow(int width, int height)
{
return reinterpret_cast<EGLNativeWindowType>(mWin32Window);
#define DALI_INTERNAL_WINDOWSYSTEM_WINDOW_BASE_WIN_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
int GetNativeWindowId() override;
/**
+ * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowResourceId()
+ */
+ std:string GetNativeWindowResourceId() override;
+
+ /**
* @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
*/
EGLNativeWindowType CreateEglWindow(int width, int height) override;
{
const unsigned int ADAPTOR_MAJOR_VERSION = 2;
const unsigned int ADAPTOR_MINOR_VERSION = 1;
-const unsigned int ADAPTOR_MICRO_VERSION = 15;
+const unsigned int ADAPTOR_MICRO_VERSION = 18;
const char* const ADAPTOR_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali2-adaptor
Summary: The DALi Tizen Adaptor
-Version: 2.1.15
+Version: 2.1.18
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT