From 6d037ef28de48c074ad4d8e292e35ebf20403c23 Mon Sep 17 00:00:00 2001 From: Joogab Yun Date: Tue, 2 Feb 2021 13:15:28 +0900 Subject: [PATCH] [Tizen] Integration TextUtils from tizen_6.0 to tizen_5.5 Add MIN_LINE_SIZE property Users want to set the line size in multi-line. We have a lineSpacing property which allows us to set the spacing of the lines. However, the user wants to achieve a similar effect by setting the size of the line, not lineSpacing. Change-Id: Ia96e1875e90454a3269d2ad853d3c4e20ce66ae9 Change Resize() to Reserve() to improve performance. Change-Id: I6078fb17131630a770cb770dc9f2251f1c9ae6b6 Divide Render() into small apis Change-Id: If20f7a5cef20386e2aeb00cf1d3e283b10da3e93 Add GetLastCharacterIndex(). This returns the last character indices when the input text is rendered with the layout size. Change-Id: I9f6ff3226a3aeb94c19d3ad69aabc8e017f99cbe add minLineSize at text-utils-devel Change-Id: I1a11d35283b8f7b4cf14b0ae40487307b24e0a0a There is a problem that ellipsis does not work properly when MIN_LINE_SIZE is set. Update the penY value. Change-Id: Iaab2f2590bda4c80316262dcf4f9fcb0f5a91343 If the size of the text is larger than the size of the control, setting it to VerticalAlignment::Center cuts the top and bottom of the text. The VerticalAlignment::CENTER setting works when the size of the control is enough. Change-Id: I3d35b4dfceb4297c89bddfc5c5364de4be5bc646 add Padding parameter at RendererParameters Change-Id: If8d78e1363bc02b5f872119af59f6d3b89550b90 Change-Id: Ib96012d9671bbb0154cec76c7800f03590183a41 text tiling If the length of text is very long and exceeds maxTextureSize, it cannot be displayed on the screen. So tiling is required. I implement tiling by attaching multiple renderers. And the MAX_TEXT_LENGTH limit is removed. sample) std::ifstream file; file.open(PATH[0]); std::stringstream ss; ss << file.rdbuf(); file.close(); ScrollView scroller = ScrollView::New(); scroller.SetPosition( 100.f, 100.f); scroller.SetSize(500.f, 1000.f); scroller.SetAnchorPoint(AnchorPoint::TOP_LEFT); scroller.SetParentOrigin(ParentOrigin::TOP_LEFT); scroller.SetAxisAutoLock(true); TextLabel textLabel = TextLabel::New( ); textLabel.SetProperty( TextLabel::Property::TEXT, ss.str() ); textLabel.SetAnchorPoint( AnchorPoint::TOP_LEFT ); textLabel.SetParentOrigin(ParentOrigin::TOP_LEFT); textLabel.SetProperty( TextLabel::Property::VERTICAL_ALIGNMENT, "TOP" ); textLabel.SetProperty( TextLabel::Property::MULTI_LINE, true ); textLabel.SetProperty( TextLabel::Property::ELLIPSIS, false ); textLabel.SetProperty( TextLabel::Property::ENABLE_MARKUP, true ); textLabel.SetProperty( TextLabel::Property::POINT_SIZE, 16); textLabel.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLUE ); scroller.Add( textLabel ); stage.Add( scroller ); Change-Id: I65082244a801ba697fd9ab0b598c82e702c2a948 --- .../utc-Dali-Text-Controller.cpp | 59 --- .../src/dali-toolkit/utc-Dali-TextLabel.cpp | 52 ++ .../controls/text-controls/text-label-devel.h | 7 + dali-toolkit/devel-api/text/text-utils-devel.cpp | 541 +++++++++++++++------ dali-toolkit/devel-api/text/text-utils-devel.h | 42 +- .../controls/text-controls/text-label-impl.cpp | 24 +- .../internal/text/layouts/layout-engine.cpp | 46 +- dali-toolkit/internal/text/layouts/layout-engine.h | 14 + .../internal/text/rendering/text-typesetter.cpp | 1 + dali-toolkit/internal/text/shaper.cpp | 4 +- dali-toolkit/internal/text/text-controller.cpp | 26 +- dali-toolkit/internal/text/text-controller.h | 16 + dali-toolkit/internal/visuals/text/text-visual.cpp | 285 +++++++---- dali-toolkit/internal/visuals/text/text-visual.h | 91 +++- 14 files changed, 892 insertions(+), 316 deletions(-) mode change 100644 => 100755 dali-toolkit/internal/text/shaper.cpp mode change 100644 => 100755 dali-toolkit/internal/visuals/text/text-visual.h diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp index 064f663..3e53b67 100755 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Controller.cpp @@ -1151,65 +1151,6 @@ int UtcDaliTextControllerSelectEvent(void) } -int UtcDaliTextControllerMaxLengthSetText(void) -{ - tet_infoline(" UtcDaliTextControllerMaxLengthSetText"); - ToolkitTestApplication application; - - // Creates a text controller. - ControllerPtr controller = Controller::New(); - - ConfigureTextLabel(controller); - - const Length MAX_TEXT_LENGTH = 1024u * 32u; - - // make over length world - int maxLength = (1024u * 32u) + 10u; - char world[maxLength]; - for( int i = 0; i < maxLength; i++ ) - { - world[i] = 'a'; - } - - // Set the text - std::string text(world); - controller->SetText( text ); - - // Perform a relayout - const Size size( Dali::Stage::GetCurrent().GetSize() ); - controller->Relayout(size); - - // check text length - controller->GetText( text ); - Length textSize = text.size(); - - DALI_TEST_EQUALS( MAX_TEXT_LENGTH, textSize, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliTextControllerDirectionCoverage(void) -{ - tet_infoline(" UtcDaliTextControllerDirectionCoverage"); - ToolkitTestApplication application; - - // Creates a text controller. - ControllerPtr controller = Controller::New(); - - ConfigureTextLabel(controller); - - controller->SetMatchSystemLanguageDirection( true ); - controller->SetLayoutDirection( Dali::LayoutDirection::RIGHT_TO_LEFT ); - - // Perform a relayout - const Size size( Dali::Stage::GetCurrent().GetSize() ); - controller->Relayout(size); - - tet_result(TET_PASS); - - END_TEST; -} - int UtcDaliTextControllerRemoveTextChangeEventData(void) { tet_infoline(" UtcDaliTextControllerRemoveTextChangeEventData"); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp index 646cb2b..939ce1c 100755 --- a/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include using namespace Dali; using namespace Toolkit; @@ -636,6 +638,11 @@ int UtcDaliToolkitTextLabelSetPropertyP(void) label.SetProperty( Actor::Property::LAYOUT_DIRECTION, LayoutDirection::RIGHT_TO_LEFT ); DALI_TEST_EQUALS( label.GetProperty< int >( Actor::Property::LAYOUT_DIRECTION ), static_cast< int >( LayoutDirection::RIGHT_TO_LEFT ), TEST_LOCATION ); + // Check the line size property + DALI_TEST_EQUALS( label.GetProperty( DevelTextLabel::Property::MIN_LINE_SIZE ), 0.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + label.SetProperty( DevelTextLabel::Property::MIN_LINE_SIZE, 50.f ); + DALI_TEST_EQUALS( label.GetProperty( DevelTextLabel::Property::MIN_LINE_SIZE ), 50.0f, Math::MACHINE_EPSILON_1000, TEST_LOCATION ); + application.SendNotification(); application.Render(); @@ -1580,3 +1587,48 @@ int UtcDaliToolkitTextlabelTextFit(void) END_TEST; } + +int UtcDaliToolkitTextlabelMaxTextureSet(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliToolkitTextlabelMaxTextureSet"); + + DevelText::BitmapFontDescription fontDescription; + fontDescription.name = "Digits"; + fontDescription.glyphs.push_back( { TEST_RESOURCE_DIR "/fonts/bitmap/u0030.png", ":", 200.f, 0.f } ); + + TextAbstraction::BitmapFont bitmapFont; + DevelText::CreateBitmapFont( fontDescription, bitmapFont ); + + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.GetFontId( bitmapFont ); + + TextLabel label = TextLabel::New(); + label.SetProperty( TextLabel::Property::FONT_FAMILY, "Digits" ); + label.SetProperty( TextLabel::Property::ENABLE_MARKUP, true ); + label.SetProperty( TextLabel::Property::TEXT, ":This is a long sample text made to allow max texture size to be exceeded." ); + label.SetProperty( TextLabel::Property::POINT_SIZE, 200.f ); + label.SetProperty( TextLabel::Property::MULTI_LINE, true ); + + Property::Map underlineMapSet; + underlineMapSet.Clear(); + underlineMapSet.Insert( "enable", true ); + underlineMapSet.Insert( "color", Color::RED ); + underlineMapSet.Insert( "height", 1 ); + label.SetProperty( TextLabel::Property::UNDERLINE, underlineMapSet ); + label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, Color::BLUE ); + + Stage::GetCurrent().Add( label ); + + application.SendNotification(); + application.Render(); + + const int maxTextureSize = Dali::GetMaxTextureSize(); + // Whether the rendered text is greater than maxTextureSize + DALI_TEST_CHECK( label.GetCurrentSize().height > maxTextureSize ); + + // Check if the number of renderers is greater than 1. + DALI_TEST_CHECK( label.GetRendererCount() > 1u ); + + END_TEST; +} diff --git a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h index 72ad6f8..9190441 100755 --- a/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h +++ b/dali-toolkit/devel-api/controls/text-controls/text-label-devel.h @@ -140,6 +140,13 @@ namespace Property */ TEXT_FIT, + /** + * @brief Sets the height of the line in points. + * @details Name "lineSize", type Property::FLOAT. + * @note If the font size is larger than the line size, it works with the font size. + */ + MIN_LINE_SIZE, + }; } // namespace Property diff --git a/dali-toolkit/devel-api/text/text-utils-devel.cpp b/dali-toolkit/devel-api/text/text-utils-devel.cpp index fae3c10..cf5e573 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 ) @@ -104,6 +106,37 @@ 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 ) +struct InternalDataModel +{ + InternalDataModel( FontClient& fontClient, + MetricsPtr metrics, + Text::ModelPtr textModel ) + : fontClient( fontClient ), + metrics( metrics ), + textModel( textModel ), + numberOfCharacters{ 0u }, + isTextMirrored{ false }, + numberOfGlyphs{ 0u } + { + layoutEngine.SetMetrics( metrics ); + } + + FontClient& fontClient; + MetricsPtr metrics; + Text::Layout::Engine layoutEngine; ///< The layout engine. + Text::ModelPtr textModel; ///< Pointer to the text's model. + Vector blendingMode; ///< How embedded items and bitmap font glyphs are blended with color text. + Vector isEmoji; ///< Whether the glyph is an emoji. + + Vector mirroredUtf32Characters; // The utf32Characters Characters but mirrored if there are RTL text. + + Length numberOfCharacters; // The number of characters (not glyphs!). + bool isTextMirrored ; // Whether the text has been mirrored. + + Length numberOfGlyphs; + Size textLayoutArea; +}; + bool GetLayoutEnumeration(const Property::Value& propertyValue, DevelText::Layout::Type& layout) { return Scripting::GetEnumerationProperty(propertyValue, LAYOUT_TYPE_TABLE, LAYOUT_TYPE_TABLE_COUNT, layout); @@ -114,80 +147,37 @@ bool GetCircularAlignmentEnumeration(const Property::Value& propertyValue, Devel return Scripting::GetEnumerationProperty(propertyValue, CIRCULAR_ALIGNMENT_TYPE_TABLE, CIRCULAR_ALIGNMENT_TYPE_TABLE_COUNT, circularAlignment); } -Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout ) +void ShapeTextPreprocess( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, InternalDataModel& internalDataModel ) { - 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. - Text::ModelPtr textModel = Text::Model::New(); ///< Pointer to the text's 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( textModel->mVisualModel->mGlyphs, - textModel->mVisualModel->mGlyphPositions, - textModel->mVisualModel->mColors, - textModel->mVisualModel->mColorIndices, - blendingMode, - isEmoji ); + 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. - rendererParameters.width = textParameters.textWidth; - rendererParameters.height = textParameters.textHeight; - rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888 + Length& numberOfCharacters = internalDataModel.numberOfCharacters; + Vector& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters; + Text::ModelPtr& textModel = internalDataModel.textModel; Vector& utf32Characters = textModel->mLogicalModel->mText; // Characters encoded in utf32. - Vector mirroredUtf32Characters; // The utf32Characters Characters but mirrored if there are RTL text. Vector& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo; // The line break info. Vector& scripts = textModel->mLogicalModel->mScriptRuns; // Charactes's script. Vector& fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns; // Desired font descriptions. Vector& validFonts = textModel->mLogicalModel->mFontRuns; // Validated fonts. Vector& bidirectionalInfo = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph. - //Vector& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo; // The bidirectional info per line. Vector& directions = textModel->mLogicalModel->mCharacterDirections; // Character's directions. Vector& colorRuns = textModel->mLogicalModel->mColorRuns; // colors of the text. - Vector& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters; // Glyphs to character map. - Vector& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph; // Characters to glyphs map. - Vector& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph; // Number of characters per glyph. - Vector& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter; // The number of glyphs that are shaped. - Vector& lines = textModel->mVisualModel->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, - textModel->mLogicalModel->mEmbeddedItems ); + fontDescriptionRuns, + textModel->mLogicalModel->mEmbeddedItems ); if (textParameters.markupEnabled) { @@ -232,9 +222,9 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout, InternalDataModel& internalDataModel ) +{ + Vector newParagraphGlyphs; // Glyphs for the new paragraph characters. + const Length numberOfCharacters = internalDataModel.numberOfCharacters; + const bool isTextMirrored = internalDataModel.isTextMirrored; + Text::ModelPtr& textModel = internalDataModel.textModel; + const Vector& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters; + FontClient& fontClient = internalDataModel.fontClient; + const Vector& utf32Characters = textModel->mLogicalModel->mText; // Characters encoded in utf32. + const Vector& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo; // The line break info. + const Vector& scripts = textModel->mLogicalModel->mScriptRuns; // Charactes's script. + const Vector& validFonts = textModel->mLogicalModel->mFontRuns; // Validated fonts. + + Vector& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters; // Glyphs to character map. + Vector& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph; // Number of characters per glyph. //////////////////////////////////////////////////////////////////////////////// // Retrieve the glyphs. Text shaping @@ -363,7 +370,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectormVisualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters ); textModel->mVisualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters ); - const Length numberOfGlyphs = rendererParameters.glyphs.Count(); + internalDataModel.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. @@ -402,12 +409,18 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectorGetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs ); + Text::ModelPtr& textModel = internalDataModel.textModel; + Vector& blendingMode = internalDataModel.blendingMode; + + Vector& colorRuns = textModel->mLogicalModel->mColorRuns; // colors of the text. + + Vector& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph; // Characters to glyphs map. + Vector& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter; // The number of glyphs that are shaped. //////////////////////////////////////////////////////////////////////////////// // Set the color runs in glyphs. @@ -418,7 +431,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectormVisualModel->mColors, textModel->mVisualModel->mColorIndices ); @@ -426,7 +439,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectormVisualModel->mColors.Insert( textModel->mVisualModel->mColors.Begin(),textParameters.textColor ); // Set how the embedded items are blended with text color. - blendingMode.Resize( numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE ); + blendingMode.Resize( internalDataModel.numberOfGlyphs, textParameters.isTextColorSet ? ColorBlendingMode::MULTIPLY : ColorBlendingMode::NONE ); if( !textParameters.isTextColorSet ) { @@ -450,7 +463,15 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, VectormVisualModel->mCharactersToGlyph[item.characterIndex]; blendingMode[glyphIndex] = item.colorBlendingMode; } +} + +void SetEmojiVector( InternalDataModel& internalDataModel ) +{ + Vector& isEmoji = internalDataModel.isEmoji; + Text::ModelPtr& textModel = internalDataModel.textModel; + const Length numberOfGlyphs = internalDataModel.numberOfGlyphs; + const Vector& scripts = textModel->mLogicalModel->mScriptRuns; // Charactes's script. //////////////////////////////////////////////////////////////////////////////// // Set the isEmoji Vector //////////////////////////////////////////////////////////////////////////////// @@ -471,18 +492,32 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout, InternalDataModel& internalDataModel, + 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. //////////////////////////////////////////////////////////////////////////////// - // Layout the text. + // Align 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; + Layout::Type layout = Layout::SINGLELINE; + + // Sets the alignment Property::Value horizontalAlignmentStr( textParameters.horizontalAlignment ); GetHorizontalAlignmentEnumeration( horizontalAlignmentStr, horizontalAlignment ); horizontalCircularAlignment = horizontalAlignment; @@ -490,40 +525,16 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector( maxAscenderDescender ); - // Convert CircularAlignment to HorizontalAlignment. if( isCircularTextLayout ) { @@ -546,49 +557,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector( 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 ) ); - } - textModel->mHorizontalAlignment = isCircularTextLayout ? horizontalCircularAlignment : horizontalAlignment; - textModel->mLineWrapMode = LineWrap::WORD; - textModel->mIgnoreSpacesAfterText = false; - textModel->mMatchSystemLanguageDirection = false; - Text::Layout::Parameters layoutParameters( textLayoutArea, - textModel ); - - // 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; - layoutParameters.interGlyphExtraAdvance = 0.f; - - // Update the visual model. - Size newLayoutSize; - bool isAutoScrollEnabled = false; - layoutEngine.LayoutText( layoutParameters, - newLayoutSize, - textParameters.ellipsisEnabled, - isAutoScrollEnabled ); - - //////////////////////////////////////////////////////////////////////////////// - // Align the text. - //////////////////////////////////////////////////////////////////////////////// // Retrieve the line of text to know the direction and the width. @todo multi-line const LineRun& line = lines[0u]; @@ -684,14 +653,14 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector( 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; } } @@ -730,7 +699,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector( 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 ); @@ -845,6 +814,17 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, 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. //////////////////////////////////////////////////////////////////////////////// @@ -995,7 +975,108 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector& embeddedItemLayout, InternalDataModel& internalDataModel ) +{ + //////////////////////////////////////////////////////////////////////////////// + // Layout the text. + //////////////////////////////////////////////////////////////////////////////// + Text::ModelPtr& textModel = internalDataModel.textModel; + Text::Layout::Engine& layoutEngine = internalDataModel.layoutEngine; + FontClient& fontClient = internalDataModel.fontClient; + const Length numberOfGlyphs = internalDataModel.numberOfGlyphs; + const bool isTextMirrored = internalDataModel.isTextMirrored; + const Vector& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters; + const Length numberOfCharacters = internalDataModel.numberOfCharacters; + + Layout::Type layout = Layout::SINGLELINE; + + Property::Value layoutStr( textParameters.layout ); + GetLayoutEnumeration( layoutStr, layout ); + + // 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. + + // Set minimun line size + layoutEngine.SetDefaultLineSize( textParameters.minLineSize ); + + // 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 ); + + // Set the layout parameters. + Size textLayoutArea = Size(static_cast(textParameters.textWidth), + static_cast(textParameters.textHeight)); + + // padding + Extents padding = textParameters.padding; + internalDataModel.textLayoutArea = Size(textLayoutArea.x - ( padding.start + padding.end ), textLayoutArea.y - ( padding.top + padding.bottom ) ); + + + if(isCircularTextLayout) + { + // In a circular layout, the length of the text area depends on the radius. + rendererParameters.radius = 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->mLineWrapMode = LineWrap::WORD; + textModel->mIgnoreSpacesAfterText = false; + textModel->mMatchSystemLanguageDirection = false; + Text::Layout::Parameters layoutParameters( internalDataModel.textLayoutArea, + textModel ); + + + // Whether the last character is a new paragraph character. + const Vector& textToShape = isTextMirrored ? mirroredUtf32Characters : textModel->mLogicalModel->mText; + 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; + layoutParameters.interGlyphExtraAdvance = 0.f; + + // Update the visual model. + Size newLayoutSize; + bool isAutoScrollEnabled = false; + layoutEngine.LayoutText( layoutParameters, + newLayoutSize, + textParameters.ellipsisEnabled, + isAutoScrollEnabled ); + + return newLayoutSize; + +} + + +Devel::PixelBuffer RenderText( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters ) +{ //////////////////////////////////////////////////////////////////////////////// // Render the text. //////////////////////////////////////////////////////////////////////////////// @@ -1007,6 +1088,94 @@ 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; + } + + FontClient fontClient = FontClient::Get(); + MetricsPtr metrics; + // Use this to access FontClient i.e. to get down-scaled Emoji metrics. + metrics = Metrics::New( fontClient ); + + Text::ModelPtr textModel = Text::Model::New(); + InternalDataModel internalData( fontClient, metrics, textModel ); + + TextAbstraction::TextRenderer::Parameters rendererParameters( internalData.textModel->mVisualModel->mGlyphs, + internalData.textModel->mVisualModel->mGlyphPositions, + internalData.textModel->mVisualModel->mColors, + internalData.textModel->mVisualModel->mColorIndices, + internalData.blendingMode, + internalData.isEmoji ); + + + rendererParameters.width = textParameters.textWidth; + rendererParameters.height = textParameters.textHeight; + rendererParameters.pixelFormat = TextAbstraction::TextRenderer::Parameters::RGBA8888; // @note: At the moment all textures are generated RGBA8888 + + + //////////////////////////////////////////////////////////////////////////////// + // Process the markup string if the mark-up processor is enabled. + //////////////////////////////////////////////////////////////////////////////// + ShapeTextPreprocess( textParameters, rendererParameters, internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyphs. Text shaping + //////////////////////////////////////////////////////////////////////////////// + ShapeText( rendererParameters, embeddedItemLayout, internalData ); + + + //////////////////////////////////////////////////////////////////////////////// + // Retrieve the glyph's metrics. + //////////////////////////////////////////////////////////////////////////////// + + metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), internalData.numberOfGlyphs ); + + //////////////////////////////////////////////////////////////////////////////// + // Set the color runs in glyphs. + //////////////////////////////////////////////////////////////////////////////// + SetColorSegmentation( textParameters, internalData ); + + + //////////////////////////////////////////////////////////////////////////////// + // Set the isEmoji Vector + //////////////////////////////////////////////////////////////////////////////// + SetEmojiVector( internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Layout the text + //////////////////////////////////////////////////////////////////////////////// + Size newLayoutSize = LayoutText( textParameters, rendererParameters, embeddedItemLayout, internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Align the text. + //////////////////////////////////////////////////////////////////////////////// + Align( textParameters, rendererParameters, embeddedItemLayout, internalData, newLayoutSize ); + + + //////////////////////////////////////////////////////////////////////////////// + // Ellipsis the text. + //////////////////////////////////////////////////////////////////////////////// + Ellipsis( textParameters, rendererParameters, embeddedItemLayout, internalData ); + + //////////////////////////////////////////////////////////////////////////////// + // Render the text. + //////////////////////////////////////////////////////////////////////////////// + return RenderText( textParameters, rendererParameters ); +} + + Devel::PixelBuffer CreateShadow( const ShadowParameters& shadowParameters ) { // The size of the pixel data. @@ -1316,6 +1485,96 @@ void UpdateBuffer(Devel::PixelBuffer src, Devel::PixelBuffer dst, unsigned int x } } + +Dali::Property::Array RenderForLastIndex( RendererParameters& textParameters ) +{ + Property::Array offsetValues; + if( textParameters.text.empty() ) + { + return offsetValues; + } + FontClient fontClient = FontClient::Get(); + MetricsPtr metrics; + metrics = Metrics::New( fontClient ); + + Text::ModelPtr textModel = Text::Model::New(); + InternalDataModel internalData( fontClient, metrics, textModel ); + + TextAbstraction::TextRenderer::Parameters rendererParameters( textModel->mVisualModel->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.padding.top + textParameters.padding.bottom); + 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; + float lineSize = internalData.layoutEngine.GetDefaultLineSize(); + float lineOffset = 0.f; + for( unsigned int index = 0u; index < numberOfLines; ++index ) + { + const LineRun& line = *( lines.Begin() + index ); + numberOfCharacters += line.characterRun.numberOfCharacters; + + lineOffset = lineSize > 0.f ? lineSize : ( line.ascender + -line.descender ); + penY += lineOffset; + if( ( penY + lineOffset ) > 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..86c44e8 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 @@ -45,19 +46,22 @@ struct DALI_TOOLKIT_API RendererParameters 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 } - {} + 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}, + minLineSize{0.f}, + padding{0u, 0u, 0u, 0u} + { + } std::string text; ///< The text to be rendered encoded in utf8. @@ -85,6 +89,10 @@ struct DALI_TOOLKIT_API RendererParameters 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. + + float minLineSize; ///< The line's minimum size (in points). + + Extents padding; ///< The padding of the boundaries where the text is going to be laid-out. }; /** @@ -192,6 +200,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 diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index 73f383f..4c3402d 100755 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -140,7 +140,8 @@ DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalLineAlignment DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textBackground", MAP, BACKGROUND ) DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "ignoreSpacesAfterText", BOOLEAN, IGNORE_SPACES_AFTER_TEXT ) DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "matchSystemLanguageDirection", BOOLEAN, MATCH_SYSTEM_LANGUAGE_DIRECTION ) -DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textFit", MAP, TEXT_FIT ) +DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textFit", MAP, TEXT_FIT ) +DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "minLineSize", FLOAT, MIN_LINE_SIZE ) DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR ) DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0 ) DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1 ) @@ -553,6 +554,19 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr } break; } + case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: + { + if( impl.mController ) + { + const float lineSize = value.Get(); + + if( impl.mController->SetDefaultLineSize( lineSize ) ) + { + impl.mTextUpdateNeeded = true; + } + } + break; + } } // Request relayout when text update is needed. It's necessary to call it @@ -834,6 +848,14 @@ Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index inde value = map; break; } + case Toolkit::DevelTextLabel::Property::MIN_LINE_SIZE: + { + if( impl.mController ) + { + value = impl.mController->GetDefaultLineSize(); + } + break; + } } } diff --git a/dali-toolkit/internal/text/layouts/layout-engine.cpp b/dali-toolkit/internal/text/layouts/layout-engine.cpp index 4246f96..3bd4568 100755 --- a/dali-toolkit/internal/text/layouts/layout-engine.cpp +++ b/dali-toolkit/internal/text/layouts/layout-engine.cpp @@ -52,7 +52,8 @@ namespace const float MAX_FLOAT = std::numeric_limits::max(); const CharacterDirection LTR = false; const CharacterDirection RTL = !LTR; -const float LINE_SPACING= 0.f; +const float LINE_SPACING = 0.f; +const float MIN_LINE_SIZE = 0.f; inline bool isEmptyLineAtLast( const Vector& lines, const Vector::Iterator& line ) { @@ -130,7 +131,8 @@ struct Engine::Impl Impl() : mLayout{ Layout::Engine::SINGLE_LINE_BOX }, mCursorWidth{ 0.f }, - mDefaultLineSpacing{ LINE_SPACING } + mDefaultLineSpacing{ LINE_SPACING }, + mDefaultLineSize{ MIN_LINE_SIZE } { } @@ -162,8 +164,12 @@ struct Engine::Impl // Sets the minimum descender. lineLayout.descender = std::min( lineLayout.descender, fontMetrics.descender ); - // set the line spacing - lineLayout.lineSpacing = mDefaultLineSpacing; + // Sets the line size + lineLayout.lineSpacing = mDefaultLineSize - ( lineLayout.ascender + -lineLayout.descender ); + lineLayout.lineSpacing = lineLayout.lineSpacing < 0.f ? 0.f : lineLayout.lineSpacing; + + // Add the line spacing + lineLayout.lineSpacing += mDefaultLineSpacing; } /** @@ -921,8 +927,6 @@ struct Engine::Impl lineRun.glyphRun.numberOfGlyphs = layout.numberOfGlyphs; lineRun.characterRun.characterIndex = layout.characterIndex; lineRun.characterRun.numberOfCharacters = layout.numberOfCharacters; - lineRun.lineSpacing = mDefaultLineSpacing; - lineRun.width = layout.length; lineRun.extraLength = std::ceil( layout.whiteSpaceLengthEndOfLine ); @@ -935,6 +939,12 @@ struct Engine::Impl lineRun.direction = layout.direction; lineRun.ellipsis = false; + lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender ); + lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing; + + lineRun.lineSpacing += mDefaultLineSpacing; + + // Update the actual size. if( lineRun.width > layoutSize.width ) { @@ -986,7 +996,11 @@ struct Engine::Impl lineRun.alignmentOffset = 0.f; lineRun.direction = LTR; lineRun.ellipsis = false; - lineRun.lineSpacing = mDefaultLineSpacing; + + lineRun.lineSpacing = mDefaultLineSize - ( lineRun.ascender + -lineRun.descender ); + lineRun.lineSpacing = lineRun.lineSpacing < 0.f ? 0.f : lineRun.lineSpacing; + + lineRun.lineSpacing += mDefaultLineSpacing; layoutSize.height += ( lineRun.ascender + -lineRun.descender ) + lineRun.lineSpacing; } @@ -1346,6 +1360,13 @@ struct Engine::Impl // Updates the vertical pen's position. penY += -layout.descender + layout.lineSpacing + mDefaultLineSpacing; + // If there is a defaultLineSize, updates the pen's position. + if( mDefaultLineSize > 0.f ) + { + float lineSpacing = mDefaultLineSize - ( layout.ascender + -layout.descender ); + lineSpacing = lineSpacing < 0.f ? 0.f : lineSpacing; + penY += lineSpacing; + } // Increase the glyph index. index = nextIndex; @@ -1551,6 +1572,7 @@ struct Engine::Impl Type mLayout; float mCursorWidth; float mDefaultLineSpacing; + float mDefaultLineSize; IntrusivePtr mMetrics; }; @@ -1632,6 +1654,16 @@ float Engine::GetDefaultLineSpacing() const return mImpl->mDefaultLineSpacing; } +void Engine::SetDefaultLineSize( float lineSize ) +{ + mImpl->mDefaultLineSize = lineSize; +} + +float Engine::GetDefaultLineSize() const +{ + return mImpl->mDefaultLineSize; +} + } // namespace Layout } // namespace Text diff --git a/dali-toolkit/internal/text/layouts/layout-engine.h b/dali-toolkit/internal/text/layouts/layout-engine.h index af693da..5641c47 100755 --- a/dali-toolkit/internal/text/layouts/layout-engine.h +++ b/dali-toolkit/internal/text/layouts/layout-engine.h @@ -152,6 +152,20 @@ public: */ float GetDefaultLineSpacing() const; + /** + * @brief Sets the default line size. + * + * @param[in] lineSize The line size. + */ + void SetDefaultLineSize( float lineSize ); + + /** + * @brief Retrieves the default line size. + * + * @return The line size. + */ + float GetDefaultLineSize() const; + private: // Undefined diff --git a/dali-toolkit/internal/text/rendering/text-typesetter.cpp b/dali-toolkit/internal/text/rendering/text-typesetter.cpp index 5b424be..0256a43 100755 --- a/dali-toolkit/internal/text/rendering/text-typesetter.cpp +++ b/dali-toolkit/internal/text/rendering/text-typesetter.cpp @@ -337,6 +337,7 @@ PixelData Typesetter::Render( const Vector2& size, Toolkit::DevelText::TextDirec case VerticalAlignment::CENTER: { penY = static_cast( 0.5f * ( size.height - layoutSize.height ) ); + penY = penY < 0.f ? 0.f : penY; break; } case VerticalAlignment::BOTTOM: diff --git a/dali-toolkit/internal/text/shaper.cpp b/dali-toolkit/internal/text/shaper.cpp old mode 100644 new mode 100755 index 593e1e5..de41d0e --- a/dali-toolkit/internal/text/shaper.cpp +++ b/dali-toolkit/internal/text/shaper.cpp @@ -117,8 +117,8 @@ void ShapeText( const Vector& text, const Length currentNumberOfGlyphs = glyphs.Count(); const Length numberOfGlyphsReserved = static_cast( numberOfCharacters * 1.3f ); - glyphs.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved, glyphInfo ); - glyphToCharacterMap.Resize( currentNumberOfGlyphs + numberOfGlyphsReserved ); + glyphs.Reserve( currentNumberOfGlyphs + numberOfGlyphsReserved ); + glyphToCharacterMap.Reserve( currentNumberOfGlyphs + numberOfGlyphsReserved ); // The actual number of glyphs. Length totalNumberOfGlyphs = currentNumberOfGlyphs; diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 6fd031f..694be22 100755 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -64,7 +64,6 @@ const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; -const unsigned int MAX_TEXT_LENGTH = 1024u * 32u; float ConvertToEven( float value ) { @@ -323,7 +322,7 @@ bool Controller::IsSmoothHandlePanEnabled() const void Controller::SetMaximumNumberOfCharacters( Length maxCharacters ) { - mImpl->mMaximumNumberOfCharacters = std::min( maxCharacters, MAX_TEXT_LENGTH ); + mImpl->mMaximumNumberOfCharacters = maxCharacters; } int Controller::GetMaximumNumberOfCharacters() @@ -704,13 +703,6 @@ void Controller::SetText( const std::string& text ) utf8 = reinterpret_cast( text.c_str() ); } - // Limit the text size. If the text size is too large, crash or deadlock will occur. - if( textSize > MAX_TEXT_LENGTH ) - { - DALI_LOG_WARNING( "The text size is too large(%d), limit the length to 32,768u\n", textSize ); - textSize = MAX_TEXT_LENGTH; - } - // Convert text into UTF-32 Vector& utf32Characters = mImpl->mModel->mLogicalModel->mText; utf32Characters.Resize( textSize ); @@ -1472,6 +1464,22 @@ float Controller::GetDefaultLineSpacing() const return mImpl->mLayoutEngine.GetDefaultLineSpacing(); } +bool Controller::SetDefaultLineSize( float lineSize ) +{ + if( std::fabs( lineSize - mImpl->mLayoutEngine.GetDefaultLineSize() ) > Math::MACHINE_EPSILON_1000 ) + { + mImpl->mLayoutEngine.SetDefaultLineSize(lineSize); + mImpl->mRecalculateNaturalSize = true; + return true; + } + return false; +} + +float Controller::GetDefaultLineSize() const +{ + return mImpl->mLayoutEngine.GetDefaultLineSize(); +} + void Controller::SetInputColor( const Vector4& color ) { if( NULL != mImpl->mEventData ) diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 4e3f5a0..497bf07 100755 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -1045,6 +1045,22 @@ public: // Default style & Input style float GetDefaultLineSpacing() const; /** + * @brief Sets the default line size. + * + * @param[in] lineSize The line size. + * + * @return True if lineSize has been updated, false otherwise + */ + bool SetDefaultLineSize( float lineSize ); + + /** + * @brief Retrieves the default line size. + * + * @return The line size. + */ + float GetDefaultLineSize() const; + + /** * @brief Sets the input text's color. * * @param[in] color The input text's color. diff --git a/dali-toolkit/internal/visuals/text/text-visual.cpp b/dali-toolkit/internal/visuals/text/text-visual.cpp index bd23926..43ab569 100755 --- a/dali-toolkit/internal/visuals/text/text-visual.cpp +++ b/dali-toolkit/internal/visuals/text/text-visual.cpp @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include // INTERNAL HEADER #include @@ -453,21 +456,32 @@ void TextVisual::DoSetOnStage( Actor& actor ) // Renderer needs textures and to be added to control mRendererUpdateNeeded = true; + mRendererList.push_back( mImpl->mRenderer ); + UpdateRenderer(); } -void TextVisual::DoSetOffStage( Actor& actor ) +void TextVisual::RemoveRenderer( Actor& actor ) { - if( mImpl->mRenderer ) + for( RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter) { - // Removes the renderer from the actor. - actor.RemoveRenderer( mImpl->mRenderer ); + Renderer renderer = (*iter); + if( renderer ) + { + // Removes the renderer from the actor. + actor.RemoveRenderer( renderer ); + } + } + // Clear the renderer list + mRendererList.clear(); +} - RemoveTextureSet(); +void TextVisual::DoSetOffStage( Actor& actor ) +{ + RemoveRenderer( actor ); - // Resets the renderer. - mImpl->mRenderer.Reset(); - } + // Resets the renderer. + mImpl->mRenderer.Reset(); // Resets the control handle. mControl.Reset(); @@ -597,14 +611,8 @@ void TextVisual::UpdateRenderer() if( ( fabsf( relayoutSize.width ) < Math::MACHINE_EPSILON_1000 ) || ( fabsf( relayoutSize.height ) < Math::MACHINE_EPSILON_1000 ) || text.empty() ) { - // Removes the texture set. - RemoveTextureSet(); - - // Remove any renderer previously set. - if( mImpl->mRenderer ) - { - control.RemoveRenderer( mImpl->mRenderer ); - } + // Remove the texture set and any renderer previously set. + RemoveRenderer( control ); // Nothing else to do if the relayout size is zero. ResourceReady( Toolkit::Visual::ResourceStatus::READY ); @@ -618,14 +626,8 @@ void TextVisual::UpdateRenderer() { mRendererUpdateNeeded = false; - // Removes the texture set. - RemoveTextureSet(); - - // Remove any renderer previously set. - if( mImpl->mRenderer ) - { - control.RemoveRenderer( mImpl->mRenderer ); - } + // Remove the texture set and any renderer previously set. + RemoveRenderer( control ); if( ( relayoutSize.width > Math::MACHINE_EPSILON_1000 ) && ( relayoutSize.height > Math::MACHINE_EPSILON_1000 ) ) @@ -668,48 +670,196 @@ void TextVisual::UpdateRenderer() const bool styleEnabled = ( shadowEnabled || underlineEnabled || outlineEnabled || backgroundEnabled ); - TextureSet textureSet = GetTextTexture( relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled ); - mImpl->mRenderer.SetTextures( textureSet ); - Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled ); - mImpl->mRenderer.SetShader(shader); + AddRenderer( control, relayoutSize, hasMultipleTextColors, containsColorGlyph, styleEnabled ); - mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; + // Text rendered and ready to display + ResourceReady( Toolkit::Visual::ResourceStatus::READY ); + } + } +} - mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast( hasMultipleTextColors ) ); +void TextVisual::AddTexture( TextureSet& textureSet, PixelData& data, Sampler& sampler, unsigned int textureSetIndex ) +{ + Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, + data.GetPixelFormat(), + data.GetWidth(), + data.GetHeight() ); + texture.Upload( data ); + + textureSet.SetTexture( textureSetIndex, texture ); + textureSet.SetSampler( textureSetIndex, sampler ); +} - mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON); +PixelData TextVisual::ConvertToPixelData( unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat ) +{ + int bpp = Pixel::GetBytesPerPixel( textPixelFormat ); + unsigned int bufferSize = width * height * bpp; + unsigned char* dstBuffer = static_cast( malloc ( bufferSize ) ); + memcpy( dstBuffer, buffer + offsetPosition * bpp, bufferSize ); + PixelData pixelData = Dali::PixelData::New( dstBuffer, + bufferSize, + width, + height, + textPixelFormat, + Dali::PixelData::FREE ); + return pixelData; +} - //Register transform properties - mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); +void TextVisual::CreateTextureSet( TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled ) +{ - control.AddRenderer( mImpl->mRenderer ); + TextureSet textureSet = TextureSet::New(); + unsigned int textureSetIndex = 0u; - // Text rendered and ready to display - ResourceReady( Toolkit::Visual::ResourceStatus::READY ); - } + // Convert the buffer to pixel data to make it a texture. + if( info.textBuffer ) + { + PixelData data = ConvertToPixelData( info.textBuffer, info.width, info.height, info.offsetPosition, info.textPixelFormat ); + AddTexture( textureSet, data, sampler, textureSetIndex ); + ++textureSetIndex; } + + if( styleEnabled && info.styleBuffer ) + { + PixelData styleData = ConvertToPixelData( info.styleBuffer, info.width, info.height, info.offsetPosition, Pixel::RGBA8888 ); + AddTexture( textureSet, styleData, sampler, textureSetIndex ); + ++textureSetIndex; + } + + if( containsColorGlyph && !hasMultipleTextColors && info.maskBuffer ) + { + PixelData maskData = ConvertToPixelData( info.maskBuffer, info.width, info.height, info.offsetPosition, Pixel::L8 ); + AddTexture( textureSet, maskData, sampler, textureSetIndex ); + } + + renderer.SetTextures( textureSet ); + + //Register transform properties + mImpl->mTransform.RegisterUniforms( renderer, Direction::LEFT_TO_RIGHT ); + + // Enable the pre-multiplied alpha to improve the text quality + renderer.SetProperty( Renderer::Property::BLEND_PRE_MULTIPLIED_ALPHA, true ); + renderer.RegisterProperty( PREMULTIPLIED_ALPHA, 1.0f ); + + // Set size and offset for the tiling. + renderer.RegisterProperty( SIZE, Vector2( info.width, info.height ) ); + renderer.RegisterProperty( OFFSET, Vector2( info.offSet.x, info.offSet.y ) ); + renderer.RegisterProperty( "uHasMultipleTextColors", static_cast( hasMultipleTextColors ) ); + renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON); + + mRendererList.push_back( renderer ); } -void TextVisual::RemoveTextureSet() + +void TextVisual::AddRenderer( Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled ) { - if( mImpl->mFlags & Impl::IS_ATLASING_APPLIED ) + Shader shader = GetTextShader( mFactoryCache, hasMultipleTextColors, containsColorGlyph, styleEnabled ); + mImpl->mRenderer.SetShader( shader ); + + // Get the maximum size. + const int maxTextureSize = Dali::GetMaxTextureSize(); + + // No tiling required. Use the default renderer. + if( size.height < maxTextureSize ) + { + TextureSet textureSet = GetTextTexture( size, hasMultipleTextColors, containsColorGlyph, styleEnabled ); + + mImpl->mRenderer.SetTextures( textureSet ); + //Register transform properties + mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT ); + mImpl->mRenderer.RegisterProperty( "uHasMultipleTextColors", static_cast( hasMultipleTextColors ) ); + mImpl->mRenderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON); + + mRendererList.push_back( mImpl->mRenderer ); + } + // If the pixel data exceeds the maximum size, tiling is required. + else { - // Removes the text's image from the texture atlas. - Vector4 atlasRect; + // Filter mode needs to be set to linear to produce better quality while scaling. + Sampler sampler = Sampler::New(); + sampler.SetFilterMode( FilterMode::LINEAR, FilterMode::LINEAR ); + + // Create RGBA texture if the text contains emojis or multiple text colors, otherwise L8 texture + Pixel::Format textPixelFormat = ( containsColorGlyph || hasMultipleTextColors ) ? Pixel::RGBA8888 : Pixel::L8; + + // Check the text direction + Toolkit::DevelText::TextDirection::Type textDirection = mController->GetTextDirection(); + + // Create a texture for the text without any styles + PixelData data = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_STYLES, false, textPixelFormat ); + + int verifiedWidth = data.GetWidth(); + int verifiedHeight = data.GetHeight(); + + // Set information for creating textures. + TilingInfo info( verifiedWidth, maxTextureSize, textPixelFormat ); + + // Get the buffer of text. + Dali::DevelPixelData::PixelDataBuffer textPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( data ); + info.textBuffer = textPixelData.buffer; + + if( styleEnabled ) + { + // Create RGBA texture for all the text styles (without the text itself) + PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 ); + Dali::DevelPixelData::PixelDataBuffer stylePixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( styleData ); + info.styleBuffer = stylePixelData.buffer; + } + + if ( containsColorGlyph && !hasMultipleTextColors ) + { + // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation + PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 ); + Dali::DevelPixelData::PixelDataBuffer maskPixelData = Dali::DevelPixelData::ReleasePixelDataBuffer( maskData ); + info.maskBuffer = maskPixelData.buffer; + } + + // Get the current offset for recalculate the offset when tiling. + Property::Map retMap; + mImpl->mTransform.GetPropertyMap( retMap ); + Vector2 offSet = retMap.Find( Dali::Toolkit::Visual::Transform::Property::OFFSET )->Get< Vector2 >(); + info.offSet = offSet; + + // Create a textureset in the default renderer. + CreateTextureSet( info, mImpl->mRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled ); - const Property::Index index = mImpl->mRenderer.GetPropertyIndex( ATLAS_RECT_UNIFORM_NAME ); - if( index != Property::INVALID_INDEX ) + verifiedHeight -= maxTextureSize; + + Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY ); + + int offsetPosition = verifiedWidth * maxTextureSize; + // Create a renderer by cutting maxTextureSize. + while( verifiedHeight > 0 ) { - const Property::Value& atlasRectValue = mImpl->mRenderer.GetProperty( index ); - atlasRectValue.Get( atlasRect ); + Renderer tilingRenderer = Renderer::New( geometry, shader ); + tilingRenderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, Toolkit::DepthIndex::CONTENT ); + // New offset position of buffer for tiling. + info.offsetPosition += offsetPosition; + // New height for tiling. + info.height = ( verifiedHeight - maxTextureSize ) > 0 ? maxTextureSize : verifiedHeight; + // New offset for tiling. + info.offSet.y += maxTextureSize; + // Create a textureset int the new tiling renderer. + CreateTextureSet( info, tilingRenderer, sampler, hasMultipleTextColors, containsColorGlyph, styleEnabled ); + + verifiedHeight -= maxTextureSize; + } + } + + mImpl->mFlags &= ~Impl::IS_ATLASING_APPLIED; - const TextureSet& textureSet = mImpl->mRenderer.GetTextures(); - mFactoryCache.GetAtlasManager()->Remove( textureSet, atlasRect ); + for( RendererContainer::iterator iter = mRendererList.begin(); iter != mRendererList.end(); ++iter) + { + Renderer renderer = (*iter); + if( renderer ) + { + actor.AddRenderer( renderer ); } } } + TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled ) { // Filter mode needs to be set to linear to produce better quality while scaling. @@ -729,31 +879,18 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText // It may happen the image atlas can't handle a pixel data it exceeds the maximum size. // In that case, create a texture. TODO: should tile the text. + unsigned int textureSetIndex = 0u; - Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D, - data.GetPixelFormat(), - data.GetWidth(), - data.GetHeight() ); - - texture.Upload( data ); - - textureSet.SetTexture( 0u, texture ); - textureSet.SetSampler( 0u, sampler ); + AddTexture( textureSet, data, sampler, textureSetIndex ); + ++textureSetIndex; if ( styleEnabled ) { // Create RGBA texture for all the text styles (without the text itself) PixelData styleData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_NO_TEXT, false, Pixel::RGBA8888 ); - Texture styleTexture = Texture::New( Dali::TextureType::TEXTURE_2D, - styleData.GetPixelFormat(), - styleData.GetWidth(), - styleData.GetHeight() ); - - styleTexture.Upload( styleData ); - - textureSet.SetTexture( 1u, styleTexture ); - textureSet.SetSampler( 1u, sampler ); + AddTexture( textureSet, styleData, sampler, textureSetIndex ); + ++textureSetIndex; } if ( containsColorGlyph && !hasMultipleTextColors ) @@ -761,23 +898,7 @@ TextureSet TextVisual::GetTextTexture( const Vector2& size, bool hasMultipleText // Create a L8 texture as a mask to avoid color glyphs (e.g. emojis) to be affected by text color animation PixelData maskData = mTypesetter->Render( size, textDirection, Text::Typesetter::RENDER_MASK, false, Pixel::L8 ); - Texture maskTexture = Texture::New( Dali::TextureType::TEXTURE_2D, - maskData.GetPixelFormat(), - maskData.GetWidth(), - maskData.GetHeight() ); - - maskTexture.Upload( maskData ); - - if ( !styleEnabled ) - { - textureSet.SetTexture( 1u, maskTexture ); - textureSet.SetSampler( 1u, sampler ); - } - else - { - textureSet.SetTexture( 2u, maskTexture ); - textureSet.SetSampler( 2u, sampler ); - } + AddTexture( textureSet, maskData, sampler, textureSetIndex ); } return textureSet; diff --git a/dali-toolkit/internal/visuals/text/text-visual.h b/dali-toolkit/internal/visuals/text/text-visual.h old mode 100644 new mode 100755 index 6f47e45..16da39a --- a/dali-toolkit/internal/visuals/text/text-visual.h +++ b/dali-toolkit/internal/visuals/text/text-visual.h @@ -182,6 +182,48 @@ protected: void OnSetTransform() override; private: + + struct TilingInfo + { + unsigned char* textBuffer; + unsigned char* styleBuffer; + unsigned char* maskBuffer; + int width; + int height; + Pixel::Format textPixelFormat; + int offsetPosition; + Vector2 offSet; + + TilingInfo( int width, int height, Pixel::Format textPixelFormat ) + : textBuffer( NULL ), + styleBuffer( NULL ), + maskBuffer( NULL ), + width( width ), + height( height ), + textPixelFormat( textPixelFormat ), + offsetPosition( 0 ), + offSet( 0.f, 0.f ) + { + } + + ~TilingInfo() + { + if( textBuffer ) + { + free( textBuffer ); + } + if( styleBuffer ) + { + free( styleBuffer ); + } + if( maskBuffer ) + { + free( maskBuffer ); + } + } + + }; + /** * @brief Set the individual property to the given value. * @@ -197,9 +239,50 @@ private: void UpdateRenderer(); /** - * @brief Removes the texture set from the renderer. + * @brief Removes the text's renderer. + */ + void RemoveRenderer( Actor& actor ); + + /** + * @brief Create a texture in textureSet and add it. + * @param[in] textureSet The textureSet to which the texture will be added. + * @param[in] data The PixelData to be uploaded to texture + * @param[in] sampler The sampler. + * @param[in] textureSetIndex The Index of TextureSet. + */ + void AddTexture( TextureSet& textureSet, PixelData& data, Sampler& sampler, unsigned int textureSetIndex ); + + /** + * @brief Convert the buffer to pixelData. + * @param[in] buffer The Buffer to be converted to pixelData. + * @param[in] width The width of pixel data. + * @param[in] height The height of pixel data. + * @param[in] offsetPosition The The buffer's start position. + * @param[in] textPixelFormat The PixelForma of text. + */ + PixelData ConvertToPixelData( unsigned char* buffer, int width, int height, int offsetPosition, const Pixel::Format textPixelFormat ); + + /** + * @brief Create the text's texture. + * @param[in] info This is the information you need to create a Tiling. + * @param[in] renderer The renderer to which the TextureSet will be added. + * @param[in] sampler The sampler. + * @param[in] hasMultipleTextColors Whether the text contains multiple colors. + * @param[in] containsColorGlyph Whether the text contains color glyph. + * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.). */ - void RemoveTextureSet(); + void CreateTextureSet( TilingInfo& info, Renderer& renderer, Sampler& sampler, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled ); + + /** + * Create renderer of the text for rendering. + * @param[in] actor The actor. + * @param[in] size The texture size. + * @param[in] hasMultipleTextColors Whether the text contains multiple colors. + * @param[in] containsColorGlyph Whether the text contains color glyph. + * @param[in] styleEnabled Whether the text contains any styles (e.g. shadow, underline, etc.). + */ + void AddRenderer( Actor& actor, const Vector2& size, bool hasMultipleTextColors, bool containsColorGlyph, bool styleEnabled ); + /** * Get the texture of the text for rendering. @@ -231,6 +314,8 @@ private: private: + typedef std::vector< Renderer > RendererContainer; + /** * Used as an alternative to boolean so that it is obvious whether the text contains single or multiple text colors, and emoji and styles. */ @@ -247,12 +332,14 @@ private: }; }; + private: Text::ControllerPtr mController; ///< The text's controller. Text::TypesetterPtr mTypesetter; ///< The text's typesetter. WeakHandle mControl; ///< The control where the renderer is added. Property::Index mAnimatableTextColorPropertyIndex; ///< The index of animatable text color property registered by the control. bool mRendererUpdateNeeded:1; ///< The flag to indicate whether the renderer needs to be updated. + RendererContainer mRendererList; }; } // namespace Internal -- 2.7.4