From: joogab yun Date: Wed, 20 Feb 2019 00:39:56 +0000 (+0000) Subject: Merge "Text improvement 1. Text - Layout text & icons. * Feature added to layout... X-Git-Tag: dali_1.4.8~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=f60b3d8e308a5145efe754cbff2a47b4ae278021;hp=e50e9862014f01ea06a82f78addf1ede66e974b6 Merge "Text improvement 1. Text - Layout text & icons. * Feature added to layout text and icons. Icons can be added using the mark-up string feature." into devel/master --- diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 746299b..093f4fb 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -16,6 +16,7 @@ SET(TC_SOURCES utc-Dali-PropertyHelper.cpp utc-Dali-SizeNegotiationMapper.cpp utc-Dali-Text-CharacterSetConversion.cpp + utc-Dali-Text-Circular.cpp utc-Dali-Text-Controller.cpp utc-Dali-Text-Cursor.cpp utc-Dali-Text-Layout.cpp diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp index 84df087..e3ccad8 100755 --- a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp @@ -108,7 +108,8 @@ void CreateTextModel( const std::string& text, visualModel = VisualModel::New(); MarkupProcessData markupProcessData( logicalModel->mColorRuns, - logicalModel->mFontDescriptionRuns ); + logicalModel->mFontDescriptionRuns, + logicalModel->mEmbeddedItems ); Length textSize = 0u; const uint8_t* utf8 = NULL; diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp new file mode 100755 index 0000000..4c94126 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Circular.cpp @@ -0,0 +1,893 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include + + + +using namespace std; +using namespace Dali; +using namespace Toolkit; +using namespace Text; + +namespace +{ +const std::string TEST_IMAGE_FILE_NAME1 = TEST_RESOURCE_DIR "/application-icon-20.png"; +const std::string TEST_IMAGE_FILE_NAME2 = TEST_RESOURCE_DIR "/application-icon-26.png"; + +const std::vector embeddedItems = { TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2, TEST_IMAGE_FILE_NAME2 }; + +struct CircularTextData +{ + std::string description; + std::string text; + DevelText::RendererParameters& textParameters; + const std::vector& embeddedItems; + bool blend:1; +}; + + +bool CircularRenderTest( const CircularTextData& data ) +{ + bool ret = true; + + Dali::Vector embeddedItemLayout; + + Devel::PixelBuffer pixelBuffer = Toolkit::DevelText::Render( data.textParameters, embeddedItemLayout ); + + const int dstWidth = static_cast( pixelBuffer.GetWidth() ); + const int dstHeight = static_cast( pixelBuffer.GetHeight() ); + + unsigned int index = 0u; + for( const auto& itemLayout : embeddedItemLayout ) + { + int width = static_cast( itemLayout.size.width ); + int height = static_cast( itemLayout.size.height ); + int x = static_cast( itemLayout.position.x ); + int y = static_cast( itemLayout.position.y ); + + Dali::Devel::PixelBuffer itemPixelBuffer = Dali::LoadImageFromFile( data.embeddedItems[index++] ); + itemPixelBuffer.Resize( width, height ); + itemPixelBuffer.Rotate( itemLayout.angle ); + + width = static_cast( itemPixelBuffer.GetWidth() ); + height = static_cast( itemPixelBuffer.GetHeight() ); + + Dali::Pixel::Format itemPixelFormat = itemPixelBuffer.GetPixelFormat(); + + // Check if the item is out of the buffer. + if( ( x + width < 0 ) || + ( x > dstWidth ) || + ( y < 0 ) || + ( y - height > dstHeight ) ) + { + // The embedded item is completely out of the buffer. + continue; + } + + // Crop if it exceeds the boundaries of the destination buffer. + int layoutX = 0; + int layoutY = 0; + int cropX = 0; + int cropY = 0; + int newWidth = width; + int newHeight = height; + + bool crop = false; + + if( 0 > x ) + { + newWidth += x; + cropX = std::abs( x ); + crop = true; + } + else + { + layoutX = x; + } + + if( cropX + newWidth > dstWidth ) + { + crop = true; + newWidth -= ( ( cropX + newWidth ) - dstWidth ); + } + + layoutY = y; + if( 0.f > layoutY ) + { + newHeight += layoutY; + cropY = std::abs(layoutY); + crop = true; + } + + if( cropY + newHeight > dstHeight ) + { + crop = true; + newHeight -= ( ( cropY + newHeight ) - dstHeight ); + } + + uint16_t uiCropX = static_cast(cropX); + uint16_t uiCropY = static_cast(cropY); + uint16_t uiNewWidth = static_cast(newWidth); + uint16_t uiNewHeight = static_cast(newHeight); + + if( crop ) + { + itemPixelBuffer.Crop( uiCropX, uiCropY, uiNewWidth, uiNewHeight ); + } + + // Blend the item pixel buffer with the text's color according its blending mode. + if( Dali::TextAbstraction::ColorBlendingMode::MULTIPLY == itemLayout.colorBlendingMode ) + { + Dali::Devel::PixelBuffer buffer = Dali::Devel::PixelBuffer::New( uiNewWidth, + uiNewHeight, + itemPixelFormat ); + + unsigned char* bufferPtr = buffer.GetBuffer(); + const unsigned char* itemBufferPtr = itemPixelBuffer.GetBuffer(); + const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(itemPixelFormat); + const unsigned int size = uiNewWidth * uiNewHeight * bytesPerPixel; + + for (unsigned int i = 0u; i < size; i += bytesPerPixel) + { + *(bufferPtr + 0u) = static_cast( static_cast( *(itemBufferPtr + 0u) ) * data.textParameters.textColor.r ); + *(bufferPtr + 1u) = static_cast( static_cast( *(itemBufferPtr + 1u) ) * data.textParameters.textColor.g ); + *(bufferPtr + 2u) = static_cast( static_cast( *(itemBufferPtr + 2u) ) * data.textParameters.textColor.b ); + *(bufferPtr + 3u) = static_cast( static_cast( *(itemBufferPtr + 3u) ) * data.textParameters.textColor.a ); + + itemBufferPtr += bytesPerPixel; + bufferPtr += bytesPerPixel; + } + + itemPixelBuffer = buffer; + } + + Dali::Toolkit::DevelText::UpdateBuffer(itemPixelBuffer, pixelBuffer, layoutX, layoutY, data.blend); + } + + return ret; +} + +} // namespace + +int UtcDaliTextCircularBitmapFont(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularBitmapFont"); + + Dali::Toolkit::DevelText::BitmapFontDescription description; + Dali::Toolkit::DevelText::Glyph glyph; + glyph.url = "BitmapFontUrl"; + glyph.utf8 = "BitmapFontUrl"; + glyph.ascender = 1.f; + glyph.descender = 1.f; + description.glyphs.push_back( glyph ); + + TextAbstraction::BitmapFont bitmapFont; + Dali::Toolkit::DevelText::CreateBitmapFont( description, bitmapFont ); + + for( const auto& bitmapGlyph : bitmapFont.glyphs ) + { + if( glyph.url != bitmapGlyph.url ) + { + std::cout << " different output string : " << bitmapGlyph.url << ", expected : " << glyph.url << " " << std::endl; + tet_result(TET_FAIL); + } + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularShadowText(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularShadowText"); + + Dali::Toolkit::DevelText::ShadowParameters shadowParameters; + Devel::PixelBuffer outPixelBuffer; + shadowParameters.input = Devel::PixelBuffer::New( 100, 100, Pixel::RGBA8888 ); + shadowParameters.textColor = Color::BLACK; + shadowParameters.color = Color::BLACK; + shadowParameters.offset.x = 10u; + shadowParameters.offset.y = 10u; + shadowParameters.blendShadow = true; + outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters ); + DALI_TEST_CHECK( outPixelBuffer ); + DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION ); + + shadowParameters.blendShadow = false; + outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters ); + DALI_TEST_CHECK( outPixelBuffer ); + DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION ); + + shadowParameters.input = Devel::PixelBuffer::New( 100, 100, Pixel::A8 ); + outPixelBuffer = Dali::Toolkit::DevelText::CreateShadow( shadowParameters ); + DALI_TEST_CHECK( outPixelBuffer ); + DALI_TEST_EQUALS( outPixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION ); + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularPixelBufferText(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularPixelBufferText"); + + Devel::PixelBuffer pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::A8 ); + Vector4 color; + Devel::PixelBuffer pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, true ); + pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, false ); + DALI_TEST_CHECK( pixelBufferRgba ); + DALI_TEST_EQUALS( pixelBufferRgba.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION ); + + pixbuf = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 ); + pixelBufferRgba = Dali::Toolkit::DevelText::ConvertToRgba8888( pixbuf, color, false ); + DALI_TEST_CHECK( pixelBufferRgba ); + DALI_TEST_EQUALS( pixelBufferRgba.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION ); + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularNoText(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularNoText"); + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = ""; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + + CircularTextData data = + { + "No text", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.text = ""; + textParameters.markupEnabled = true; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularIncrementAngle(void) +{ + + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularIncrementAngle"); + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 0.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + + CircularTextData data = + { + "IncrementAngle", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + + + +int UtcDaliTextCircularMarkup(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularMarkup"); + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World Hello World"; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = false; + + CircularTextData data = + { + "Markup", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularFont(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularFont"); + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = "thin"; + textParameters.fontWidth = "condensed"; + textParameters.fontSlant = "normal"; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "Font", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularAlignment(void) +{ + + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularAlignment"); + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "Hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "Alignment", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.horizontalAlignment = "begin"; + textParameters.verticalAlignment = "top"; + textParameters.circularAlignment = "begin"; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.horizontalAlignment = "end"; + textParameters.verticalAlignment = "bottom"; + textParameters.circularAlignment = "end"; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularRTL(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularRTL"); + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "مرحبا بالعالم" + image1 + " hello world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "RTL", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.circularAlignment = "begin"; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.circularAlignment = "end"; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.text = "שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم שלום עולם مرحبا بالعالم"; + textParameters.layout = "singleLine"; + textParameters.horizontalAlignment = "end"; + textParameters.fontSize = 90.f; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularN(void) +{ + + ToolkitTestApplication application; + tet_infoline(" UtcDaliTextCircularN"); + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "singleLine"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "singleLine", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.verticalAlignment = "top"; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.verticalAlignment = "bottom"; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.textWidth = 90u; + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularBlend(void) +{ + tet_infoline(" UtcDaliTextCircularN"); + + ToolkitTestApplication application; + Stage stage = Stage::GetCurrent(); + stage.SetBackgroundColor( Color::WHITE ); + stage.SetBackgroundColor( Vector4( 0.04f, 0.345f, 0.392f, 1.0f ) ); + + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "blend", + "", + textParameters, + embeddedItems, + false + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularEllipsis(void) +{ + tet_infoline(" UtcDaliTextCircularEllipsis"); + + ToolkitTestApplication application; + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = false; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "ellipsis", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + textParameters.layout = "singleLine"; + textParameters.textHeight = 50u; + textParameters.ellipsisEnabled = true; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularEmoji(void) +{ + tet_infoline(" UtcDaliTextCircularEmoji"); + + ToolkitTestApplication application; + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "\xF0\x9F\x98\x81 \xF0\x9F\x98\x82 \xF0\x9F\x98\x83 \xF0\x9F\x98\x84"; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "Emoji", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextUpdateBufferFormatCheck(void) +{ + tet_infoline(" UtcDaliTextUpdateBufferFormatCheck"); + ToolkitTestApplication application; + + Devel::PixelBuffer srcBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 ); + Devel::PixelBuffer dstBuffer = Devel::PixelBuffer::New( 10, 10, Pixel::A8 ); + + Dali::Toolkit::DevelText::UpdateBuffer(srcBuffer, dstBuffer, 0, 0, true); + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularTextColor(void) +{ + tet_infoline(" UtcDaliTextCircularTextColor"); + + ToolkitTestApplication application; + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "textColor", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} + +int UtcDaliTextCircularColorBlend(void) +{ + tet_infoline(" UtcDaliTextCircularColorBlend"); + + ToolkitTestApplication application; + + const std::string image1 = ""; + const std::string image2 = ""; + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "hello " + image1 + " world " + image2 + " this " + image1 + " is " + image2 + " a " + image1 + " demo " + image2 + " of " + image1 + " circular " + image2 + " text " + image1 + " width " + image2 + " icons."; + textParameters.horizontalAlignment = "center"; + textParameters.verticalAlignment = "center"; + textParameters.circularAlignment = "center"; + textParameters.fontFamily = "SamsungUI"; + textParameters.fontWeight = ""; + textParameters.fontWidth = ""; + textParameters.fontSlant = ""; + textParameters.layout = "circular"; + textParameters.textColor = Color::BLACK; + textParameters.fontSize = 25.f; + textParameters.textWidth = 360u; + textParameters.textHeight = 360u; + textParameters.radius = 180u; + textParameters.beginAngle = 15.f; + textParameters.incrementAngle = 360.f; + textParameters.ellipsisEnabled = true; + textParameters.markupEnabled = true; + + CircularTextData data = + { + "colorBlend", + "", + textParameters, + embeddedItems, + true + }; + + if( !CircularRenderTest( data ) ) + { + tet_result(TET_FAIL); + } + + tet_result(TET_PASS); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp index 7007170..779eb56 100755 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Markup.cpp @@ -36,6 +36,7 @@ using namespace Text; namespace { + /////////////////////////////////////////////////////////// struct TokenComparisonData @@ -182,9 +183,20 @@ namespace Vector colorRuns; Vector fontRuns; - MarkupProcessData markupProcessData( colorRuns, fontRuns ); + Vector items; + MarkupProcessData markupProcessData( colorRuns, fontRuns, items ); ProcessMarkupString( data.xHTMLEntityString, markupProcessData ); + for( Vector::Iterator it = items.Begin(), + endIt = items.End(); + it != endIt; + ++it ) + { + EmbeddedItem& item = *it; + delete[] item.url; + } + items.Clear(); + if( markupProcessData.markupProcessedText != data.expectedString ) { std::cout << " different output string : " << markupProcessData.markupProcessedText << ", expected : " << data.expectedString << " " << std::endl; diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp old mode 100644 new mode 100755 index 65a56da..b26d11b --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Shaping.cpp @@ -55,8 +55,8 @@ struct GlyphInfoData float yBearing; ///< The distance from the baseline to the topmost border of the glyph float advance; ///< The distance to move the cursor for this glyph float scaleFactor; ///< The scaling applied (fixed-size fonts only) - bool softwareItalic; ///< Whether glyph needs software support to draw italic style - bool softwareBold; ///< Whether glyph needs software support to draw bold style + bool isItalicRequired; ///< Whether the italic style is required. + bool isBoldRequired; ///< Whether the bold style is required. }; bool IsEqualGlyph ( const GlyphInfoData& glyphData, const GlyphInfo& glyph ) @@ -93,11 +93,11 @@ bool IsEqualGlyph ( const GlyphInfoData& glyphData, const GlyphInfo& glyph ) { return false; } - if( glyphData.softwareItalic != glyph.softwareItalic ) + if( glyphData.isItalicRequired != glyph.isItalicRequired ) { return false; } - if( glyphData.softwareBold != glyph.softwareBold ) + if( glyphData.isBoldRequired != glyph.isBoldRequired ) { return false; } @@ -551,14 +551,14 @@ int UtcDaliTextSoftwareStyling(void) struct GlyphInfoData glyphs01[] = { - { 2u, 4857u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, false }, - { 2u, 7316u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, false }, - { 2u, 4364u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, false }, + { 2u, 4857u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, true }, + { 2u, 7316u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, true }, + { 2u, 4364u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, true }, }; struct GlyphInfoData glyphs02[] = { { 2u, 4857u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, false, false }, - { 2u, 7316u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, false, false }, + { 2u, 7316u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, false, true }, { 2u, 4364u, 0.f, 0.f, 0.f, 0.f, 15.f, 0.f, true, false }, }; diff --git a/dali-toolkit/devel-api/file.list b/dali-toolkit/devel-api/file.list index 115156e..25be5fa 100755 --- a/dali-toolkit/devel-api/file.list +++ b/dali-toolkit/devel-api/file.list @@ -47,6 +47,8 @@ devel_api_src_files = \ $(devel_api_src_dir)/layouting/layout-transition-data.cpp \ $(devel_api_src_dir)/scripting/script.cpp \ $(devel_api_src_dir)/styling/style-manager-devel.cpp \ + $(devel_api_src_dir)/text/bitmap-font.cpp \ + $(devel_api_src_dir)/text/text-utils-devel.cpp \ $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \ $(devel_api_src_dir)/transition-effects/cube-transition-effect.cpp \ $(devel_api_src_dir)/transition-effects/cube-transition-fold-effect.cpp \ @@ -182,7 +184,9 @@ devel_api_text_controls_header_files = \ $(devel_api_src_dir)/controls/text-controls/text-style-properties-devel.h devel_api_text_header_files = \ - $(devel_api_src_dir)/text/text-enumerations-devel.h + $(devel_api_src_dir)/text/text-enumerations-devel.h \ + $(devel_api_src_dir)/text/bitmap-font.h \ + $(devel_api_src_dir)/text/text-utils-devel.h devel_api_tool_bar_header_files = \ $(devel_api_src_dir)/controls/tool-bar/tool-bar.h diff --git a/dali-toolkit/devel-api/text/bitmap-font.cpp b/dali-toolkit/devel-api/text/bitmap-font.cpp new file mode 100755 index 0000000..1e0e9c6 --- /dev/null +++ b/dali-toolkit/devel-api/text/bitmap-font.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +// EXTERNAL INCLUDE +#include +#include + +// INTERNAL INCLUDE +#include +#include + + +namespace Dali +{ + +namespace Toolkit +{ +using namespace Text; +namespace DevelText +{ + +Glyph::Glyph() +: url{}, + utf8{ 0u }, + ascender{ 0.f }, + descender{ 0.f } +{} + +Glyph::~Glyph() +{} + +BitmapFontDescription::BitmapFontDescription() +: glyphs{}, + name{}, + underlinePosition{ 0.f }, + underlineThickness{ 1.f } +{} + +BitmapFontDescription::~BitmapFontDescription() +{} + +void CreateBitmapFont( const BitmapFontDescription& description, TextAbstraction::BitmapFont& bitmapFont ) +{ + bitmapFont.glyphs.reserve( description.glyphs.size() ); + bitmapFont.name = description.name; + bitmapFont.underlinePosition = description.underlinePosition; + bitmapFont.underlineThickness = description.underlineThickness; + + for( const auto& glyph : description.glyphs ) + { + // 1) Convert to utf32 + Vector utf32; + utf32.Resize( glyph.utf8.size() ); + + const uint32_t numberOfCharacters = ( glyph.utf8.size() == 0 ) ? 0 : + Text::Utf8ToUtf32( reinterpret_cast( glyph.utf8.c_str() ), + glyph.utf8.size(), + &utf32[0u] ); + utf32.Resize( numberOfCharacters ); + + TextAbstraction::BitmapGlyph bitmapGlyph( glyph.url, utf32[0u], glyph.ascender, glyph.descender ); + + bitmapFont.glyphs.push_back( std::move( bitmapGlyph ) ); + } +} + +} // namespace DevelText + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/devel-api/text/bitmap-font.h b/dali-toolkit/devel-api/text/bitmap-font.h new file mode 100755 index 0000000..ca068b4 --- /dev/null +++ b/dali-toolkit/devel-api/text/bitmap-font.h @@ -0,0 +1,107 @@ +#ifndef DALI_TOOLKIT_FONT_BITMAP_DEVEL_H +#define DALI_TOOLKIT_FONT_BITMAP_DEVEL_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace TextAbstraction +{ +// Forward declarations +struct BitmapFont; +} + +namespace Toolkit +{ + +namespace DevelText +{ + +/** + * @brief Struct that stores the needed info to create a bitmap glyph. + */ + +struct DALI_TOOLKIT_API Glyph +{ + /** + * @brief Default constructor. + * + * Initialize the members to its defaults. + */ + Glyph(); + + /** + * @brief Default destructor. + */ + ~Glyph(); + + std::string url; ///< The url of the glyph. + std::string utf8; ///< the glyph encoded in utf8 + float ascender; ///< The ascender. The distance from the base line to the top of the glyph. + float descender; ///< The descender. The distance from the base line to the bottom of the glyph. +}; + +/** + * @brief Describes a bitmap font. + */ +struct DALI_TOOLKIT_API BitmapFontDescription +{ + /** + * @brief Default constructor. + * + * Initialize the members to its defaults. + */ + BitmapFontDescription(); + + /** + * @brief Default destructor. + */ + ~BitmapFontDescription(); + + std::vector glyphs; ///< Vector of glyphs. + std::string name; ///< Name of the font. + float underlinePosition; ///< The position of the underline from the base line. + float underlineThickness; ///< The thickness of the underline. +}; + +/** + * @brief Creates a bitmap font with the given description. + * + * The @p bitmapFont output can be passed to the FontClient::GetFontId() + * method to load the font and get an Id. + * + * @param[in] description The description of the bitmap font. + * @param[out] bitmapFont A bitmap font. + * + * @note If the @e ascender and @e descender of the glyphs are zero, the @e descender value will be left as zero and all the bitmaps will be loaded to find out the @e ascender value. + */ +DALI_TOOLKIT_API void CreateBitmapFont( const BitmapFontDescription& description, TextAbstraction::BitmapFont& bitmapFont ); + +} // namespace DevelText + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_UTILS_DEVEL_H diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp new file mode 100755 index 0000000..3a286ad --- /dev/null +++ b/dali-toolkit/devel-api/text/text-utils-devel.cpp @@ -0,0 +1,1360 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ + +using namespace TextAbstraction; + +namespace Toolkit +{ +using namespace Text; + +namespace DevelText +{ + +namespace Layout +{ + +/** + * @brief The text's layout. + */ +enum Type +{ + SINGLELINE, ///< The text is laid out on a single line. + MULTILINE, ///< The text is laid out in multiple lines. + CIRCULAR, ///< The text is laid out on a single line following a circular path. +}; + +} // namespace Layout + +namespace CircularAlignment +{ + +/** + * @brief The enumerations for the circular alignment. + */ +enum Type +{ + BEGIN, ///< The text is aligned to the @p begin angle of the arc (or to the @p begin+increment if it's a RTL text). + CENTER, ///< The text is centered within the arc. + END, ///< The text is aligned to the @p begin+increment angle of the arc (or to the @p begin if it's a RTL text). +}; + +} // namespace CircularAlignment + +const float TO_POINT_26_DOT_6 = 64.f; +const float TO_FLOAT = 1.f / 255.f; +const float TO_UCHAR = 255.f; +const bool RTL = true; +const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians +const float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians; +const float RAD_225 = RAD_135 + Math::PI_2; ///< 225 degrees in radians; +const float RAD_270 = 3.f * Math::PI_2; ///< 270 degrees in radians; +const float RAD_315 = RAD_225 + Math::PI_2; ///< 315 degrees in radians; + +DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, MULTILINE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, CIRCULAR ) +DALI_ENUM_TO_STRING_TABLE_END( LAYOUT_TYPE ) + +DALI_ENUM_TO_STRING_TABLE_BEGIN( CIRCULAR_ALIGNMENT_TYPE ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, BEGIN ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, CENTER ) +DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::CircularAlignment, END ) +DALI_ENUM_TO_STRING_TABLE_END( CIRCULAR_ALIGNMENT_TYPE ) + +bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout) +{ + return Scripting::GetEnumerationProperty(propertyValue, LAYOUT_TYPE_TABLE, LAYOUT_TYPE_TABLE_COUNT, layout); +} + +bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, DevelText::CircularAlignment::Type& circularAlignment) +{ + return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment); +} + +Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout ) +{ + if( textParameters.text.empty() ) + { + Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( textParameters.textWidth, + textParameters.textHeight, + Dali::Pixel::RGBA8888 ); + + const unsigned int bufferSize = textParameters.textWidth * textParameters.textHeight * Dali::Pixel::GetBytesPerPixel(Dali::Pixel::RGBA8888); + unsigned char* buffer = pixelBuffer.GetBuffer(); + memset(buffer, 0, bufferSize); + + return pixelBuffer; + } + + MultilanguageSupport multilanguageSupport = MultilanguageSupport::Get(); + FontClient fontClient = FontClient::Get(); + MetricsPtr metrics; + Text::Layout::Engine layoutEngine; ///< The layout engine. + LogicalModelPtr logicalModel = LogicalModel::New(); ///< Pointer to the logical model. + VisualModelPtr visualModel = VisualModel::New(); ///< Pointer to the visual model. + Vector blendingMode; ///< How embedded items and bitmap font glyphs are blended with color text. + Vector isEmoji; ///< Whether the glyph is an emoji. + + // Use this to access FontClient i.e. to get down-scaled Emoji metrics. + metrics = Metrics::New( fontClient ); + layoutEngine.SetMetrics( metrics ); + + TextAbstraction::TextRenderer::Parameters rendererParameters( visualModel->mGlyphs, + visualModel->mGlyphPositions, + visualModel->mColors, + visualModel->mColorIndices, + blendingMode, + isEmoji ); + + rendererParameters.width = textParameters.textWidth; + rendererParameters.height = textParameters.textHeight; + rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888 + + Vector& utf32Characters = logicalModel->mText; // Characters encoded in utf32. + Vector mirroredUtf32Characters; // The utf32Characters Characters but mirrored if there are RTL text. + Vector& lineBreakInfo = logicalModel->mLineBreakInfo; // The line break info. + Vector& scripts = logicalModel->mScriptRuns; // Charactes's script. + Vector& fontDescriptionRuns = logicalModel->mFontDescriptionRuns; // Desired font descriptions. + Vector& validFonts = logicalModel->mFontRuns; // Validated fonts. + Vector& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph. + Vector& bidirectionalLineInfo = logicalModel->mBidirectionalLineInfo; // The bidirectional info per line. + Vector& directions = logicalModel->mCharacterDirections; // Character's directions. + Vector& colorRuns = logicalModel->mColorRuns; // colors of the text. + + Vector& glyphsToCharacters = visualModel->mGlyphsToCharacters; // Glyphs to character map. + Vector& charactersToGlyph = visualModel->mCharactersToGlyph; // Characters to glyphs map. + Vector& charactersPerGlyph = visualModel->mCharactersPerGlyph; // Number of characters per glyph. + Vector& glyphsPerCharacter = visualModel->mGlyphsPerCharacter; // The number of glyphs that are shaped. + Vector& lines = visualModel->mLines; // The laid out lines. + + Vector newParagraphGlyphs; // Glyphs for the new paragraph characters. + + // the default font's description. + FontDescription defaultFontDescription; + PointSize26Dot6 defaultPointSize = FontClient::DEFAULT_POINT_SIZE; + + Length numberOfCharacters = 0u; // The number of characters (not glyphs!). + bool isTextMirrored = false; // Whether the text has been mirrored. + + const uint8_t* utf8 = NULL; // pointer to the first character of the text (encoded in utf8) + Length textSize = 0u; // The length of the utf8 string. + + //////////////////////////////////////////////////////////////////////////////// + // Process the markup string if the mark-up processor is enabled. + //////////////////////////////////////////////////////////////////////////////// + + MarkupProcessData markupProcessData( colorRuns, + fontDescriptionRuns, + logicalModel->mEmbeddedItems ); + + if (textParameters.markupEnabled) + { + ProcessMarkupString(textParameters.text, markupProcessData); + textSize = markupProcessData.markupProcessedText.size(); + + // This is a bit horrible but std::string returns a (signed) char* + utf8 = reinterpret_cast(markupProcessData.markupProcessedText.c_str()); + } + else + { + textSize = textParameters.text.size(); + + // This is a bit horrible but std::string returns a (signed) char* + utf8 = reinterpret_cast(textParameters.text.c_str()); + } + + //////////////////////////////////////////////////////////////////////////////// + // Convert from utf8 to utf32 + //////////////////////////////////////////////////////////////////////////////// + + utf32Characters.Resize(textSize); + + // Transform a text array encoded in utf8 into an array encoded in utf32. + // It returns the actual number of characters. + numberOfCharacters = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() ); + utf32Characters.Resize( numberOfCharacters ); + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the Line and Word Break Info. + //////////////////////////////////////////////////////////////////////////////// + + lineBreakInfo.Resize( numberOfCharacters, LINE_NO_BREAK ); + + SetLineBreakInfo( utf32Characters, + 0u, + numberOfCharacters, + lineBreakInfo ); + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the script runs. + //////////////////////////////////////////////////////////////////////////////// + + multilanguageSupport.SetScripts( utf32Characters, + 0u, + numberOfCharacters, + scripts ); + + // Check if there are emojis. + // If there are an RGBA8888 pixel format is needed. + for( const auto& run : scripts ) + { + if( run.script == TextAbstraction::Script::EMOJI ) + { + rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; + break; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the font runs. + //////////////////////////////////////////////////////////////////////////////// + + // Set the description font run with the given text parameters. + FontDescriptionRun fontDescriptionRun; + fontDescriptionRun.characterRun.characterIndex = 0u; + fontDescriptionRun.characterRun.numberOfCharacters = numberOfCharacters; + + fontDescriptionRun.familyLength = 0u; + fontDescriptionRun.familyName = nullptr; + fontDescriptionRun.familyDefined = !textParameters.fontFamily.empty(); + if( fontDescriptionRun.familyDefined ) + { + // The allocated memory will be freed when the logical model is destroyed. + fontDescriptionRun.familyLength = textParameters.fontFamily.size(); + fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; + memcpy( fontDescriptionRun.familyName, textParameters.fontFamily.c_str(), fontDescriptionRun.familyLength ); + } + + fontDescriptionRun.weightDefined = !textParameters.fontWeight.empty(); + if( fontDescriptionRun.weightDefined ) + { + fontDescriptionRun.weight = StringToWeight( textParameters.fontWeight.c_str() ); + } + + fontDescriptionRun.widthDefined = !textParameters.fontWidth.empty(); + if( fontDescriptionRun.widthDefined ) + { + fontDescriptionRun.width = StringToWidth( textParameters.fontWidth.c_str() ); + } + + fontDescriptionRun.slantDefined = !textParameters.fontSlant.empty(); + if( fontDescriptionRun.slantDefined ) + { + fontDescriptionRun.slant = StringToSlant( textParameters.fontSlant.c_str() ); + } + + fontDescriptionRun.sizeDefined = !EqualsZero( textParameters.fontSize ); + if( fontDescriptionRun.sizeDefined ) + { + fontDescriptionRun.size = static_cast( textParameters.fontSize * TO_POINT_26_DOT_6 ); + } + + fontDescriptionRuns.PushBack( fontDescriptionRun ); + + // Validates the fonts. If there is a character with no assigned font it sets a default one. + // After this call, fonts are validated. + multilanguageSupport.ValidateFonts( utf32Characters, + scripts, + fontDescriptionRuns, + defaultFontDescription, + defaultPointSize, + 0u, + numberOfCharacters, + validFonts ); + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the Bidirectional info. + //////////////////////////////////////////////////////////////////////////////// + + bidirectionalInfo.Reserve( 1u ); + + SetBidirectionalInfo( utf32Characters, + scripts, + lineBreakInfo, + 0u, + numberOfCharacters, + bidirectionalInfo ); + + const bool hasBidirectionalText = 0u != bidirectionalInfo.Count(); + if( hasBidirectionalText ) + { + // Only set the character directions if there is right to left characters. + GetCharactersDirection( bidirectionalInfo, + numberOfCharacters, + 0u, + numberOfCharacters, + directions ); + + // This paragraph has right to left text. Some characters may need to be mirrored. + // TODO: consider if the mirrored string can be stored as well. + + isTextMirrored = GetMirroredText( utf32Characters, + directions, + bidirectionalInfo, + 0u, + numberOfCharacters, + mirroredUtf32Characters ); + } + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyphs. Text shaping + //////////////////////////////////////////////////////////////////////////////// + + const Vector& textToShape = isTextMirrored ? mirroredUtf32Characters : utf32Characters; + + newParagraphGlyphs.Reserve( 1u ); + + // Shapes the text. + ShapeText( textToShape, + lineBreakInfo, + scripts, + validFonts, + 0u, + 0u, + numberOfCharacters, + rendererParameters.glyphs, + glyphsToCharacters, + charactersPerGlyph, + newParagraphGlyphs ); + + // Create the 'number of glyphs' per character and the glyph to character conversion tables. + visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters ); + visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters ); + + const Length numberOfGlyphs = rendererParameters.glyphs.Count(); + + // Once the text has been shaped and the glyphs created it's possible to replace the font id of those glyphs + // that represent an image or an item and create the embedded item layout info. + // Note: the position of the embedded item can't be set until the text is laid-out. + embeddedItemLayout.Reserve( logicalModel->mEmbeddedItems.Count() ); + for( const auto& item : logicalModel->mEmbeddedItems ) + { + // Get the glyph that matches with the character index. + const GlyphIndex glyphIndex = visualModel->mCharactersToGlyph[item.characterIndex]; + GlyphInfo& glyph = rendererParameters.glyphs[glyphIndex]; + + glyph.fontId = 0u; + Pixel::Format pixelFormat = Pixel::A8; + TextAbstraction::FontClient::EmbeddedItemDescription description = { std::string( item.url, item.urlLength ), item.width, item.height, item.colorBlendingMode }; + glyph.index = fontClient.CreateEmbeddedItem( description, pixelFormat ); // Set here an index to an item. + + if( ( Pixel::RGBA8888 == pixelFormat ) || ( Pixel::BGRA8888 == pixelFormat ) ) + { + rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; + } + + // If the url is empty the item is going to be added after the text is rendered. It's needed to store the layout here. + if( description.url.empty() ) + { + EmbeddedItemInfo embeddedInfo = + { + item.characterIndex, + glyphIndex, + Vector2::ZERO, + Size( static_cast( item.width ), static_cast( item.height ) ), + Size( static_cast( item.width ), static_cast( item.height ) ), + Degree( 0.f ), + item.colorBlendingMode + }; + + embeddedItemLayout.PushBack( embeddedInfo ); + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyph's metrics. + //////////////////////////////////////////////////////////////////////////////// + + metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs ); + + //////////////////////////////////////////////////////////////////////////////// + // Set the color runs in glyphs. + //////////////////////////////////////////////////////////////////////////////// + + SetColorSegmentationInfo( colorRuns, + charactersToGlyph, + glyphsPerCharacter, + 0u, + 0u, + numberOfCharacters, + visualModel->mColors, + visualModel->mColorIndices ); + + // Insert the default color at the beginning of the vector. + visualModel->mColors.Insert( visualModel->mColors.Begin(),textParameters.textColor ); + + // Set how the embedded items are blended with text color. + blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE ); + + if( !textParameters.isTextColorSet ) + { + // Traverse the color runs. + for( const auto& run : colorRuns ) + { + const GlyphIndex firstGlyph = visualModel->mCharactersToGlyph[run.characterRun.characterIndex]; + const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u; + const GlyphIndex lastGlyphPlusOne = visualModel->mCharactersToGlyph[lastCharacter] + visualModel->mGlyphsPerCharacter[lastCharacter]; + + for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index ) + { + blendingMode[index] = ColorBlendingMode::MULTIPLY; + } + } + } + + // Traverse the embedded items and update the blending mode vector. + for( const auto& item : logicalModel->mEmbeddedItems ) + { + const GlyphIndex glyphIndex = visualModel->mCharactersToGlyph[item.characterIndex]; + blendingMode[glyphIndex] = item.colorBlendingMode; + } + + //////////////////////////////////////////////////////////////////////////////// + // Set the isEmoji Vector + //////////////////////////////////////////////////////////////////////////////// + + isEmoji.Resize( numberOfGlyphs, false ); + + for( const auto& run : scripts ) + { + if( run.script == TextAbstraction::Script::EMOJI ) + { + const GlyphIndex firstGlyph = visualModel->mCharactersToGlyph[run.characterRun.characterIndex]; + const CharacterIndex lastCharacter = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u; + const GlyphIndex lastGlyphPlusOne = visualModel->mCharactersToGlyph[lastCharacter] + visualModel->mGlyphsPerCharacter[lastCharacter]; + + for( GlyphIndex index = firstGlyph; index < lastGlyphPlusOne; ++index ) + { + isEmoji[index] = true; + } + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Layout the text. + //////////////////////////////////////////////////////////////////////////////// + + // Sets the alignment + HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER; + HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER; + VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER; + Layout::Type layout = Layout::SINGLELINE; + CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN; + + Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment ); + GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment ); + horizontalCircularAlignment = horizontalAlignment; + + Property::Value verticalAlignmentStr( textParameters.verticalAlignment ); + GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment ); + + Property::Value layoutStr( textParameters.layout ); + GetLayoutEnumeration( layoutStr, layout ); + + Property::Value circularAlignmentStr( textParameters.circularAlignment ); + GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment ); + + // Whether the layout is multi-line. + const Text::Layout::Engine::Type horizontalLayout = ( Layout::MULTILINE == layout ) ? Text::Layout::Engine::MULTI_LINE_BOX : Text::Layout::Engine::SINGLE_LINE_BOX; + layoutEngine.SetLayout( horizontalLayout ); // TODO: multi-line. + + + // Whether the layout is circular. + const bool isCircularTextLayout = (Layout::CIRCULAR == layout); + const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle ); + + // Calculates the max ascender or the max descender. + // Is used to calculate the radius of the base line of the text. + float maxAscenderDescender = 0.f; + if( isCircularTextLayout ) + { + FontId currentFontId = 0u; + for( const auto& glyph : rendererParameters.glyphs ) + { + if( currentFontId != glyph.fontId ) + { + currentFontId = glyph.fontId; + FontMetrics metrics; + fontClient.GetFontMetrics(currentFontId, metrics); + maxAscenderDescender = std::max( maxAscenderDescender, isClockwise ? metrics.ascender : metrics.descender ); + } + } + } + const unsigned int radius = textParameters.radius - static_cast( maxAscenderDescender ); + + // Convert CircularAlignment to HorizontalAlignment. + if( isCircularTextLayout ) + { + switch( circularAlignment ) + { + case CircularAlignment::BEGIN: + { + horizontalCircularAlignment = Toolkit::HorizontalAlignment::BEGIN; + break; + } + case CircularAlignment::CENTER: + { + horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER; + break; + } + case CircularAlignment::END: + { + horizontalCircularAlignment = Toolkit::HorizontalAlignment::END; + break; + } + } + } + + // Set the layout parameters. + Size textLayoutArea( static_cast( textParameters.textWidth ), + static_cast( textParameters.textHeight ) ); + + if( isCircularTextLayout ) + { + // In a circular layout, the length of the text area depends on the radius. + rendererParameters.radius = radius; + textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast( rendererParameters.radius ) ); + } + + Text::Layout::Parameters layoutParameters( textLayoutArea, + textToShape.Begin(), + lineBreakInfo.Begin(), + nullptr, + ( 0u != directions.Count() ) ? directions.Begin() : nullptr, + rendererParameters.glyphs.Begin(), + glyphsToCharacters.Begin(), + charactersPerGlyph.Begin(), + charactersToGlyph.Begin(), + glyphsPerCharacter.Begin(), + numberOfGlyphs, + isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment, + LineWrap::WORD, + 0.f, + false, + false ); // Outline's width + + // Resize the vector of positions to have the same size than the vector of glyphs. + rendererParameters.positions.Resize( numberOfGlyphs ); + + // Whether the last character is a new paragraph character. + layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( textToShape[numberOfCharacters - 1u] ); + + // The initial glyph and the number of glyphs to layout. + layoutParameters.startGlyphIndex = 0u; + layoutParameters.numberOfGlyphs = numberOfGlyphs; + layoutParameters.startLineIndex = 0u; + layoutParameters.estimatedNumberOfLines = 1u; + + // Update the visual model. + Size newLayoutSize; + bool isAutoScrollEnabled = false; + layoutEngine.LayoutText( layoutParameters, + rendererParameters.positions, + lines, + newLayoutSize, + textParameters.ellipsisEnabled, + isAutoScrollEnabled ); + + //////////////////////////////////////////////////////////////////////////////// + // Reorder BiDirectional lines. + //////////////////////////////////////////////////////////////////////////////// + + if( hasBidirectionalText ) + { + // Reorder the line. + bidirectionalLineInfo.Reserve( 1u ); + + ReorderLines( bidirectionalInfo, + 0u, + numberOfCharacters, + lines, + bidirectionalLineInfo ); + + // Set the bidirectional info per line into the layout parameters. + layoutParameters.lineBidirectionalInfoRunsBuffer = bidirectionalLineInfo.Begin(); + layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count(); + + // Re-layout the text. Reorder those lines with right to left characters. + layoutEngine.ReLayoutRightToLeftLines( layoutParameters, + 0u, + numberOfCharacters, + rendererParameters.positions ); + } + + //////////////////////////////////////////////////////////////////////////////// + // Align the text. + //////////////////////////////////////////////////////////////////////////////// + + // Retrieve the line of text to know the direction and the width. @todo multi-line + const LineRun& line = lines[0u]; + + if( isCircularTextLayout ) + { + // Set the circular alignment. + rendererParameters.circularLayout = isClockwise ? TextRenderer::Parameters::CLOCKWISE : TextRenderer::Parameters::COUNTER_CLOCKWISE; + + // Update the text's height to be used by the ellipsis code. + textLayoutArea.height = newLayoutSize.height; + + // Set the size of the text laid out on a straight horizontal line. + rendererParameters.circularWidth = static_cast( newLayoutSize.width ); + rendererParameters.circularHeight = static_cast( newLayoutSize.height ); + + // Calculate the center of the circular text according the horizontal and vertical alingments and the radius. + switch( horizontalAlignment ) + { + case HorizontalAlignment::BEGIN: + { + rendererParameters.centerX = static_cast(textParameters.radius); + break; + } + case HorizontalAlignment::CENTER: + { + rendererParameters.centerX = static_cast( textParameters.textWidth / 2u ); + break; + } + case HorizontalAlignment::END: + { + rendererParameters.centerX = static_cast( textParameters.textWidth ) - static_cast(textParameters.radius); + break; + } + } + + switch( verticalAlignment ) + { + case VerticalAlignment::TOP: + { + rendererParameters.centerY = static_cast(textParameters.radius); + break; + } + case VerticalAlignment::CENTER: + { + rendererParameters.centerY = static_cast( textParameters.textHeight / 2u ); + break; + } + case VerticalAlignment::BOTTOM: + { + rendererParameters.centerY = static_cast( textParameters.textHeight ) - static_cast(textParameters.radius); + break; + } + } + + // Calculate the beginning angle according with the given horizontal alignment. + const bool isRTL = RTL == line.direction; + + CircularAlignment::Type alignment = circularAlignment; + if( isRTL ) + { + // Swap the alignment type if the line is right to left. + switch( alignment ) + { + case CircularAlignment::BEGIN: + { + alignment = CircularAlignment::END; + break; + } + case CircularAlignment::CENTER: + { + // Nothing to do. + break; + } + case CircularAlignment::END: + { + alignment = CircularAlignment::BEGIN; + break; + } + } + } + + float angleOffset = 0.f; + + switch( alignment ) + { + case CircularAlignment::BEGIN: + { + angleOffset = 0.f; + break; + } + case CircularAlignment::CENTER: + { + const bool isNeg = textParameters.incrementAngle < 0.f; + const float textWidth = static_cast( rendererParameters.circularWidth ); + angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast( radius ); + break; + } + case CircularAlignment::END: + { + const bool isNeg = textParameters.incrementAngle < 0.f; + const float textWidth = static_cast( rendererParameters.circularWidth ); + angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast( radius ); + break; + } + } + + // Update the beginning angle with the calculated offset. + rendererParameters.beginAngle = Radian( Degree( textParameters.beginAngle ) ) + angleOffset; + + // Set the vertical position of the glyphs. + for( auto& position : rendererParameters.positions ) + { + position.y = 0.f; + } + } + else + { + // Calculate the vertical offset according with the given alignment. + float penY = 0.f; + + switch( verticalAlignment ) + { + case VerticalAlignment::TOP: + { + penY = line.ascender; + break; + } + case VerticalAlignment::CENTER: + { + penY = line.ascender + 0.5f * ( textLayoutArea.height - ( line.ascender - line.descender ) ); + break; + } + case VerticalAlignment::BOTTOM: + { + penY = textLayoutArea.height; + break; + } + } + + // Calculate the horizontal offset according with the given alignment. + float alignmentOffset = 0.f; + layoutEngine.Align( textLayoutArea, + 0u, + numberOfCharacters, + horizontalAlignment, + lines, + alignmentOffset, + Dali::LayoutDirection::LEFT_TO_RIGHT, + false ); + + // Update the position of the glyphs with the calculated offsets. + for( auto& position : rendererParameters.positions ) + { + position.x += line.alignmentOffset; + position.y = penY; + } + } + + // Cairo adds the bearing to the position of the glyph + // that has already been added by the DALi's layout engine, + // so it's needed to be removed here. + for( unsigned int index = 0u; index < rendererParameters.glyphs.Count(); ++index ) + { + const GlyphInfo& glyph = rendererParameters.glyphs[index]; + Vector2& position = rendererParameters.positions[index]; + + position.x -= glyph.xBearing; + } + + // Set the position of the embedded items (if there is any). + EmbeddedItemInfo* embeddedItemLayoutBuffer = embeddedItemLayout.Begin(); + + auto transformToArc = isClockwise ? &Dali::TextAbstraction::TransformToArcClockwise : &Dali::TextAbstraction::TransformToArcAntiClockwise; + + for( Length index = 0u, endIndex = embeddedItemLayout.Count(); index < endIndex; ++index ) + { + EmbeddedItemInfo& embeddedItem = *( embeddedItemLayoutBuffer + index ); + + embeddedItem.position = rendererParameters.positions[embeddedItem.glyphIndex]; + + if( isCircularTextLayout ) + { + // Calculate the new position of the embedded item in the circular path. + + // Center of the bitmap. + const float halfWidth = 0.5f * embeddedItem.size.width; + const float halfHeight = 0.5f * embeddedItem.size.height; + double centerX = static_cast( embeddedItem.position.x + halfWidth ); + double centerY = static_cast(embeddedItem.position.y - halfHeight); + + Dali::TextAbstraction::CircularTextParameters circularTextParameters; + + circularTextParameters.radius = static_cast( radius ); + circularTextParameters.invRadius = 1.0 / circularTextParameters.radius; + circularTextParameters.beginAngle = static_cast( -rendererParameters.beginAngle + Dali::Math::PI_2 ); + circularTextParameters.centerX = 0.5f * static_cast( textParameters.textWidth ); + circularTextParameters.centerY = 0.5f * static_cast( textParameters.textHeight ); + + // Calculate the rotation angle. + float radians = rendererParameters.beginAngle; + if( isClockwise ) + { + radians += static_cast( circularTextParameters.invRadius * centerX ); + radians = -radians; + } + else + { + radians -= static_cast( circularTextParameters.invRadius * centerX ); + radians = -radians + Dali::Math::PI; + } + embeddedItem.angle = Degree( Radian( radians ) ); + + transformToArc( circularTextParameters, centerX, centerY ); + + // Recalculate the size of the embedded item after the rotation to position it correctly. + float width = embeddedItem.size.width; + float height = embeddedItem.size.height; + + // Transform the input angle into the range [0..2PI] + radians = fmod( radians, TWO_PI ); + radians += ( radians < 0.f ) ? TWO_PI : 0.f; + + // Does the same operations than rotate by shear. + if( ( radians > Math::PI_4 ) && ( radians <= RAD_135 ) ) + { + std::swap( width, height ); + radians -= Math::PI_2; + } + else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) ) + { + radians -= Math::PI; + } + else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) ) + { + std::swap( width, height ); + radians -= RAD_270; + } + + if( fabs( radians ) > Dali::Math::MACHINE_EPSILON_10 ) + { + const float angleSinus = fabs( sin( radians ) ); + const float angleCosinus = cos( radians ); + + // Calculate the rotated image dimensions. + embeddedItem.rotatedSize.height = width * angleSinus + height * angleCosinus; + embeddedItem.rotatedSize.width = height * angleSinus + width * angleCosinus + 1.f; + } + + embeddedItem.position.x = floor( static_cast( centerX ) - 0.5f * embeddedItem.rotatedSize.width ); + embeddedItem.position.y = floor( static_cast( centerY ) - 0.5f * embeddedItem.rotatedSize.height ); + } + else + { + embeddedItem.position.y -= embeddedItem.size.height; + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Ellipsis the text. + //////////////////////////////////////////////////////////////////////////////// + + if( textParameters.ellipsisEnabled ) + { + const LineRun& line = lines[0u]; // TODO: multi-line + + if( line.ellipsis ) + { + Length finalNumberOfGlyphs = 0u; + + if( ( line.ascender - line.descender ) > textLayoutArea.height ) + { + // The height of the line is bigger than the height of the text area. + // Show the ellipsis glyph even if it doesn't fit in the text area. + // If no text is rendered then issues are rised and it may be a while + // until is find out that the text area is too small. + + // Get the first glyph which is going to be replaced and the ellipsis glyph. + GlyphInfo& glyphInfo = rendererParameters.glyphs[0u]; + const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphInfo.fontId ) ); + + // Change the 'x' and 'y' position of the ellipsis glyph. + Vector2& position = rendererParameters.positions[0u]; + position.x = ellipsisGlyph.xBearing; + position.y = textLayoutArea.height - ellipsisGlyph.yBearing; + + // Replace the glyph by the ellipsis glyph. + glyphInfo = ellipsisGlyph; + + // Set the final number of glyphs + finalNumberOfGlyphs = 1u; + } + else + { + + // firstPenX, penY and firstPenSet are used to position the ellipsis glyph if needed. + float firstPenX = 0.f; // Used if rtl text is elided. + bool firstPenSet = false; + + // Add the ellipsis glyph. + bool inserted = false; + float removedGlypsWidth = 0.f; + Length numberOfRemovedGlyphs = 0u; + if (line.glyphRun.numberOfGlyphs > 0u) + { + GlyphIndex index = line.glyphRun.numberOfGlyphs - 1u; + + GlyphInfo* glyphs = rendererParameters.glyphs.Begin(); + Vector2* glyphPositions = rendererParameters.positions.Begin(); + + float penY = 0.f; + + // The ellipsis glyph has to fit in the place where the last glyph(s) is(are) removed. + while( !inserted ) + { + const GlyphInfo& glyphToRemove = *( glyphs + index ); + + if( 0u != glyphToRemove.fontId ) + { + // i.e. The font id of the glyph shaped from the '\n' character is zero. + + // Need to reshape the glyph as the font may be different in size. + const GlyphInfo& ellipsisGlyph = fontClient.GetEllipsisGlyph( fontClient.GetPointSize( glyphToRemove.fontId ) ); + + if( !firstPenSet ) + { + const Vector2& position = *( glyphPositions + index ); + + // Calculates the penY of the current line. It will be used to position the ellipsis glyph. + penY = position.y; + + // Calculates the first penX which will be used if rtl text is elided. + firstPenX = position.x - glyphToRemove.xBearing; + if( firstPenX < -ellipsisGlyph.xBearing ) + { + // Avoids to exceed the bounding box when rtl text is elided. + firstPenX = -ellipsisGlyph.xBearing; + } + + removedGlypsWidth = -ellipsisGlyph.xBearing; + + firstPenSet = true; + } + + removedGlypsWidth += std::min( glyphToRemove.advance, ( glyphToRemove.xBearing + glyphToRemove.width ) ); + + // Calculate the width of the ellipsis glyph and check if it fits. + const float ellipsisGlyphWidth = ellipsisGlyph.width + ellipsisGlyph.xBearing; + if( ellipsisGlyphWidth < removedGlypsWidth ) + { + GlyphInfo& glyphInfo = *( glyphs + index ); + Vector2& position = *( glyphPositions + index ); + position.x -= ( 0.f > glyphInfo.xBearing ) ? glyphInfo.xBearing : 0.f; + + // Replace the glyph by the ellipsis glyph. + glyphInfo = ellipsisGlyph; + + // Update the isEmoji vector + isEmoji[index] = false; + + // Change the 'x' and 'y' position of the ellipsis glyph. + + if( position.x > firstPenX ) + { + position.x = firstPenX + removedGlypsWidth - ellipsisGlyphWidth; + } + + position.x += ellipsisGlyph.xBearing; + position.y = penY; + + inserted = true; + } + } + + if( !inserted ) + { + if( index > 0u ) + { + --index; + } + else + { + // No space for the ellipsis. + inserted = true; + } + ++numberOfRemovedGlyphs; + } + + // Set the final number of glyphs + finalNumberOfGlyphs = line.glyphRun.numberOfGlyphs - numberOfRemovedGlyphs; + } + } + + // Resize the number of glyphs/positions + rendererParameters.glyphs.Resize( finalNumberOfGlyphs ); + rendererParameters.positions.Resize( finalNumberOfGlyphs ); + + // Remove from the embedded items those exceding the last laid out glyph. + embeddedItemLayout.Erase( std::remove_if( embeddedItemLayout.Begin(), + embeddedItemLayout.End(), + [finalNumberOfGlyphs]( const EmbeddedItemInfo& item ) + { + return item.glyphIndex >= finalNumberOfGlyphs; + } ), + embeddedItemLayout.End() ); + } + } + } + + //////////////////////////////////////////////////////////////////////////////// + // Render the text. + //////////////////////////////////////////////////////////////////////////////// + + rendererParameters.width = textParameters.textWidth; + rendererParameters.height = textParameters.textHeight; + + TextAbstraction::TextRenderer renderer = TextAbstraction::TextRenderer::Get(); + return renderer.Render( rendererParameters ); +} + +Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters ) +{ + // The size of the pixel data. + const int width = static_cast(shadowParameters.input.GetWidth()); + const int height = static_cast(shadowParameters.input.GetHeight()); + + // The shadow's offset. + const int xOffset = static_cast( shadowParameters.offset.x ); + const int yOffset = static_cast( shadowParameters.offset.y ); + + // The size in bytes of the pixel of the input's buffer. + const Pixel::Format inputFormat = shadowParameters.input.GetPixelFormat(); + const unsigned int inputPixelSize = Pixel::GetBytesPerPixel( inputFormat ); + const bool isA8 = Pixel::A8 == inputFormat; + + // Creates the output pixel buffer. + Devel::PixelBuffer outputPixelBuffer = Devel::PixelBuffer::New(width, height, Pixel::RGBA8888); + + // Clear the output buffer + unsigned char* outputPixelBufferPtr = outputPixelBuffer.GetBuffer(); + memset(outputPixelBufferPtr, 0, width * height * Pixel::GetBytesPerPixel(Pixel::RGBA8888)); + + // Gets the buffer of the input pixel buffer. + const unsigned char* const inputPixelBuffer = shadowParameters.input.GetBuffer(); + + float textColor[4u]; + if (isA8) + { + memcpy(textColor, shadowParameters.textColor.AsFloat(), 4u * sizeof(float)); + } + const float* const shadowColor = shadowParameters.color.AsFloat(); + + // Traverse the input pixel buffer and write the text on the foreground and the shadow on the background. + for (int rowIndex = 0; rowIndex < height; ++rowIndex) + { + // Calculates the rowIndex to the input pixel buffer for the shadow and whether it's within the boundaries. + const int yOffsetIndex = rowIndex - yOffset; + const bool isValidRowIndex = ((yOffsetIndex >= 0) && (yOffsetIndex < height)); + + const int rows = rowIndex * width; + const int offsetRows = yOffsetIndex * width; + for (int columnIndex = 0; columnIndex < width; ++columnIndex) + { + // Index to the input buffer to retrieve the alpha value of the foreground text. + const unsigned int index = inputPixelSize * static_cast(rows + columnIndex); + + // Build the index to the input buffer to retrieve the alpha value of the background shadow. + unsigned int shadowIndex = 0u; + bool isValidShadowIndex = false; + if (isValidRowIndex) + { + const int xOffsetIndex = columnIndex - xOffset; + isValidShadowIndex = ((xOffsetIndex >= 0) && (xOffsetIndex < width)); + + if (isValidShadowIndex) + { + shadowIndex = inputPixelSize * static_cast(offsetRows + xOffsetIndex); + } + } + + // If the input buffer is an alpha mask, retrieve the values for the foreground text and the background shadow. + // If not retrieve the color. + float inputShadowOffsetAlphaValue = 1.f; + float inputAlphaValue = 1.f; + if (isA8) + { + // Retrieve the alpha value for the shadow. + inputShadowOffsetAlphaValue = isValidShadowIndex ? (static_cast(*(inputPixelBuffer + shadowIndex)) / 255.f) : 0.f; + + // Retrieve the alpha value for the text. + inputAlphaValue = static_cast(*(inputPixelBuffer + index)) / 255.f; + } + else + { + // The input buffer is not an alpha mask. Retrieve the color. + textColor[0u] = TO_FLOAT * static_cast( *(inputPixelBuffer + index + 0u) ); + textColor[1u] = TO_FLOAT * static_cast( *(inputPixelBuffer + index + 1u) ); + textColor[2u] = TO_FLOAT * static_cast( *(inputPixelBuffer + index + 2u) ); + textColor[3u] = TO_FLOAT * static_cast( *(inputPixelBuffer + index + 3u) ); + inputAlphaValue = textColor[3u]; + inputShadowOffsetAlphaValue = isValidShadowIndex ? TO_FLOAT * static_cast( *(inputPixelBuffer + shadowIndex + 3u) ) : 0.f; + } + + // Build the output color. + float outputColor[4u]; + + if( shadowParameters.blendShadow ) + { + // Blend the shadow's color with the text's color on top + const float textAlpha = textColor[3u] * inputAlphaValue; + const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue; + + // Blends the alpha. + outputColor[3u] = 1.f - ((1.f - textAlpha) * (1.f - shadowAlpha)); + const bool isOutputAlphaZero = outputColor[3u] < Dali::Math::MACHINE_EPSILON_1000; + if( isOutputAlphaZero ) + { + std::fill( outputColor, outputColor + 4u, 0.f ); + } + else + { + // Blends the RGB components. + float shadowComponent = 0.f; + float textComponent = 0.f; + + shadowComponent = shadowColor[0u] * inputShadowOffsetAlphaValue; + textComponent = textColor[0u] * inputAlphaValue; + outputColor[0u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]); + + shadowComponent = shadowColor[1u] * inputShadowOffsetAlphaValue; + textComponent = textColor[1u] * inputAlphaValue; + outputColor[1u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]); + + shadowComponent = shadowColor[2u] * inputShadowOffsetAlphaValue; + textComponent = textColor[2u] * inputAlphaValue; + outputColor[2u] = (textComponent * textAlpha / outputColor[3u]) + (shadowComponent * shadowAlpha * (1.f - textAlpha) / outputColor[3u]); + } + } + else + { + // No blending!!! + std::fill( outputColor, outputColor + 4u, 0.f ); + + const float textAlpha = textColor[3u]; + const float shadowAlpha = shadowColor[3u] * inputShadowOffsetAlphaValue; + + // Write shadow first. + if( shadowAlpha > Dali::Math::MACHINE_EPSILON_1000 ) + { + outputColor[0u] = shadowColor[0u] * inputShadowOffsetAlphaValue; + outputColor[1u] = shadowColor[1u] * inputShadowOffsetAlphaValue; + outputColor[2u] = shadowColor[2u] * inputShadowOffsetAlphaValue; + outputColor[3u] = shadowAlpha; + } + + // Write character on top. + if( textAlpha > Dali::Math::MACHINE_EPSILON_1000 ) + { + outputColor[0u] = textColor[0u]; + outputColor[1u] = textColor[1u]; + outputColor[2u] = textColor[2u]; + outputColor[3u] = textAlpha; + } + } + + // Write the color into the output pixel buffer. + const unsigned int outputIndex = 4u * (rows + columnIndex); + *(outputPixelBufferPtr + outputIndex + 0u) = static_cast( TO_UCHAR * outputColor[0u] ); + *(outputPixelBufferPtr + outputIndex + 1u) = static_cast( TO_UCHAR * outputColor[1u] ); + *(outputPixelBufferPtr + outputIndex + 2u) = static_cast( TO_UCHAR * outputColor[2u] ); + *(outputPixelBufferPtr + outputIndex + 3u) = static_cast( TO_UCHAR * outputColor[3u] ); + } + } + + // Returns the pixel buffer. + return outputPixelBuffer; +} + +Devel::PixelBuffer ConvertToRgba8888(Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha) +{ + if (Dali::Pixel::A8 != pixelBuffer.GetPixelFormat()) + { + // Does nothing. + return pixelBuffer; + } + + const unsigned int width = pixelBuffer.GetWidth(); + const unsigned int height = pixelBuffer.GetHeight(); + Devel::PixelBuffer newPixelBuffer = Devel::PixelBuffer::New( width, height, Dali::Pixel::RGBA8888 ); + + unsigned char* dstBuffer = newPixelBuffer.GetBuffer(); + const unsigned char* const srcBuffer = pixelBuffer.GetBuffer(); + + const unsigned char r = static_cast( TO_UCHAR * color.r ); + const unsigned char g = static_cast( TO_UCHAR * color.g ); + const unsigned char b = static_cast( TO_UCHAR * color.b ); + + unsigned char dstColor[4]; + for( unsigned int j = 0u; j < height; ++j ) + { + const unsigned int lineIndex = j * width; + for( unsigned int i=0u; i < width; ++i ) + { + const unsigned int srcIndex = lineIndex + i; + + const float srcAlpha = static_cast( *( srcBuffer + srcIndex ) ); + + if( multiplyByAlpha ) + { + dstColor[0u] = static_cast( srcAlpha * color.r ); + dstColor[1u] = static_cast( srcAlpha * color.g ); + dstColor[2u] = static_cast( srcAlpha * color.b ); + dstColor[3u] = static_cast( srcAlpha * color.a ); + } + else + { + dstColor[0u] = r; + dstColor[1u] = g; + dstColor[2u] = b; + dstColor[3u] = static_cast( srcAlpha ); + } + + const unsigned int dstIndex = srcIndex * 4u; + memcpy( dstBuffer + dstIndex, dstColor, 4u ); + } + } + + return newPixelBuffer; +} + +void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend) +{ + const Dali::Pixel::Format pixelFormat = dst.GetPixelFormat(); + if( src.GetPixelFormat() != pixelFormat ) + { + DALI_LOG_ERROR("PixelBuffer::SetBuffer. The pixel format of the new data must be the same of the current pixel buffer."); + return; + } + + const unsigned int srcWidth = src.GetWidth(); + const unsigned int srcHeight = src.GetHeight(); + const unsigned int dstWidth = dst.GetWidth(); + const unsigned int dstHeight = dst.GetHeight(); + + if( ( x > dstWidth ) || + ( y > dstHeight ) || + ( x + srcWidth > dstWidth ) || + ( y + srcHeight > dstHeight ) ) + { + DALI_LOG_ERROR("PixelBuffer::SetBuffer. The source pixel buffer is out of the boundaries of the destination pixel buffer."); + return; + } + + const unsigned int bytesPerPixel = Dali::Pixel::GetBytesPerPixel(pixelFormat); + const unsigned int alphaIndex = bytesPerPixel - 1u; + + const unsigned char* const srcBuffer = src.GetBuffer(); + unsigned char* dstBuffer = dst.GetBuffer(); + + if( !blend ) + { + const unsigned int currentLineSize = dstWidth * bytesPerPixel; + const unsigned int newLineSize = srcWidth * bytesPerPixel; + unsigned char* currentBuffer = dstBuffer + (y * dstWidth + x) * bytesPerPixel; + for (unsigned int j = 0u; j < srcHeight; ++j) + { + memcpy(currentBuffer + j * currentLineSize, srcBuffer + j * newLineSize, newLineSize); + } + } + else + { + float outputColor[4u]; + + // Blend the src pixel buffer with the dst pixel buffer as background. + // + // fgColor, fgAlpha, bgColor, bgAlpha + // + // alpha = 1 - ( 1 - fgAlpha ) * ( 1 - bgAlpha ) + // color = ( fgColor * fgAlpha / alpha ) + ( bgColor * bgAlpha * ( 1 - fgAlpha ) / alpha ) + + // Jump till the 'x,y' position + const unsigned int dstWidthBytes = dstWidth * bytesPerPixel; + dstBuffer += ( y * dstWidthBytes + x * bytesPerPixel ); + + for (unsigned int j = 0u; j < srcHeight; ++j) + { + const unsigned int srcLineIndex = j * srcWidth; + for (unsigned int i = 0u; i < srcWidth; ++i) + { + const float srcAlpha = TO_FLOAT * static_cast( *( srcBuffer + bytesPerPixel * ( srcLineIndex + i ) + alphaIndex ) ); + const float dstAlpha = TO_FLOAT * static_cast( *(dstBuffer + i*bytesPerPixel + alphaIndex) ); + + // Blends the alpha channel. + const float oneMinusSrcAlpha = 1.f - srcAlpha; + outputColor[alphaIndex] = 1.f - (oneMinusSrcAlpha * (1.f - dstAlpha)); + + // Blends the RGB channels. + const bool isOutputAlphaZero = outputColor[alphaIndex] < Dali::Math::MACHINE_EPSILON_1000; + if( isOutputAlphaZero ) + { + std::fill( outputColor, outputColor + bytesPerPixel, 0.f ); + } + else + { + const float srcAlphaOverOutputAlpha = srcAlpha / outputColor[alphaIndex]; // fgAlpha / alpha + const float dstAlphaOneMinusSrcAlphaOverOutputAlpha = dstAlpha * oneMinusSrcAlpha / outputColor[alphaIndex]; // bgAlpha * ( 1 - fgAlpha ) / alpha + for (unsigned int index = 0u; index < alphaIndex; ++index) + { + const float dstComponent = TO_FLOAT * static_cast( *( dstBuffer + i * bytesPerPixel + index ) ) * dstAlpha; + const float srcComponent = TO_FLOAT * static_cast(*(srcBuffer + bytesPerPixel * (srcLineIndex + i) + index) ) * srcAlpha; + outputColor[index] = ( srcComponent * srcAlphaOverOutputAlpha ) + ( dstComponent * dstAlphaOneMinusSrcAlphaOverOutputAlpha ); + } + } + + for (unsigned int index = 0u; index < bytesPerPixel; ++index) + { + *(dstBuffer + i * bytesPerPixel + index) = static_cast( TO_UCHAR * outputColor[index] ); + } + } + + dstBuffer += dstWidthBytes; + } + } +} + +} // namespace DevelText + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/devel-api/text/text-utils-devel.h b/dali-toolkit/devel-api/text/text-utils-devel.h new file mode 100755 index 0000000..83c6ea9 --- /dev/null +++ b/dali-toolkit/devel-api/text/text-utils-devel.h @@ -0,0 +1,201 @@ +#ifndef DALI_TOOLKIT_TEXT_UTILS_DEVEL_H +#define DALI_TOOLKIT_TEXT_UTILS_DEVEL_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace DevelText +{ + +/** + * @brief Struct with the text and style parameters to be rendered into a pixel buffer. + */ +struct DALI_TOOLKIT_API RendererParameters +{ + RendererParameters() + : text{}, + horizontalAlignment{ "begin" }, + verticalAlignment{ "top" }, + fontFamily{}, + fontWeight{}, + fontWidth{}, + fontSlant{}, + layout{ "singleLine" }, + circularAlignment{ "begin" }, + textColor{ Color::WHITE }, + fontSize{ 0.f }, + textWidth{ 0u }, + textHeight{ 0u }, + radius{ 0u }, + beginAngle{ 0.f }, + incrementAngle{ 0.f }, + ellipsisEnabled{ true }, + markupEnabled{ false }, + isTextColorSet{ false } + {} + + std::string text; ///< The text to be rendered encoded in utf8. + + std::string horizontalAlignment; ///< The horizontal alignment: one of {"begin", "center", "end"}. + std::string verticalAlignment; ///< The vertical alignment: one of {"top", "center", "bottom"}. + + std::string fontFamily; ///< The font's family. + std::string fontWeight; ///< The font's weight: one of {"thin", "ultraLight", "extraLight", "light", "demiLight", "semiLight", "book", "normal", "regular", "medium", "demiBold", "semiBold", "bold", "ultraBold", "extraBold", "black", "heavy", "extraBlack"}. + std::string fontWidth; ///< The font's width: one of {"ultraCondensed", "extraCondensed", "condensed", "semiCondensed", "normal", "semiExpanded", "expanded", "extraExpanded", "ultraExpanded"}. + std::string fontSlant; ///< The font's slant. one of {"normal", "roman", "italic", "oblique"} + std::string layout; ///< The type of layout: one of {"singleLine", "multiLine", "circular"} + std::string circularAlignment; ///< The text alignment within the arc: one of {"begin", "center", "end"}. The @p horizontalAlignment and @p verticalAlignment can be used to align the text within the text area. + + Vector4 textColor; ///< The default text's color. Default is white. + + float fontSize; ///< The font's size (in points). + + unsigned int textWidth; ///< The width in pixels of the boundaries where the text is going to be laid-out. + unsigned int textHeight; ///< The height in pixels of the boundaries where the text is going to be laid-out. + + unsigned int radius; ///< The radius in pixels of the circular text. + float beginAngle; ///< The begin angle in degrees of the text area on the circle. The top of the circle is 0°, the right side 90°, the bottom 180° and the left 270°. + float incrementAngle; ///< The increment angle in degrees of the text area on the circle. The @p incrementAngle defines a direction. If positive, the text will be laid out clockwise. + + bool ellipsisEnabled:1; ///< Whether the ellipsis layout option is enabled. + bool markupEnabled:1; ///< Whether the mark-up processor is enabled. + bool isTextColorSet:1; ///< Whether a default color has been set. +}; + +/** + * @brief Struct with info of the embedded items layout. + */ +struct DALI_TOOLKIT_API EmbeddedItemInfo +{ + TextAbstraction::CharacterIndex characterIndex; ///< Index to the character within the string. + TextAbstraction::GlyphIndex glyphIndex; ///< Index to the glyph + Vector2 position; ///< The layout position within the buffer (top, left corner). + Size size; ///< The size within the buffer of the embedded item. + Size rotatedSize; ///< The rotated size within the buffer of the embedded item. + Degree angle; ///< Rotation angle of the pixel buffer in degrees. + TextAbstraction::ColorBlendingMode colorBlendingMode; ///< Whether the color of the image is multiplied by the color of the text. +}; + +/** +* @brief Struct with the parameters needed to build a shadow for the given pixel buffer. +*/ +struct DALI_TOOLKIT_API ShadowParameters +{ + Devel::PixelBuffer input; ///< The input pixel buffer used to create the shadow. + Vector4 textColor; ///< The color of the text. + Vector4 color; ///< The color of the shadow. + Vector2 offset; ///< The offset of the shadow. + bool blendShadow; ///< Whether to blend the shadow. +}; + +/** + * @brief Renders text into a pixel buffer. + * + * @note: Can process a mark-up string. + * @note: It does the font selection, RTL reordering, shaping and layouting. + * @note: The width of the pixel buffer may be different to the given @e textWidth + * due to some padding pixels added. + * + * The text is laid-out for the given size @e (textWidth,textHeight). + * If the @e multiLineEnabled option is enabled, the text will wrap in lines. + * If the @e ellipsisEnabled option is enabled, the text will be ellided if + * there is no more space for new lines. + * + * It won't be rendered the parts of the text exceeding the boundaries of + * the given width and height. + * + * If the given @e textHeight is zero, a big enough pixel buffer will be created + * to render the full text. + * + * If the given @e textWidth is zero, the 'natural size' of the text will be + * used to create the pixel buffer to render the full text. + * + * If the radius is not zero, the text will be laid-out following a circular path. + * In that case the text is laid-out in a single line. + * + * If the mark-up string contains embedded items, the @p embeddedItemLayout vector + * contains the layout info of each embedded item. + * + * @param[in] textParameters The text and style options. + * @param[out] embeddedItemLayout The layout info of the embedded items. + * + * @return A pixel buffer with the text rendered on it. + */ +DALI_TOOLKIT_API Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout ); + +/** + * @brief Creates a shadow for the text given in the input pixel buffer. + * + * The function returns a RGBA8888 pixel buffer with the text and its shadow rendered on it. + * + * The pixel format of the @e input pixel buffer could be an A8 or an RGBA8888. If it's + * an A8 pixel buffer, it uses the given @e textColor to give color to the text. Otherwise + * it uses the color of the @e input pixel buffer. + * + * @param[in] shadowParameters The parameters needed to create the text's shadow. + * + * @return A pixel buffer with the text and the shadow rendered on it. + */ +DALI_TOOLKIT_API Devel::PixelBuffer CreateShadow(const ShadowParameters& shadowParameters); + +/** + * @brief Converts a @p pixelBuffer with pixel format A8 to RGBA8888 using the given @p color. + * + * @note Does nothing if the @p pixelBuffer is not A8. + * + * @param[in] pixelBuffer The pixel buffer with pixel format A8 + * @param[in] color The color used to convert to RGBA8888 + * @param[in] multiplyByAlpha Whether to multiply the @p color with the alpha value of the @p pixel @p buffer. + * + * @return The pixel buffer converted to RGBA8888. + */ +DALI_TOOLKIT_API Devel::PixelBuffer ConvertToRgba8888( Devel::PixelBuffer pixelBuffer, const Vector4& color, bool multiplyByAlpha ); + +/** +* @brief Updates the @p dst pixel buffer with the data from @p src pixel buffer. +* +* @note Both pixel buffers must have the same pixel format. Does nothing if both pixel format are different. +* @note The function does nothing if the @p src pixel buffer doesn't fit into the @p dst pixel buffer. +* +* The @p src pixel buffer could be blended with the @p dst pixel buffer if @p blend is set to @e true. +* +* @param[in] src The pixel buffer from where the data is read. +* @param[in] dst The pixel buffer where the data is written.. +* @param[in] x The top left corner's X within the destination pixel buffer. +* @param[in] y The top left corner's y within the destination pixel buffer. +* @param[in] blend Whether to blend the source pixel buffer with the destination pixel buffer as background. +*/ +DALI_TOOLKIT_API void UpdateBuffer( Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend); + +} // namespace DevelText + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_UTILS_DEVEL_H diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 3a0375e..be6c728 100755 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -135,6 +135,7 @@ toolkit_src_files = \ $(toolkit_src_dir)/text/logical-model-impl.cpp \ $(toolkit_src_dir)/text/markup-processor.cpp \ $(toolkit_src_dir)/text/markup-processor-color.cpp \ + $(toolkit_src_dir)/text/markup-processor-embedded-item.cpp \ $(toolkit_src_dir)/text/markup-processor-font.cpp \ $(toolkit_src_dir)/text/markup-processor-helper-functions.cpp \ $(toolkit_src_dir)/text/multi-language-support.cpp \ diff --git a/dali-toolkit/internal/text/embedded-item.h b/dali-toolkit/internal/text/embedded-item.h new file mode 100755 index 0000000..496c207 --- /dev/null +++ b/dali-toolkit/internal/text/embedded-item.h @@ -0,0 +1,60 @@ +#ifndef DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H +#define DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief An embedded item within the text. + * + * The @e url of the image is optional. If there is no image + * the layout engine will use the @e width and @e height to + * create a space inside the text. This gap can be filled later. + * + * A color blending mode can be set. The default is NONE, the + * image will use its own color. If MULTIPLY is set, the color + * of the image will be multiplied by the color of the text. + */ +struct EmbeddedItem +{ + CharacterIndex characterIndex; ///< The character's index of the embedded item within the string. + char* url; ///< The url path of the image. + Length urlLength; ///< The length of the url. + unsigned int width; ///< The width of the item. + unsigned int height; ///< The height of the item. + ColorBlendingMode colorBlendingMode; ///< Whether the color of the image is multiplied by the color of the text. +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_EMBEDDED_ITEM_H diff --git a/dali-toolkit/internal/text/font-run.h b/dali-toolkit/internal/text/font-run.h index a787558..8190fcd 100644 --- a/dali-toolkit/internal/text/font-run.h +++ b/dali-toolkit/internal/text/font-run.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_FONT_RUN_H__ -#define __DALI_TOOLKIT_TEXT_FONT_RUN_H__ +#ifndef DALI_TOOLKIT_TEXT_FONT_RUN_H +#define DALI_TOOLKIT_TEXT_FONT_RUN_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -18,9 +18,6 @@ * */ -// EXTERNAL INCLUDES -#include - // INTERNAL INCLUDES #include @@ -38,10 +35,10 @@ namespace Text */ struct FontRun { - CharacterRun characterRun; ///< The initial character index and the number of characters of the run. - FontId fontId; ///< Font id of the run. - bool softwareItalic:1; ///< Whether font needs software support to draw italic style - bool softwareBold:1; ///< Whether font needs software support to draw bold style + CharacterRun characterRun; ///< The initial character index and the number of characters of the run. + FontId fontId; ///< Font id of the run. + bool isItalicRequired:1; ///< Whether the italic style is required. + bool isBoldRequired:1; ///< Whether the bold style is required. }; } // namespace Text @@ -50,4 +47,4 @@ struct FontRun } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_FONT_RUN_H__ +#endif // DALI_TOOLKIT_TEXT_FONT_RUN_H diff --git a/dali-toolkit/internal/text/glyph-metrics-helper.cpp b/dali-toolkit/internal/text/glyph-metrics-helper.cpp old mode 100644 new mode 100755 index 9c7c8ec..ef9098c --- a/dali-toolkit/internal/text/glyph-metrics-helper.cpp +++ b/dali-toolkit/internal/text/glyph-metrics-helper.cpp @@ -58,21 +58,41 @@ void GetGlyphsMetrics( GlyphIndex glyphIndex, const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex ); Text::FontMetrics fontMetrics; - metrics->GetFontMetrics( firstGlyph.fontId, fontMetrics ); + if( 0u != firstGlyph.fontId ) + { + metrics->GetFontMetrics( firstGlyph.fontId, fontMetrics ); + } + else if( 0u != firstGlyph.index ) + { + // It may be an embedded image. + fontMetrics.ascender = firstGlyph.height; + fontMetrics.descender = 0.f; + fontMetrics.height = fontMetrics.ascender; + } + + const bool isItalicFont = metrics->HasItalicStyle( firstGlyph.fontId ); glyphMetrics.fontId = firstGlyph.fontId; glyphMetrics.fontHeight = fontMetrics.height; - glyphMetrics.width = firstGlyph.width; + glyphMetrics.width = firstGlyph.width + ( ( firstGlyph.isItalicRequired && !isItalicFont ) ? static_cast( TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * static_cast( firstGlyph.height ) ) : 0u ); glyphMetrics.advance = firstGlyph.advance; glyphMetrics.ascender = fontMetrics.ascender; glyphMetrics.xBearing = firstGlyph.xBearing; - for( unsigned int i = 1u; i < numberOfGlyphs; ++i ) + if( 1u < numberOfGlyphs ) { - const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i ); + const float widthInit = firstGlyph.xBearing; + + for( unsigned int i = 1u; i < numberOfGlyphs; ++i ) + { + const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i ); + + glyphMetrics.width = glyphMetrics.advance + glyphInfo.xBearing + glyphInfo.width + ( ( firstGlyph.isItalicRequired && !isItalicFont ) ? static_cast( TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE * static_cast( firstGlyph.height ) ) : 0u ); + glyphMetrics.advance += glyphInfo.advance; + + } - glyphMetrics.advance += glyphInfo.advance; - glyphMetrics.width += glyphInfo.width; + glyphMetrics.width -= widthInit; } } diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index f97a8ea..5594c01 100755 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -117,26 +117,31 @@ struct Engine::Impl /** * @brief Updates the line ascender and descender with the metrics of a new font. * - * @param[in] fontId The id of the new font. + * @param[in] glyphMetrics The metrics of the new font. * @param[in,out] lineLayout The line layout. */ - void UpdateLineHeight( FontId fontId, LineLayout& lineLayout ) + void UpdateLineHeight( const GlyphMetrics& glyphMetrics, LineLayout& lineLayout ) { Text::FontMetrics fontMetrics; - mMetrics->GetFontMetrics( fontId, fontMetrics ); - - // Sets the maximum ascender. - if( fontMetrics.ascender > lineLayout.ascender ) + if( 0u != glyphMetrics.fontId ) { - lineLayout.ascender = fontMetrics.ascender; + mMetrics->GetFontMetrics( glyphMetrics.fontId, fontMetrics ); } - - // Sets the minimum descender. - if( fontMetrics.descender < lineLayout.descender ) + else { - lineLayout.descender = fontMetrics.descender; + fontMetrics.ascender = glyphMetrics.fontHeight; + fontMetrics.descender = 0.f; + fontMetrics.height = fontMetrics.ascender; + fontMetrics.underlinePosition = 0.f; + fontMetrics.underlineThickness = 1.f; } + // Sets the maximum ascender. + lineLayout.ascender = std::max( lineLayout.ascender, fontMetrics.ascender ); + + // Sets the minimum descender. + lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender ); + // set the line spacing lineLayout.lineSpacing = mDefaultLineSpacing; } @@ -158,22 +163,18 @@ struct Engine::Impl { lineLayout.length += lineLayout.wsLengthEndOfLine; - lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine; + lineLayout.wsLengthEndOfLine = tmpLineLayout.wsLengthEndOfLine; } else { lineLayout.wsLengthEndOfLine += tmpLineLayout.wsLengthEndOfLine; } - if( tmpLineLayout.ascender > lineLayout.ascender ) - { - lineLayout.ascender = tmpLineLayout.ascender; - } + // Sets the maximum ascender. + lineLayout.ascender = std::max( lineLayout.ascender, tmpLineLayout.ascender ); - if( tmpLineLayout.descender < lineLayout.descender ) - { - lineLayout.descender = tmpLineLayout.descender; - } + // Sets the minimum descender. + lineLayout.descender = std::min( lineLayout.descender, tmpLineLayout.descender ); } /** @@ -239,7 +240,7 @@ struct Engine::Impl // Calculate the line height if there is no characters. FontId lastFontId = glyphMetrics.fontId; - UpdateLineHeight( lastFontId, tmpLineLayout ); + UpdateLineHeight( glyphMetrics, tmpLineLayout ); bool oneWordLaidOut = false; @@ -266,7 +267,7 @@ struct Engine::Impl // If it's different the ascender and descender need to be updated. if( lastFontId != glyphMetrics.fontId ) { - UpdateLineHeight( glyphMetrics.fontId, tmpLineLayout ); + UpdateLineHeight( glyphMetrics, tmpLineLayout ); lastFontId = glyphMetrics.fontId; } @@ -572,7 +573,7 @@ struct Engine::Impl const bool ellipsis = isAutoScrollEnabled ? ( penY - layout.descender > layoutParameters.boundingBox.height ) : ( ( penY - layout.descender > layoutParameters.boundingBox.height ) || ( ( mLayout == SINGLE_LINE_BOX ) && - ( layout.extraBearing + layout.length + layout.extraWidth > layoutParameters.boundingBox.width ) ) ); + ( layout.length > layoutParameters.boundingBox.width ) ) ); if( ellipsis ) { @@ -613,7 +614,7 @@ struct Engine::Impl lineRun->characterRun.characterIndex = ellipsisLayout.characterIndex; lineRun->characterRun.numberOfCharacters = ellipsisLayout.numberOfCharacters; lineRun->width = ellipsisLayout.length; - lineRun->extraLength = ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f; + lineRun->extraLength = std::ceil( ( ellipsisLayout.wsLengthEndOfLine > 0.f ) ? ellipsisLayout.wsLengthEndOfLine - ellipsisLayout.extraWidth : 0.f ); lineRun->ascender = ellipsisLayout.ascender; lineRun->descender = ellipsisLayout.descender; lineRun->direction = !RTL; @@ -679,8 +680,12 @@ struct Engine::Impl else { lineRun.width = layout.extraBearing + layout.length + layout.extraWidth; - lineRun.extraLength = ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f; + lineRun.extraLength = std::ceil( ( layout.wsLengthEndOfLine > 0.f ) ? layout.wsLengthEndOfLine - layout.extraWidth : 0.f ); } + + // Rounds upward to avoid a non integer size. + lineRun.width = std::ceil( lineRun.width ); + lineRun.ascender = layout.ascender; lineRun.descender = layout.descender; lineRun.direction = !RTL; @@ -716,7 +721,10 @@ struct Engine::Impl const GlyphInfo& glyphInfo = *( layoutParameters.glyphsBuffer + layoutParameters.totalNumberOfGlyphs - 1u ); Text::FontMetrics fontMetrics; - mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics ); + if( 0u != glyphInfo.fontId ) + { + mMetrics->GetFontMetrics( glyphInfo.fontId, fontMetrics ); + } LineRun& lineRun = *( linesBuffer + numberOfLines ); ++numberOfLines; @@ -832,6 +840,9 @@ struct Engine::Impl UpdateLayoutSize( lines, layoutSize ); + // Rounds upward to avoid a non integer size. + layoutSize.height = std::ceil( layoutSize.height ); + // Nothing else do if there are no glyphs to layout. return false; } @@ -910,6 +921,10 @@ struct Engine::Impl DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText width too small!\n\n" ); lines.Resize( numberOfLines ); + + // Rounds upward to avoid a non integer size. + layoutSize.height = std::ceil( layoutSize.height ); + return false; } @@ -1041,6 +1056,9 @@ struct Engine::Impl lines.Resize( numberOfLines ); } + // Rounds upward to avoid a non integer size. + layoutSize.height = std::ceil( layoutSize.height ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--LayoutText\n\n" ); return true; diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp old mode 100644 new mode 100755 index 9b66925..6fbabb1 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -44,6 +44,20 @@ void FreeFontFamilyNames( Vector& fontDescriptionRuns ) fontDescriptionRuns.Clear(); } +void FreeEmbeddedItems( Vector& embeddedItem ) +{ + for( Vector::Iterator it = embeddedItem.Begin(), + endIt = embeddedItem.End(); + it != endIt; + ++it ) + { + EmbeddedItem& item = *it; + delete[] item.url; + } + + embeddedItem.Clear(); +} + LogicalModelPtr LogicalModel::New() { return LogicalModelPtr( new LogicalModel() ); @@ -550,9 +564,15 @@ void LogicalModel::FindParagraphs( CharacterIndex index, } } +void LogicalModel::ClearEmbeddedImages() +{ + FreeEmbeddedItems( mEmbeddedItems ); +} + LogicalModel::~LogicalModel() { ClearFontDescriptionRuns(); + ClearEmbeddedImages(); } LogicalModel::LogicalModel() diff --git a/dali-toolkit/internal/text/logical-model-impl.h b/dali-toolkit/internal/text/logical-model-impl.h old mode 100644 new mode 100755 index 9f2fa31..b2fc5a1 --- a/dali-toolkit/internal/text/logical-model-impl.h +++ b/dali-toolkit/internal/text/logical-model-impl.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H__ -#define __DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H__ +#ifndef DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H +#define DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,13 @@ public: Length numberOfCharacters, Vector& paragraphs ); + // Embedded images + + /** + * @brief Clears the embedded images. + */ + void ClearEmbeddedImages(); + protected: /** @@ -210,6 +218,7 @@ public: Vector mBidirectionalParagraphInfo; Vector mCharacterDirections; ///< For each character, whether is right to left. ( @e flase is left to right, @e true right to left ). Vector mBidirectionalLineInfo; + Vector mEmbeddedItems; BidirectionalLineRunIndex mBidirectionalLineIndex; ///< The last fetched bidirectional line info. }; @@ -220,4 +229,4 @@ public: } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H__ +#endif // DALI_TOOLKIT_TEXT_LOGICAL_MODEL_IMPL_H diff --git a/dali-toolkit/internal/text/markup-processor-embedded-item.cpp b/dali-toolkit/internal/text/markup-processor-embedded-item.cpp new file mode 100755 index 0000000..7751c01 --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-embedded-item.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +namespace +{ +const std::string XHTML_URL_ATTRIBUTE("url"); +const std::string XHTML_WIDTH_ATTRIBUTE("width"); +const std::string XHTML_HEIGHT_ATTRIBUTE("height"); +const std::string XHTML_COLOR_BLENDING_ATTRIBUTE("color-blending"); + +const std::string NONE("none"); +const std::string MULTIPLY("multiply"); +} + +void ProcessEmbeddedItem( const Tag& tag, EmbeddedItem& embeddedItem ) +{ + embeddedItem.url = nullptr; + embeddedItem.urlLength = 0u; + embeddedItem.width = 0u; + embeddedItem.height = 0u; + embeddedItem.colorBlendingMode = ColorBlendingMode::NONE; + + for( Vector::ConstIterator it = tag.attributes.Begin(), + endIt = tag.attributes.End(); + it != endIt; + ++it ) + { + const Attribute& attribute( *it ); + if( TokenComparison(XHTML_URL_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) ) + { + embeddedItem.urlLength = attribute.valueLength; + embeddedItem.url = new char[embeddedItem.urlLength]; + memcpy(embeddedItem.url, attribute.valueBuffer, embeddedItem.urlLength); + // The memory is freed when the font run is removed from the logical model. + } + else if (TokenComparison(XHTML_WIDTH_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength)) + { + embeddedItem.width = StringToUint(attribute.valueBuffer); + } + else if (TokenComparison(XHTML_HEIGHT_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength)) + { + embeddedItem.height = StringToUint(attribute.valueBuffer); + } + else if (TokenComparison(XHTML_COLOR_BLENDING_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength)) + { + if (TokenComparison(MULTIPLY, attribute.valueBuffer, attribute.valueLength)) + { + embeddedItem.colorBlendingMode = ColorBlendingMode::MULTIPLY; + } + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/markup-processor-embedded-item.h b/dali-toolkit/internal/text/markup-processor-embedded-item.h new file mode 100755 index 0000000..6333c35 --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-embedded-item.h @@ -0,0 +1,47 @@ +#ifndef DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H +#define DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H + +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Tag; +struct EmbeddedItem; + +/** + * @brief Retrieves the @e embedded @e item from the @p tag. + * + * @param[in] tag The embedded item tag and its attributes. + * @param[in,out] embeddedItem The embedded item. + */ +void ProcessEmbeddedItem( const Tag& tag, EmbeddedItem& embeddedItem ); + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_EMBEDDED_ITEM_H diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp old mode 100644 new mode 100755 index 76d9a6a..6c133ae --- a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp @@ -92,6 +92,11 @@ void JumpToWhiteSpace( const char*& stringBuffer, for( ; ( WHITE_SPACE != *stringBuffer ) && ( stringBuffer < stringEndBuffer ); ++stringBuffer ); } +unsigned int StringToUint( const char* const uintStr ) +{ + return static_cast( strtoul( uintStr, NULL, 10 ) ); +} + unsigned int StringToHex( const char* const uintStr ) { return static_cast( strtoul( uintStr, NULL, 16 ) ); diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.h b/dali-toolkit/internal/text/markup-processor-helper-functions.h old mode 100644 new mode 100755 index d1ecbc8..2b0cafb --- a/dali-toolkit/internal/text/markup-processor-helper-functions.h +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.h @@ -95,6 +95,15 @@ void JumpToWhiteSpace( const char*& stringBuffer, const char* const stringEndBuffer ); /** +* @brief Converts a string into an unsigned int. +* +* @param[in] uintStr An unsigned int packed inside a string. +* +* @return The unsigned int value. +*/ +unsigned int StringToUint( const char* const uintStr ); + +/** * @brief Converts a string into an hexadecimal unsigned int. * * @param[in] uintStr An hexadecimal unsigned int packed inside a string. diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index 25b4616..4565b9d 100755 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -25,12 +25,11 @@ // INTERNAL INCLUDES #include #include +#include #include #include #include - - namespace Dali { @@ -53,6 +52,7 @@ const std::string XHTML_U_TAG("u"); const std::string XHTML_SHADOW_TAG("shadow"); const std::string XHTML_GLOW_TAG("glow"); const std::string XHTML_OUTLINE_TAG("outline"); +const std::string XHTML_ITEM_TAG("item"); const char LESS_THAN = '<'; const char GREATER_THAN = '>'; @@ -66,7 +66,7 @@ const char SEMI_COLON = ';'; const char CHAR_ARRAY_END = '\0'; const char HEX_CODE = 'x'; -const char WHITE_SPACE = 0x20; // ASCII value of the white space. +const char WHITE_SPACE = 0x20; // ASCII value of the white space. // Range 1 0x0u < XHTML_DECIMAL_ENTITY_RANGE <= 0xD7FFu // Range 2 0xE000u < XHTML_DECIMAL_ENTITY_RANGE <= 0xFFFDu @@ -310,12 +310,15 @@ bool IsTag( const char*& markupStringBuffer, bool isQuotationOpen = false; bool attributesFound = false; tag.isEndTag = false; + bool isPreviousLessThan = false; + bool isPreviousSlash = false; const char character = *markupStringBuffer; if( LESS_THAN == character ) // '<' { tag.buffer = NULL; tag.length = 0u; + isPreviousLessThan = true; // if the iterator is pointing to a '<' character, then check if it's a mark-up tag is needed. ++markupStringBuffer; @@ -327,12 +330,20 @@ bool IsTag( const char*& markupStringBuffer, { const char character = *markupStringBuffer; - if( SLASH == character ) // '/' + if( !isQuotationOpen && ( SLASH == character ) ) // '/' { - // if the tag has a '/' then it's an end or empty tag. - tag.isEndTag = true; + if (isPreviousLessThan) + { + tag.isEndTag = true; + } + else + { + // if the tag has a '/' it may be an end tag. + isPreviousSlash = true; + } - if( ( markupStringBuffer + 1u < markupStringEndBuffer ) && ( WHITE_SPACE >= *( markupStringBuffer + 1u ) ) && ( !isQuotationOpen ) ) + isPreviousLessThan = false; + if( ( markupStringBuffer + 1u < markupStringEndBuffer ) && ( WHITE_SPACE >= *( markupStringBuffer + 1u ) ) ) { ++markupStringBuffer; SkipWhiteSpace( markupStringBuffer, markupStringEndBuffer ); @@ -342,11 +353,21 @@ bool IsTag( const char*& markupStringBuffer, else if( GREATER_THAN == character ) // '>' { isTag = true; + if (isPreviousSlash) + { + tag.isEndTag = true; + } + + isPreviousSlash = false; + isPreviousLessThan = false; } else if( QUOTATION_MARK == character ) { isQuotationOpen = !isQuotationOpen; ++tag.length; + + isPreviousSlash = false; + isPreviousLessThan = false; } else if( WHITE_SPACE >= character ) // ' ' { @@ -366,6 +387,9 @@ bool IsTag( const char*& markupStringBuffer, // If it's not any of the 'special' characters then just add it to the tag string. ++tag.length; + + isPreviousSlash = false; + isPreviousLessThan = false; } } } @@ -466,6 +490,8 @@ bool XHTMLNumericEntityToUtf8 ( const char* markupText, char* utf8 ) void ProcessMarkupString( const std::string& markupString, MarkupProcessData& markupProcessData ) { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "markupString: %s\n", markupString.c_str() ); + // Reserve space for the plain text. const Length markupStringSize = markupString.size(); markupProcessData.markupProcessedText.reserve( markupStringSize ); @@ -489,6 +515,7 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma CharacterIndex characterIndex = 0u; for( ; markupStringBuffer < markupStringEndBuffer; ) { + tag.attributes.Clear(); if( IsTag( markupStringBuffer, markupStringEndBuffer, tag ) ) @@ -654,6 +681,22 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma // Pop the top of the stack and set the number of characters of the run. } } // + else if (TokenComparison(XHTML_ITEM_TAG, tag.buffer, tag.length)) + { + if (tag.isEndTag) + { + // Create an embedded item instance. + EmbeddedItem item; + item.characterIndex = characterIndex; + ProcessEmbeddedItem(tag, item); + + markupProcessData.items.PushBack(item); + + // Insert white space character that will be replaced by the item. + markupProcessData.markupProcessedText.append( 1u, WHITE_SPACE ); + ++characterIndex; + } + } } // end if( IsTag() ) else if( markupStringBuffer < markupStringEndBuffer ) { @@ -753,6 +796,14 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma else { markupProcessData.colorRuns.Resize( colorRunIndex ); + +#ifdef DEBUG_ENABLED + for( unsigned int i=0; i +#include #include namespace Dali @@ -41,15 +42,17 @@ namespace Text struct MarkupProcessData { MarkupProcessData( Vector& colorRuns, - Vector& fontRuns ) + Vector& fontRuns, + Vector& items ) : colorRuns( colorRuns ), fontRuns( fontRuns ), + items(items), markupProcessedText() {} Vector& colorRuns; ///< The color runs. Vector& fontRuns; ///< The font description runs. - + Vector& items; ///< The embedded items. std::string markupProcessedText; ///< The mark-up string. }; @@ -67,4 +70,4 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H__ +#endif // DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_H diff --git a/dali-toolkit/internal/text/metrics.h b/dali-toolkit/internal/text/metrics.h old mode 100644 new mode 100755 index ad4ed41..868dba3 --- a/dali-toolkit/internal/text/metrics.h +++ b/dali-toolkit/internal/text/metrics.h @@ -87,6 +87,18 @@ public: return mFontClient.GetGlyphMetrics( array, size, mGlyphType, true ); // inline for performance } + /** + * @brief Whether the font has Italic style. + * + * @param[in] fontId The font identifier. + * + * @return true if the font has italic style. + */ + bool HasItalicStyle( FontId fontId ) const + { + return mFontClient.HasItalicStyle( fontId ); + } + protected: /** diff --git a/dali-toolkit/internal/text/multi-language-support-impl.cpp b/dali-toolkit/internal/text/multi-language-support-impl.cpp index 607d159..81d815c 100755 --- a/dali-toolkit/internal/text/multi-language-support-impl.cpp +++ b/dali-toolkit/internal/text/multi-language-support-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -435,6 +435,8 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, currentFontRun.characterRun.characterIndex = startIndex; currentFontRun.characterRun.numberOfCharacters = 0u; currentFontRun.fontId = 0u; + currentFontRun.isBoldRequired = false; + currentFontRun.isItalicRequired = false; // Get the font client. TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); @@ -448,16 +450,13 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, bool isPreviousEmojiScript = false; - // Description of fallback font which is selected at current iteration. - TextAbstraction::FontDescription selectedFontDescription; - CharacterIndex lastCharacter = startIndex + numberOfCharacters; for( Length index = startIndex; index < lastCharacter; ++index ) { // Get the current character. const Character character = *( textBuffer + index ); - bool needSoftwareBoldening = false; - bool needSoftwareItalic = false; + bool isItalicRequired = false; + bool isBoldRequired = false; // new description for current character TextAbstraction::FontDescription currentFontDescription; @@ -536,6 +535,8 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters; currentFontRun.characterRun.numberOfCharacters = 0u; currentFontRun.fontId = fontId; + currentFontRun.isItalicRequired = false; + currentFontRun.isBoldRequired = false; } // If the given font is not valid, it means either: @@ -676,22 +677,17 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, } #endif - if( fontId != currentFontRun.fontId ) - { - fontClient.GetDescription(fontId,selectedFontDescription); - } - - // Developer sets bold to character but selected font cannot support it - needSoftwareBoldening = ( currentFontDescription.weight >= TextAbstraction::FontWeight::BOLD ) && ( selectedFontDescription.weight < TextAbstraction::FontWeight::BOLD ); + // Whether bols style is required. + isBoldRequired = ( currentFontDescription.weight >= TextAbstraction::FontWeight::BOLD ); - // Developer sets italic to character but selected font cannot support it - needSoftwareItalic = ( currentFontDescription.slant == TextAbstraction::FontSlant::ITALIC ) && ( selectedFontDescription.slant < TextAbstraction::FontSlant::ITALIC ); + // Whether italic style is required. + isItalicRequired = ( currentFontDescription.slant >= TextAbstraction::FontSlant::ITALIC ); // The font is now validated. if( ( fontId != currentFontRun.fontId ) || isNewParagraphCharacter || // If font id is same as previous but style is diffrent, initialize new one - ( ( fontId == currentFontRun.fontId ) && ( ( needSoftwareBoldening != currentFontRun.softwareBold ) || ( needSoftwareItalic != currentFontRun.softwareItalic ) ) ) ) + ( ( fontId == currentFontRun.fontId ) && ( ( isBoldRequired != currentFontRun.isBoldRequired ) || ( isItalicRequired != currentFontRun.isItalicRequired ) ) ) ) { // Current run needs to be stored and a new one initialized. @@ -706,8 +702,8 @@ void MultilanguageSupport::ValidateFonts( const Vector& text, currentFontRun.characterRun.characterIndex = currentFontRun.characterRun.characterIndex + currentFontRun.characterRun.numberOfCharacters; currentFontRun.characterRun.numberOfCharacters = 0u; currentFontRun.fontId = fontId; - currentFontRun.softwareItalic = needSoftwareItalic; - currentFontRun.softwareBold = needSoftwareBoldening; + currentFontRun.isBoldRequired = isBoldRequired; + currentFontRun.isItalicRequired = isItalicRequired; } // Add one more character to the run. diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp index 957fd8e..3fd324d 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -44,7 +44,7 @@ AtlasGlyphManager::AtlasGlyphManager() } void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, - const uint32_t outlineWidth, + const Toolkit::AtlasGlyphManager::GlyphStyle& style, const PixelData& bitmap, Dali::Toolkit::AtlasManager::AtlasSlot& slot ) { @@ -63,9 +63,11 @@ void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, GlyphRecordEntry record; record.mIndex = glyph.index; - record.mOutlineWidth = outlineWidth; record.mImageId = slot.mImageId; record.mCount = 1; + record.mOutlineWidth = style.outline; + record.isItalic = style.isItalic; + record.isBold = style.isBold; // Have glyph records been created for this fontId ? bool foundGlyph = false; @@ -99,9 +101,9 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, } bool AtlasGlyphManager::IsCached( Text::FontId fontId, - Text::GlyphIndex index, - uint32_t outlineWidth, - Dali::Toolkit::AtlasManager::AtlasSlot& slot ) + Text::GlyphIndex index, + const Toolkit::AtlasGlyphManager::GlyphStyle& style, + Dali::Toolkit::AtlasManager::AtlasSlot& slot ) { for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin(); fontGlyphRecordIt != mFontGlyphRecords.end(); @@ -113,7 +115,10 @@ bool AtlasGlyphManager::IsCached( Text::FontId fontId, glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End(); ++glyphRecordIt ) { - if ( glyphRecordIt->mIndex == index && glyphRecordIt->mOutlineWidth == outlineWidth ) + if ( ( glyphRecordIt->mIndex == index ) && + ( glyphRecordIt->mOutlineWidth == style.outline ) && + ( glyphRecordIt->isItalic == style.isItalic ) && + ( glyphRecordIt->isBold == style.isBold ) ) { slot.mImageId = glyphRecordIt->mImageId; slot.mAtlasId = mAtlasManager.GetAtlas( slot.mImageId ); @@ -174,7 +179,7 @@ const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics() return mMetrics; } -void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, uint32_t outlineWidth, int32_t delta ) +void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const Toolkit::AtlasGlyphManager::GlyphStyle& style, int32_t delta ) { if( 0 != delta ) { @@ -190,7 +195,10 @@ void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIn glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End(); ++glyphRecordIt ) { - if ( glyphRecordIt->mIndex == index && glyphRecordIt->mOutlineWidth == outlineWidth ) + if ( ( glyphRecordIt->mIndex == index ) && + ( glyphRecordIt->mOutlineWidth == style.outline ) && + ( glyphRecordIt->isItalic == style.isItalic ) && + ( glyphRecordIt->isBold == style.isBold ) ) { glyphRecordIt->mCount += delta; DALI_ASSERT_DEBUG( glyphRecordIt->mCount >= 0 && "Glyph ref-count should not be negative" ); diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h index 0d32834..3d2613e 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager-impl.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__ -#define __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__ +#ifndef DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H +#define DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -51,9 +51,11 @@ public: struct GlyphRecordEntry { Text::GlyphIndex mIndex; - uint32_t mOutlineWidth; uint32_t mImageId; int32_t mCount; + uint16_t mOutlineWidth; + bool isItalic:1; + bool isBold:1; }; struct FontGlyphRecord @@ -71,7 +73,7 @@ public: * @copydoc Toolkit::AtlasGlyphManager::Add */ void Add( const Text::GlyphInfo& glyph, - const uint32_t outlineWidth, + const Toolkit::AtlasGlyphManager::GlyphStyle& style, const PixelData& bitmap, Dali::Toolkit::AtlasManager::AtlasSlot& slot ); @@ -87,7 +89,7 @@ public: */ bool IsCached( Text::FontId fontId, Text::GlyphIndex index, - uint32_t outlineWidth, + const Toolkit::AtlasGlyphManager::GlyphStyle& style, Dali::Toolkit::AtlasManager::AtlasSlot& slot ); /** @@ -108,7 +110,7 @@ public: /** * @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount */ - void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, uint32_t outlineWidth, int32_t delta ); + void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const Toolkit::AtlasGlyphManager::GlyphStyle& style, int32_t delta ); /** * @copydoc Toolkit::AtlasGlyphManager::GetTextures @@ -158,4 +160,4 @@ inline Internal::AtlasGlyphManager& GetImplementation(Toolkit::AtlasGlyphManager } // namespace Dali -#endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H__ +#endif // DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_IMPL_H diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp index bd6850d..357f431 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -69,11 +69,11 @@ AtlasGlyphManager::AtlasGlyphManager(Internal::AtlasGlyphManager *impl) } void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph, - const uint32_t outlineWidth, + const GlyphStyle& style, const PixelData& bitmap, AtlasManager::AtlasSlot& slot ) { - GetImplementation(*this).Add( glyph, outlineWidth, bitmap, slot ); + GetImplementation(*this).Add( glyph, style, bitmap, slot ); } void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, @@ -87,10 +87,10 @@ void AtlasGlyphManager::GenerateMeshData( uint32_t imageId, bool AtlasGlyphManager::IsCached( Text::FontId fontId, Text::GlyphIndex index, - uint32_t outlineWidth, + const GlyphStyle& style, AtlasManager::AtlasSlot& slot ) { - return GetImplementation(*this).IsCached( fontId, index, outlineWidth, slot ); + return GetImplementation(*this).IsCached( fontId, index, style, slot ); } void AtlasGlyphManager::SetNewAtlasSize( uint32_t width, uint32_t height, uint32_t blockWidth, uint32_t blockHeight ) @@ -118,9 +118,9 @@ const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics() return GetImplementation(*this).GetMetrics(); } -void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, uint32_t outlineWidth, int32_t delta ) +void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const GlyphStyle& style, int32_t delta ) { - GetImplementation(*this).AdjustReferenceCount( fontId, index, outlineWidth, delta ); + GetImplementation(*this).AdjustReferenceCount( fontId, index, style, delta ); } } // namespace Toolkit diff --git a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h index c41415e..592017b 100644 --- a/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h +++ b/dali-toolkit/internal/text/rendering/atlas/atlas-glyph-manager.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H__ -#define __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H__ +#ifndef DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H +#define DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -55,6 +55,19 @@ public: AtlasManager::Metrics mAtlasMetrics; ///< metrics from the Atlas Manager }; + struct GlyphStyle + { + GlyphStyle() + : outline{ 0u }, + isItalic{ false }, + isBold{ false } + {} + + uint16_t outline; ///< The outline width of this glyph + bool isItalic:1; ///< Whether the glyph is italic. + bool isBold:1; ///< Whether the glyph is bold. + }; + /** * @brief Create a AtlasGlyphManager handle. * @@ -80,12 +93,12 @@ public: * @brief Ask Atlas Manager to add a glyph * * @param[in] glyph glyph to add to an atlas - * @param[in] outlineWidth the outline width of the glyph + * @param[in] style The style of this glyph * @param[in] bitmap bitmap to use for glyph addition * @param[out] slot information returned by atlas manager for addition */ void Add( const Text::GlyphInfo& glyph, - const uint32_t outlineWidth, + const GlyphStyle& style, const PixelData& bitmap, AtlasManager::AtlasSlot& slot ); @@ -105,14 +118,14 @@ public: * * @param[in] fontId The font that this glyph comes from * @param[in] index The GlyphIndex of this glyph - * @param[in] outlineWidth The outline width of this glyph + * @param[in] style The style of this glyph * @param[out] slot container holding information about the glyph( mImage = 0 indicates not being cached ) * * @return Whether glyph is cached or not ? */ bool IsCached( Text::FontId fontId, Text::GlyphIndex index, - uint32_t outlineWidth, + const GlyphStyle& style, AtlasManager::AtlasSlot& slot ); /** @@ -164,10 +177,10 @@ public: * * @param[in] fontId The font this image came from * @param[in] index The index of the glyph - * @param[in] outlineWidth The outline width of the glyph + * @param[in] style The style of this glyph * @param[in] delta The adjustment to make to the reference count */ - void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, uint32_t outlineWidth, int32_t delta ); + void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, const GlyphStyle& style, int32_t delta ); private: @@ -179,4 +192,4 @@ private: } // namespace Dali -#endif // __DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H__ +#endif // DALI_TOOLKIT_ATLAS_GLYPH_MANAGER_H diff --git a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp index e06b958..dddb301 100755 --- a/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp +++ b/dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -93,7 +93,7 @@ const float HALF( 0.5f ); const float ONE( 1.0f ); const uint32_t DEFAULT_ATLAS_WIDTH = 512u; const uint32_t DEFAULT_ATLAS_HEIGHT = 512u; -const uint32_t NO_OUTLINE = 0; +const uint16_t NO_OUTLINE = 0u; } struct AtlasRenderer::Impl @@ -168,17 +168,21 @@ struct AtlasRenderer::Impl struct TextCacheEntry { TextCacheEntry() - : mFontId( 0 ), - mIndex( 0 ), - mOutlineWidth( 0 ), - mImageId( 0 ) + : mFontId{ 0u }, + mIndex{ 0u }, + mImageId{ 0u }, + mOutlineWidth{ 0u }, + isItalic{ false }, + isBold{ false } { } FontId mFontId; Text::GlyphIndex mIndex; - uint32_t mOutlineWidth; uint32_t mImageId; + uint16_t mOutlineWidth; + bool isItalic:1; + bool isBold:1; }; Impl() @@ -211,9 +215,9 @@ struct AtlasRenderer::Impl return false; } - void CacheGlyph( const GlyphInfo& glyph, FontId lastFontId, uint32_t outline, AtlasManager::AtlasSlot& slot ) + void CacheGlyph( const GlyphInfo& glyph, FontId lastFontId, const AtlasGlyphManager::GlyphStyle& style, AtlasManager::AtlasSlot& slot ) { - const bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, outline, slot ); // Check FontGlyphRecord vector for entry with glyph index and fontId + const bool glyphNotCached = !mGlyphManager.IsCached( glyph.fontId, glyph.index, style, slot ); // Check FontGlyphRecord vector for entry with glyph index and fontId DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AddGlyphs fontID[%u] glyphIndex[%u] [%s]\n", glyph.fontId, glyph.index, (glyphNotCached)?"not cached":"cached" ); @@ -243,7 +247,7 @@ struct AtlasRenderer::Impl PixelData bitmap; // Whether the glyph is an outline. - const bool isOutline = 0u != outline; + const bool isOutline = 0u != style.outline; // Whether the current glyph is a color one. const bool isColorGlyph = mFontClient.IsColorGlyph( glyph.fontId, glyph.index ); @@ -257,10 +261,10 @@ struct AtlasRenderer::Impl mFontClient.CreateBitmap( glyph.fontId, glyph.index, - glyph.softwareItalic, - glyph.softwareBold, + glyph.isItalicRequired, + glyph.isBoldRequired, glyphBufferData, - outline ); + style.outline ); // Create the pixel data. bitmap = PixelData::New( glyphBufferData.buffer, @@ -292,21 +296,21 @@ struct AtlasRenderer::Impl blockSize.mNeededBlockHeight ); // Locate a new slot for our glyph - mGlyphManager.Add( glyph, outline, bitmap, slot ); // slot will be 0 is glyph not added + mGlyphManager.Add( glyph, style, bitmap, slot ); // slot will be 0 is glyph not added } } } else { // We have 2+ copies of the same glyph - mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, outline, 1 ); //increment + mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, style, 1 ); //increment } } void GenerateMesh( const GlyphInfo& glyph, const Vector2& position, const Vector4& color, - uint32_t outline, + uint16_t outline, AtlasManager::AtlasSlot& slot, bool underlineGlyph, float currentUnderlinePosition, @@ -324,6 +328,8 @@ struct AtlasRenderer::Impl textCacheEntry.mImageId = slot.mImageId; textCacheEntry.mIndex = glyph.index; textCacheEntry.mOutlineWidth = outline; + textCacheEntry.isItalic = glyph.isItalicRequired; + textCacheEntry.isBold = glyph.isBoldRequired; newTextCache.PushBack( textCacheEntry ); @@ -445,7 +451,7 @@ struct AtlasRenderer::Impl const bool underlineEnabled = view.IsUnderlineEnabled(); const Vector4& underlineColor( view.GetUnderlineColor() ); const float underlineHeight = view.GetUnderlineHeight(); - const unsigned int outlineWidth = view.GetOutlineWidth(); + const uint16_t outlineWidth = view.GetOutlineWidth(); const Vector4& outlineColor( view.GetOutlineColor() ); const bool isOutline = 0u != outlineWidth; @@ -528,13 +534,18 @@ struct AtlasRenderer::Impl lastUnderlinedFontId = glyph.fontId; } // underline + AtlasGlyphManager::GlyphStyle style; + style.isItalic = glyph.isItalicRequired; + style.isBold = glyph.isBoldRequired; + // Retrieves and caches the glyph's bitmap. - CacheGlyph( glyph, lastFontId, NO_OUTLINE, slot ); + CacheGlyph( glyph, lastFontId, style, slot ); // Retrieves and caches the outline glyph's bitmap. if( isOutline ) { - CacheGlyph( glyph, lastFontId, outlineWidth, slotOutline ); + style.outline = outlineWidth; + CacheGlyph( glyph, lastFontId, style, slotOutline ); } // Move the origin (0,0) of the mesh to the center of the actor @@ -655,7 +666,11 @@ struct AtlasRenderer::Impl { for( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter ) { - mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, oldTextIter->mOutlineWidth, -1/*decrement*/ ); + AtlasGlyphManager::GlyphStyle style; + style.outline = oldTextIter->mOutlineWidth; + style.isItalic = oldTextIter->isItalic; + style.isBold = oldTextIter->isBold; + mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, style, -1/*decrement*/ ); } mTextCache.Resize( 0 ); } diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.cpp b/dali-toolkit/internal/text/rendering/text-typesetter.cpp index 8018054..de6b712 100755 --- a/dali-toolkit/internal/text/rendering/text-typesetter.cpp +++ b/dali-toolkit/internal/text/rendering/text-typesetter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -285,7 +285,7 @@ PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirec // Retrieves the layout size. const Size& layoutSize = mModel->GetLayoutSize(); - const float outlineWidth = mModel->GetOutlineWidth(); + const int outlineWidth = static_cast( mModel->GetOutlineWidth() ); // Set the offset for the horizontal alignment according to the text direction and outline width. int penX = 0; @@ -304,13 +304,13 @@ PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirec } case HorizontalAlignment::END: { - penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth * 2.0f : outlineWidth * 2.0f; + penX += ( textDirection == Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT ) ? -outlineWidth * 2 : outlineWidth * 2; break; } } // Set the offset for the vertical alignment. - int penY = 0; + int penY = 0u; switch( mModel->GetVerticalAlignment() ) { @@ -390,8 +390,8 @@ PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirec { // Generate the outline if enabled - const float outlineWidth = mModel->GetOutlineWidth(); - if ( outlineWidth > Math::MACHINE_EPSILON_1 ) + const uint16_t outlineWidth = mModel->GetOutlineWidth(); + if ( outlineWidth != 0u ) { // Create the image buffer for outline Devel::PixelBuffer outlineImageBuffer = CreateImageBuffer( bufferWidth, bufferHeight, Typesetter::STYLE_OUTLINE, ignoreHorizontalAlignment, pixelFormat, penX, penY, 0u, numberOfGlyphs -1 ); @@ -505,7 +505,7 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth } // Retrieves the glyph's outline width - float outlineWidth = mModel->GetOutlineWidth(); + float outlineWidth = static_cast( mModel->GetOutlineWidth() ); if( style == Typesetter::STYLE_OUTLINE ) { @@ -672,10 +672,10 @@ Devel::PixelBuffer Typesetter::CreateImageBuffer( const unsigned int bufferWidth { fontClient.CreateBitmap( glyphInfo->fontId, glyphInfo->index, - glyphInfo->softwareItalic, - glyphInfo->softwareBold, + glyphInfo->isItalicRequired, + glyphInfo->isBoldRequired, glyphData.glyphBitmap, - outlineWidth ); + static_cast( outlineWidth ) ); } diff --git a/dali-toolkit/internal/text/rendering/view-model.cpp b/dali-toolkit/internal/text/rendering/view-model.cpp index 3543fce..9be8215 100755 --- a/dali-toolkit/internal/text/rendering/view-model.cpp +++ b/dali-toolkit/internal/text/rendering/view-model.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -203,7 +203,7 @@ const Vector4& ViewModel::GetOutlineColor() const return mModel->GetOutlineColor(); } -float ViewModel::GetOutlineWidth() const +uint16_t ViewModel::GetOutlineWidth() const { return mModel->GetOutlineWidth(); } diff --git a/dali-toolkit/internal/text/rendering/view-model.h b/dali-toolkit/internal/text/rendering/view-model.h index 65cf48c..bc7d45f 100755 --- a/dali-toolkit/internal/text/rendering/view-model.h +++ b/dali-toolkit/internal/text/rendering/view-model.h @@ -191,7 +191,7 @@ public: /** * @copydoc ModelInterface::GetOutlineWidth() */ - virtual float GetOutlineWidth() const; + virtual uint16_t GetOutlineWidth() const; /** * @copydoc ModelInterface::GetBackgroundColor() diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp index 624c443..593e1e5 100644 --- a/dali-toolkit/internal/text/shaper.cpp +++ b/dali-toolkit/internal/text/shaper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -111,9 +111,13 @@ void ShapeText( const Vector& text, // There is no way to know the number of glyphs before shaping the text. // To avoid reallocations it's reserved space for a slightly biger number of glyphs than the number of characters. + GlyphInfo glyphInfo; + glyphInfo.isItalicRequired = false; + glyphInfo.isBoldRequired = false; + const Length currentNumberOfGlyphs = glyphs.Count(); const Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); - glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved ); + glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved, glyphInfo ); glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved ); // The actual number of glyphs. @@ -137,8 +141,8 @@ void ShapeText( const Vector& text, currentFontId = fontRun.fontId; currentScript = scriptRun.script; - bool softwareItalic = fontRun.softwareItalic; - bool softwareBold = fontRun.softwareBold; + const bool isItalicRequired = fontRun.isItalicRequired; + const bool isBoldRequired = fontRun.isBoldRequired; // Get the min index to the last character of both runs. CharacterIndex currentIndex = min( fontRun.characterRun.characterIndex + fontRun.characterRun.numberOfCharacters, @@ -174,8 +178,8 @@ void ShapeText( const Vector& text, Vector tmpGlyphToCharacterMap; GlyphInfo glyphInfo; - glyphInfo.softwareItalic = softwareItalic; - glyphInfo.softwareBold = softwareBold; + glyphInfo.isItalicRequired = isItalicRequired; + glyphInfo.isBoldRequired = isBoldRequired; tmpGlyphs.Resize( numberOfGlyphs, glyphInfo ); tmpGlyphToCharacterMap.Resize( numberOfGlyphs ); diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 1468941..6e6bfaa 100755 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -65,7 +65,7 @@ const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; float ConvertToEven( float value ) { int intValue(static_cast( value )); - return static_cast(intValue % 2 == 0) ? intValue : (intValue + 1); + return static_cast( intValue + ( intValue & 1 ) ); } } // namespace @@ -556,7 +556,8 @@ void Controller::SetText( const std::string& text ) mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor ); MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns, - mImpl->mModel->mLogicalModel->mFontDescriptionRuns ); + mImpl->mModel->mLogicalModel->mFontDescriptionRuns, + mImpl->mModel->mLogicalModel->mEmbeddedItems ); Length textSize = 0u; const uint8_t* utf8 = NULL; @@ -1241,14 +1242,14 @@ const Vector4& Controller::GetOutlineColor() const return mImpl->mModel->mVisualModel->GetOutlineColor(); } -void Controller::SetOutlineWidth( unsigned int width ) +void Controller::SetOutlineWidth( uint16_t width ) { mImpl->mModel->mVisualModel->SetOutlineWidth( width ); mImpl->RequestRelayout(); } -unsigned int Controller::GetOutlineWidth() const +uint16_t Controller::GetOutlineWidth() const { return mImpl->mModel->mVisualModel->GetOutlineWidth(); } @@ -3939,6 +3940,9 @@ void Controller::ResetText() // Reset buffers. mImpl->mModel->mLogicalModel->mText.Clear(); + // Reset the embedded images buffer. + mImpl->mModel->mLogicalModel->ClearEmbeddedImages(); + // We have cleared everything including the placeholder-text mImpl->PlaceholderCleared(); diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 33f1f8f..592b19d 100755 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -861,14 +861,14 @@ public: // Default style & Input style * * @param[in] width The width in pixels of the outline, 0 indicates no outline */ - void SetOutlineWidth( unsigned int width ); + void SetOutlineWidth( uint16_t width ); /** * @brief Retrieves the width of an outline * * @return The width of the outline. */ - unsigned int GetOutlineWidth() const; + uint16_t GetOutlineWidth() const; /** * @brief Set the background color. diff --git a/dali-toolkit/internal/text/text-definitions.h b/dali-toolkit/internal/text/text-definitions.h old mode 100644 new mode 100755 index 2884119..e98e08e --- a/dali-toolkit/internal/text/text-definitions.h +++ b/dali-toolkit/internal/text/text-definitions.h @@ -51,6 +51,8 @@ typedef TextAbstraction::Script Script; ///< The charact typedef TextAbstraction::LineBreakInfo LineBreakInfo; ///< Line break info (must break, allow break, no break). Possible values are: @e LINE_MUST_BREAK, @e LINE_ALLOW_BREAK and @e LINE_NO_BREAK (in the TextAbstraction namespace). typedef TextAbstraction::WordBreakInfo WordBreakInfo; ///< Word break info (break, no break). Possible values are: @e WORD_BREAK and @e WORD_NO_BREAK (in the TextAbstraction namespace). typedef TextAbstraction::CharacterDirection CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left. +typedef TextAbstraction::ColorBlendingMode ColorBlendingMode; ///< Defines how a color is blended. +typedef TextAbstraction::ColorIndex ColorIndex; ///< An index into an array of colors. typedef uint32_t GlyphIndex; ///< An index into an array of glyphs. typedef uint32_t ScriptRunIndex; ///< An index into an array of script runs. @@ -60,7 +62,6 @@ typedef uint32_t BidirectionalRunIndex; ///< An inde typedef uint32_t BidirectionalLineRunIndex; ///< An index into an array of bidirectional line info. typedef uint32_t LineIndex; ///< An index into an array of lines. typedef uint32_t ParagraphRunIndex; ///< An index into an array of paragraphs. -typedef uint32_t ColorIndex; ///< An index into an array of colors. } // namespace Text diff --git a/dali-toolkit/internal/text/text-effects-style.cpp b/dali-toolkit/internal/text/text-effects-style.cpp index 10d9da4..d5f8ff1 100755 --- a/dali-toolkit/internal/text/text-effects-style.cpp +++ b/dali-toolkit/internal/text/text-effects-style.cpp @@ -175,7 +175,7 @@ bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap, bool& colorDefined, Vector4& color, bool& widthDefined, - unsigned int& width ) + uint16_t& width ) { const unsigned int numberOfItems = underlinePropertiesMap.Count(); @@ -194,7 +194,7 @@ bool ParseOutlineProperties( const Property::Map& underlinePropertiesMap, { /// Width key. widthDefined = true; - width = static_cast( valueGet.second.Get() ); + width = static_cast( valueGet.second.Get() ); } } @@ -587,7 +587,7 @@ bool SetOutlineProperties( ControllerPtr controller, const Property::Value& valu bool colorDefined = false; Vector4 color; bool widthDefined = false; - unsigned int width = 0u; + uint16_t width = 0u; bool empty = true; @@ -668,7 +668,7 @@ void GetOutlineProperties( ControllerPtr controller, Property::Value& value, Eff else { const Vector4& color = controller->GetOutlineColor(); - const unsigned int width = controller->GetOutlineWidth(); + const uint16_t width = controller->GetOutlineWidth(); Property::Map map; map.Insert( COLOR_KEY, color ); diff --git a/dali-toolkit/internal/text/text-model-interface.h b/dali-toolkit/internal/text/text-model-interface.h index f2a82ad..a301d03 100755 --- a/dali-toolkit/internal/text/text-model-interface.h +++ b/dali-toolkit/internal/text/text-model-interface.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_TEXT_MODEL_INTERFACE_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -238,7 +238,7 @@ public: * * @return The width of the outline. */ - virtual float GetOutlineWidth() const = 0; + virtual uint16_t GetOutlineWidth() const = 0; /** * @brief Retrieves the background color. diff --git a/dali-toolkit/internal/text/text-model.cpp b/dali-toolkit/internal/text/text-model.cpp index 474b3ae..da87e0c 100755 --- a/dali-toolkit/internal/text/text-model.cpp +++ b/dali-toolkit/internal/text/text-model.cpp @@ -162,7 +162,7 @@ const Vector4& Model::GetOutlineColor() const return mVisualModel->GetOutlineColor(); } -float Model::GetOutlineWidth() const +uint16_t Model::GetOutlineWidth() const { return mVisualModel->GetOutlineWidth(); } diff --git a/dali-toolkit/internal/text/text-model.h b/dali-toolkit/internal/text/text-model.h index f4fbd7b..3230e47 100755 --- a/dali-toolkit/internal/text/text-model.h +++ b/dali-toolkit/internal/text/text-model.h @@ -191,7 +191,7 @@ public: /** * @copydoc ModelInterface::GetOutlineWidth() */ - virtual float GetOutlineWidth() const override; + virtual uint16_t GetOutlineWidth() const override; /** * @copydoc ModelInterface::GetBackgroundColor() diff --git a/dali-toolkit/internal/text/text-view-interface.h b/dali-toolkit/internal/text/text-view-interface.h old mode 100644 new mode 100755 index 96f9005..9e8020c --- a/dali-toolkit/internal/text/text-view-interface.h +++ b/dali-toolkit/internal/text/text-view-interface.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H__ -#define __DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H__ +#ifndef DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H +#define DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -185,7 +185,7 @@ public: * * @return The width of the outline. */ - virtual unsigned int GetOutlineWidth() const = 0; + virtual uint16_t GetOutlineWidth() const = 0; }; @@ -195,4 +195,4 @@ public: } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H__ +#endif // DALI_TOOLKIT_TEXT_VIEW_INTERFACE_H diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp old mode 100644 new mode 100755 index 62c0008..929c17c --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -411,7 +411,7 @@ const Vector4& View::GetOutlineColor() const return Vector4::ZERO; } -unsigned int View::GetOutlineWidth() const +uint16_t View::GetOutlineWidth() const { if( mImpl->mVisualModel ) { diff --git a/dali-toolkit/internal/text/text-view.h b/dali-toolkit/internal/text/text-view.h old mode 100644 new mode 100755 index 51426de..e7d1942 --- a/dali-toolkit/internal/text/text-view.h +++ b/dali-toolkit/internal/text/text-view.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_VIEW_H__ -#define __DALI_TOOLKIT_TEXT_VIEW_H__ +#ifndef DALI_TOOLKIT_TEXT_VIEW_H +#define DALI_TOOLKIT_TEXT_VIEW_H /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -139,7 +139,7 @@ public: /** * @copydoc Dali::Toolkit::Text::ViewInterface::GetOutlineWidth() */ - virtual unsigned int GetOutlineWidth() const; + virtual uint16_t GetOutlineWidth() const; private: @@ -160,4 +160,4 @@ private: } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_VIEW_H__ +#endif // DALI_TOOLKIT_TEXT_VIEW_H diff --git a/dali-toolkit/internal/text/visual-model-impl.cpp b/dali-toolkit/internal/text/visual-model-impl.cpp index bd567a4..3b1f5b7 100755 --- a/dali-toolkit/internal/text/visual-model-impl.cpp +++ b/dali-toolkit/internal/text/visual-model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -373,7 +373,7 @@ void VisualModel::SetUnderlineHeight( float height ) mUnderlineHeight = height; } -void VisualModel::SetOutlineWidth( unsigned int width ) +void VisualModel::SetOutlineWidth( uint16_t width ) { mOutlineWidth = width; } @@ -428,7 +428,7 @@ float VisualModel::GetUnderlineHeight() const return mUnderlineHeight; } -unsigned int VisualModel::GetOutlineWidth() const +uint16_t VisualModel::GetOutlineWidth() const { return mOutlineWidth; } @@ -473,8 +473,8 @@ VisualModel::VisualModel() mControlSize(), mShadowOffset(), mUnderlineHeight( 0.0f ), - mOutlineWidth( 0u ), mShadowBlurRadius( 0.0f ), + mOutlineWidth( 0u ), mNaturalSize(), mLayoutSize(), mCachedLineIndex( 0u ), diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index 1cb6b4d..4b82cef 100755 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -1,8 +1,8 @@ -#ifndef __DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H__ -#define __DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H__ +#ifndef DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H +#define DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -320,14 +320,14 @@ public: * * @param[in] width The width in pixels of the outline, 0 indicates no outline */ - void SetOutlineWidth( unsigned int width ); + void SetOutlineWidth( uint16_t width ); /** * @brief Retrieves the width of an outline * * @return The width of the outline. */ - unsigned int GetOutlineWidth() const; + uint16_t GetOutlineWidth() const; /** * @brief Sets the text's background color. @@ -398,8 +398,8 @@ public: Size mControlSize; ///< The size of the UI control. Vector2 mShadowOffset; ///< Offset for drop shadow, 0 indicates no shadow float mUnderlineHeight; ///< Fixed height for underline to override font metrics. - unsigned int mOutlineWidth; ///< Width of outline. float mShadowBlurRadius; ///< Blur radius of shadow, 0 indicates no blur. + uint16_t mOutlineWidth; ///< Width of outline. private: @@ -422,4 +422,4 @@ public: } // namespace Dali -#endif // __DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H__ +#endif // DALI_TOOLKIT_TEXT_VISUAL_MODEL_IMPL_H