From 438618b603404cf0edb6df2eefe58702e40f0723 Mon Sep 17 00:00:00 2001 From: Joogab Yun Date: Fri, 10 Jul 2020 15:14:55 +0900 Subject: [PATCH] Add GetLastCharacterIndex(). This returns the last character indices when the input text is rendered with the layout size. Change-Id: I9f6ff3226a3aeb94c19d3ad69aabc8e017f99cbe --- .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 23 +++ dali-toolkit/devel-api/text/text-utils-devel.cpp | 225 +++++++++++++++------ dali-toolkit/devel-api/text/text-utils-devel.h | 9 + 3 files changed, 191 insertions(+), 66 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 4fa21f8..07052fc 100755 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace Dali; using namespace Toolkit; @@ -1631,3 +1632,25 @@ int UtcDaliToolkitTextlabelMaxTextureSet(void) END_TEST; } + +int UtcDaliToolkitTextlabelLastCharacterIndex(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextlabelLastCharacterIndex"); + + Vector2 size( 300.0f, 100.0f ); + + Dali::Toolkit::DevelText::RendererParameters textParameters; + textParameters.text = "This is a sample text to get the last index."; + textParameters.layout = "multiLine"; + textParameters.fontSize = 20.f; + textParameters.textWidth = 300u; + textParameters.textHeight = 100u; + textParameters.ellipsisEnabled = true; + Dali::Property::Array indexArray = Dali::Toolkit::DevelText::GetLastCharacterIndex( textParameters ); + + DALI_TEST_CHECK( !indexArray.Empty() ); + DALI_TEST_EQUALS( indexArray.GetElementAt(0).Get(), 10, TEST_LOCATION ); + + END_TEST; +} \ No newline at end of file diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp index ccea7e0..c39cb21 100755 --- a/dali-toolkit/devel-api/text/text-utils-devel.cpp +++ b/dali-toolkit/devel-api/text/text-utils-devel.cpp @@ -25,6 +25,7 @@ #include #include #include +#include // INTERNAL INCLUDES #include @@ -91,6 +92,7 @@ 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; +const float MAX_INT = std::numeric_limits::max(); DALI_ENUM_TO_STRING_TABLE_BEGIN( LAYOUT_TYPE ) DALI_ENUM_TO_STRING_WITH_SCOPE( DevelText::Layout, SINGLELINE ) @@ -132,6 +134,7 @@ struct InternalDataModel bool isTextMirrored ; // Whether the text has been mirrored. Length numberOfGlyphs; + Size textLayoutArea; }; bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout) @@ -495,14 +498,12 @@ void SetEmojiVector( InternalDataModel& internalDataModel ) void Align( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector& embeddedItemLayout, InternalDataModel& internalDataModel, - Size& textLayoutArea, const Size& newLayoutSize, - const bool isCircularTextLayout, const bool isClockwise, - HorizontalAlignment::Type horizontalAlignment, VerticalAlignment::Type verticalAlignment, CircularAlignment::Type circularAlignment, - const unsigned int radius ) + const Size& newLayoutSize ) { Text::Layout::Engine& layoutEngine = internalDataModel.layoutEngine; Text::ModelPtr& textModel = internalDataModel.textModel; const Length numberOfCharacters = internalDataModel.numberOfCharacters; + Size& textLayoutArea = internalDataModel.textLayoutArea; Vector& lines = textModel->mVisualModel->mLines; // The laid out lines. @@ -510,6 +511,55 @@ void Align( const RendererParameters& textParameters, TextAbstraction::TextRende // Align the text. //////////////////////////////////////////////////////////////////////////////// + HorizontalAlignment::Type horizontalAlignment = Toolkit::HorizontalAlignment::CENTER; + HorizontalAlignment::Type horizontalCircularAlignment = Toolkit::HorizontalAlignment::CENTER; + VerticalAlignment::Type verticalAlignment = VerticalAlignment::CENTER; + CircularAlignment::Type circularAlignment = CircularAlignment::BEGIN; + + Layout::Type layout = Layout::SINGLELINE; + + // Sets the alignment + Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment ); + GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment ); + horizontalCircularAlignment = horizontalAlignment; + + Property::Value verticalAlignmentStr( textParameters.verticalAlignment ); + GetVerticalAlignmentEnumeration( verticalAlignmentStr, verticalAlignment ); + + Property::Value circularAlignmentStr( textParameters.circularAlignment ); + GetCircularAlignmentEnumeration( circularAlignmentStr, circularAlignment ); + + Property::Value layoutStr( textParameters.layout ); + GetLayoutEnumeration( layoutStr, layout ); + + // Whether the layout is circular. + const bool isCircularTextLayout = (Layout::CIRCULAR == layout); + const bool isClockwise = isCircularTextLayout && ( 0.f < textParameters.incrementAngle ); + + // 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; + } + } + } + textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment; + // Retrieve the line of text to know the direction and the width. @todo multi-line const LineRun& line = lines[0u]; @@ -604,14 +654,14 @@ void Align( const RendererParameters& textParameters, TextAbstraction::TextRende { 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 ); + angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast( rendererParameters.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 ); + angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast( rendererParameters.radius ); break; } } @@ -700,7 +750,7 @@ void Align( const RendererParameters& textParameters, TextAbstraction::TextRende Dali::TextAbstraction::CircularTextParameters circularTextParameters; - circularTextParameters.radius = static_cast( radius ); + circularTextParameters.radius = static_cast( rendererParameters.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 ); @@ -768,14 +818,14 @@ void Align( const RendererParameters& textParameters, TextAbstraction::TextRende } void Ellipsis( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, - Vector& embeddedItemLayout, Size& textLayoutArea, InternalDataModel& internalDataModel ) + Vector& embeddedItemLayout, InternalDataModel& internalDataModel ) { Text::ModelPtr& textModel = internalDataModel.textModel; FontClient& fontClient = internalDataModel.fontClient; Vector& lines = textModel->mVisualModel->mLines; // The laid out lines. Vector& isEmoji = internalDataModel.isEmoji; - + const Size textLayoutArea = internalDataModel.textLayoutArea; //////////////////////////////////////////////////////////////////////////////// // Ellipsis the text. //////////////////////////////////////////////////////////////////////////////// @@ -942,31 +992,15 @@ Size LayoutText( const RendererParameters& textParameters, TextAbstraction::Text const Vector& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters; const Length numberOfCharacters = internalDataModel.numberOfCharacters; - // 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 ); @@ -990,49 +1024,23 @@ Size LayoutText( const RendererParameters& textParameters, TextAbstraction::Text } 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 ) ); + internalDataModel.textLayoutArea = Size( 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 ) ); + internalDataModel.textLayoutArea.width = fabs( Radian( Degree( textParameters.incrementAngle ) ) * static_cast( rendererParameters.radius ) ); } // Resize the vector of positions to have the same size than the vector of glyphs. rendererParameters.positions.Resize( numberOfGlyphs ); - - - textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment; textModel->mLineWrapMode = LineWrap::WORD; textModel->mIgnoreSpacesAfterText = false; textModel->mMatchSystemLanguageDirection = false; - Text::Layout::Parameters layoutParameters( textLayoutArea, + Text::Layout::Parameters layoutParameters( internalDataModel.textLayoutArea, textModel ); @@ -1055,14 +1063,7 @@ Size LayoutText( const RendererParameters& textParameters, TextAbstraction::Text textParameters.ellipsisEnabled, isAutoScrollEnabled ); - //////////////////////////////////////////////////////////////////////////////// - // Align the text. - //////////////////////////////////////////////////////////////////////////////// - Align( textParameters, rendererParameters, embeddedItemLayout, internalDataModel, - textLayoutArea, newLayoutSize, isCircularTextLayout, isClockwise, - horizontalAlignment, verticalAlignment, circularAlignment, radius ); - - return textLayoutArea; + return newLayoutSize; } @@ -1146,14 +1147,20 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectormVisualModel->mGlyphs, + textModel->mVisualModel->mGlyphPositions, + textModel->mVisualModel->mColors, + textModel->mVisualModel->mColorIndices, + internalData.blendingMode, + internalData.isEmoji ); + + + rendererParameters.width = textParameters.textWidth; + rendererParameters.height = textParameters.textHeight; + + //////////////////////////////////////////////////////////////////////////////// + // Process the markup string if the mark-up processor is enabled. + //////////////////////////////////////////////////////////////////////////////// + ShapeTextPreprocess( textParameters, rendererParameters, internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyphs. Text shaping + //////////////////////////////////////////////////////////////////////////////// + Dali::Vector embeddedItemLayout; + ShapeText( rendererParameters, embeddedItemLayout, internalData ); + + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyph's metrics. + //////////////////////////////////////////////////////////////////////////////// + metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs ); + + + //////////////////////////////////////////////////////////////////////////////// + // Layout the text + //////////////////////////////////////////////////////////////////////////////// + int boundingBox = textParameters.textHeight; + textParameters.textHeight = MAX_INT; // layout for the entire area. + LayoutText( textParameters, rendererParameters, embeddedItemLayout, internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Calculation last character index + //////////////////////////////////////////////////////////////////////////////// + Vector& lines = internalData.textModel->mVisualModel->mLines; + unsigned int numberOfLines = lines.Count(); + int numberOfCharacters = 0; + float penY = 0.f; + for( unsigned int index = 0u; index < numberOfLines; ++index ) + { + const LineRun& line = *( lines.Begin() + index ); + numberOfCharacters += line.characterRun.numberOfCharacters; + penY += ( line.ascender + -line.descender ); + if( ( penY + ( line.ascender + -line.descender ) ) > boundingBox ) + { + offsetValues.PushBack( numberOfCharacters ); + penY = 0.f; + } + } + if( penY > 0.f) + { + // add remain character index + offsetValues.PushBack( numberOfCharacters ); + } + + return offsetValues; +} + + +Dali::Property::Array GetLastCharacterIndex( RendererParameters& textParameters ) +{ + Dali::Property::Array offsetValues = Toolkit::DevelText::RenderForLastIndex( textParameters ); + return offsetValues; +} + + } // namespace DevelText } // namespace Toolkit diff --git a/dali-toolkit/devel-api/text/text-utils-devel.h b/dali-toolkit/devel-api/text/text-utils-devel.h index 83c6ea9..0670e8e 100755 --- a/dali-toolkit/devel-api/text/text-utils-devel.h +++ b/dali-toolkit/devel-api/text/text-utils-devel.h @@ -19,6 +19,7 @@ */ // EXTERNAL INCLUDES +#include #include #include #include @@ -192,6 +193,14 @@ DALI_TOOLKIT_API Devel::PixelBuffer ConvertToRgba8888( Devel::PixelBuffer pixelB */ DALI_TOOLKIT_API void UpdateBuffer( Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x, unsigned int y, bool blend); +/** + * @brief Splits the text in pages of the size given in @p textParameters + * + * @note The returned indices are indices to utf32 characters. The input text is encoded in utf8. + * @return An array with the indices of the last character of each page + */ +DALI_TOOLKIT_API Dali::Property::Array GetLastCharacterIndex( RendererParameters& textParameters ); + } // namespace DevelText } // namespace Toolkit -- 2.7.4