Merge "(Automated Tests) Changes after Window changes in Adaptor" into devel/master
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Mon, 13 Jul 2020 21:42:07 +0000 (21:42 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 13 Jul 2020 21:42:07 +0000 (21:42 +0000)
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextLabel.cpp
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/devel-api/text/text-utils-devel.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h

index 90bb27b..10f7dfa 100644 (file)
@@ -270,6 +270,8 @@ int UtcDaliAnimatedVectorImageVisualGetPropertyMap01(void)
   application.SendNotification();
   application.Render();
 
+  std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );    // wait for next rasterize thread run
+
   Property::Map resultMap;
   resultMap = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
 
@@ -679,6 +681,8 @@ int UtcDaliAnimatedVectorImageVisualPlayRange(void)
   application.SendNotification();
   application.Render();
 
+  std::this_thread::sleep_for( std::chrono::milliseconds( 20 ) );    // wait for next rasterize thread run
+
   map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
   value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
 
index 4fa21f8..07052fc 100755 (executable)
@@ -29,6 +29,7 @@
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali-toolkit/devel-api/text/bitmap-font.h>
 #include <dali-toolkit/devel-api/text/rendering-backend.h>
+#include <dali-toolkit/devel-api/text/text-utils-devel.h>
 
 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<int>(), 10, TEST_LOCATION );
+
+  END_TEST;
+}
\ No newline at end of file
index fc8afb9..c39cb21 100755 (executable)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/devel-api/scripting/enum-helper.h>
 #include <cstring>
+#include <limits>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
@@ -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<int>::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<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
+  Vector<bool> isEmoji;                          ///< Whether the glyph is an emoji.
+
+  Vector<Character> 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,38 @@ 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<EmbeddedItemInfo>& 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;
-  }
+void ShapeTextPreprocess( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters, InternalDataModel& internalDataModel )
+{
 
   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<ColorBlendingMode> blendingMode;        ///< How embedded items and bitmap font glyphs are blended with color text.
-  Vector<bool> 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<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
 
   Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
-  Vector<Character> mirroredUtf32Characters;                                                                        // The utf32Characters Characters but mirrored if there are RTL text.
   Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
   Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
   Vector<FontDescriptionRun>& fontDescriptionRuns = textModel->mLogicalModel->mFontDescriptionRuns;                 // Desired font descriptions.
   Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
   Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = textModel->mLogicalModel->mBidirectionalParagraphInfo; // The bidirectional info per paragraph.
-  //Vector<BidirectionalLineInfoRun>& bidirectionalLineInfo = textModel->mLogicalModel->mBidirectionalLineInfo;     // The bidirectional info per line.
   Vector<CharacterDirection>& directions = textModel->mLogicalModel->mCharacterDirections;                          // Character's directions.
   Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
 
-  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
-  Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
-  Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
-  Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
-  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                                                         // The laid out lines.
-
-  Vector<GlyphIndex> 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 +223,9 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   ////////////////////////////////////////////////////////////////////////////////
 
   multilanguageSupport.SetScripts( utf32Characters,
-                                   0u,
-                                   numberOfCharacters,
-                                   scripts );
+                                  0u,
+                                  numberOfCharacters,
+                                  scripts );
 
   // Check if there are emojis.
   // If there are an RGBA8888 pixel format is needed.
@@ -330,13 +321,30 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     // 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,
+    internalDataModel.isTextMirrored = GetMirroredText( utf32Characters,
                                       directions,
                                       bidirectionalInfo,
                                       0u,
                                       numberOfCharacters,
                                       mirroredUtf32Characters );
   }
+}
+
+void ShapeText( TextAbstraction::TextRenderer::Parameters& rendererParameters, Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel )
+{
+  Vector<GlyphIndex> newParagraphGlyphs;                   // Glyphs for the new paragraph characters.
+  const Length numberOfCharacters = internalDataModel.numberOfCharacters;
+  const bool isTextMirrored = internalDataModel.isTextMirrored;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  const Vector<Character>& mirroredUtf32Characters = internalDataModel.mirroredUtf32Characters;
+  FontClient& fontClient = internalDataModel.fontClient;
+  const Vector<Character>& utf32Characters = textModel->mLogicalModel->mText;                                             // Characters encoded in utf32.
+  const Vector<LineBreakInfo>& lineBreakInfo = textModel->mLogicalModel->mLineBreakInfo;                                  // The line break info.
+  const Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
+  const Vector<FontRun>& validFonts = textModel->mLogicalModel->mFontRuns;                                                // Validated fonts.
+
+  Vector<CharacterIndex>& glyphsToCharacters = textModel->mVisualModel->mGlyphsToCharacters;                        // Glyphs to character map.
+  Vector<Length>& charactersPerGlyph = textModel->mVisualModel->mCharactersPerGlyph;                                // Number of characters per glyph.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Retrieve the glyphs. Text shaping
@@ -363,7 +371,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   textModel->mVisualModel->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 +410,18 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       embeddedItemLayout.PushBack( embeddedInfo );
     }
   }
+}
 
-  ////////////////////////////////////////////////////////////////////////////////
-  // Retrieve the glyph's metrics.
-  ////////////////////////////////////////////////////////////////////////////////
+void SetColorSegmentation( const RendererParameters& textParameters, InternalDataModel& internalDataModel )
+{
+
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  Vector<ColorBlendingMode>& blendingMode = internalDataModel.blendingMode;
+
+  Vector<ColorRun>& colorRuns = textModel->mLogicalModel->mColorRuns;                                               // colors of the text.
 
-  metrics->GetGlyphMetrics( rendererParameters.glyphs.Begin(), numberOfGlyphs );
+  Vector<GlyphIndex>& charactersToGlyph = textModel->mVisualModel->mCharactersToGlyph;                              // Characters to glyphs map.
+  Vector<Length>& glyphsPerCharacter = textModel->mVisualModel->mGlyphsPerCharacter;                                // The number of glyphs that are shaped.
 
   ////////////////////////////////////////////////////////////////////////////////
   // Set the color runs in glyphs.
@@ -418,7 +432,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
                             glyphsPerCharacter,
                             0u,
                             0u,
-                            numberOfCharacters,
+                            internalDataModel.numberOfCharacters,
                             textModel->mVisualModel->mColors,
                             textModel->mVisualModel->mColorIndices );
 
@@ -426,7 +440,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   textModel->mVisualModel->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 +464,15 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     const GlyphIndex glyphIndex = textModel->mVisualModel->mCharactersToGlyph[item.characterIndex];
     blendingMode[glyphIndex] = item.colorBlendingMode;
   }
+}
+
+void SetEmojiVector( InternalDataModel& internalDataModel )
+{
+  Vector<bool>& isEmoji = internalDataModel.isEmoji;
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  const Length numberOfGlyphs = internalDataModel.numberOfGlyphs;
 
+  const Vector<ScriptRun>& scripts = textModel->mLogicalModel->mScriptRuns;                                               // Charactes's script.
   ////////////////////////////////////////////////////////////////////////////////
   // Set the isEmoji Vector
   ////////////////////////////////////////////////////////////////////////////////
@@ -471,18 +493,32 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
+}
+
+
+void Align( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+            Vector<EmbeddedItemInfo>& 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<LineRun>& 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 +526,16 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   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.
-
+  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 );
 
-  // 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<unsigned int>( maxAscenderDescender );
-
   // Convert CircularAlignment to HorizontalAlignment.
   if( isCircularTextLayout )
   {
@@ -546,49 +558,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
-
-  // Set the layout parameters.
-  Size textLayoutArea( static_cast<float>( textParameters.textWidth ),
-                     static_cast<float>( 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<float>( 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 +654,14 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       {
         const bool isNeg = textParameters.incrementAngle < 0.f;
         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        angleOffset = ( isNeg ? -0.5f : 0.5f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( rendererParameters.radius );
         break;
       }
       case CircularAlignment::END:
       {
         const bool isNeg = textParameters.incrementAngle < 0.f;
         const float textWidth = static_cast<float>( rendererParameters.circularWidth );
-        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( radius );
+        angleOffset = ( isNeg ? -1.f : 1.f ) * ( textLayoutArea.width - textWidth ) / static_cast<float>( rendererParameters.radius );
         break;
       }
     }
@@ -730,7 +700,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     }
 
     // Calculate the horizontal offset according with the given alignment.
-  float alignmentOffset = 0.f;
+    float alignmentOffset = 0.f;
     layoutEngine.Align( textLayoutArea,
                       0u,
                       numberOfCharacters,
@@ -742,10 +712,10 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
     // Update the position of the glyphs with the calculated offsets.
     for( auto& position : rendererParameters.positions )
-  {
-    position.x += line.alignmentOffset;
-    position.y = penY;
-  }
+    {
+      position.x += line.alignmentOffset;
+      position.y = penY;
+    }
   }
 
   // Cairo adds the bearing to the position of the glyph
@@ -780,7 +750,7 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
 
       Dali::TextAbstraction::CircularTextParameters circularTextParameters;
 
-      circularTextParameters.radius = static_cast<double>( radius );
+      circularTextParameters.radius = static_cast<double>( rendererParameters.radius );
       circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
       circularTextParameters.beginAngle = static_cast<double>( -rendererParameters.beginAngle + Dali::Math::PI_2 );
       circularTextParameters.centerX = 0.5f * static_cast<double>( textParameters.textWidth );
@@ -845,6 +815,17 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
     }
   }
 
+}
+
+void Ellipsis(  const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+               Vector<EmbeddedItemInfo>& embeddedItemLayout, InternalDataModel& internalDataModel )
+{
+  Text::ModelPtr& textModel = internalDataModel.textModel;
+  FontClient& fontClient = internalDataModel.fontClient;
+
+  Vector<LineRun>& lines = textModel->mVisualModel->mLines;                              // The laid out lines.
+  Vector<bool>& isEmoji = internalDataModel.isEmoji;
+  const Size textLayoutArea = internalDataModel.textLayoutArea;
   ////////////////////////////////////////////////////////////////////////////////
   // Ellipsis the text.
   ////////////////////////////////////////////////////////////////////////////////
@@ -995,7 +976,100 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
       }
     }
   }
+}
 
+Size LayoutText( const RendererParameters& textParameters, TextAbstraction::TextRenderer::Parameters& rendererParameters,
+                 Vector<EmbeddedItemInfo>& 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<Character>& 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.
+
+  // 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<unsigned int>( maxAscenderDescender );
+
+  // Set the layout parameters.
+  internalDataModel.textLayoutArea = Size( static_cast<float>( textParameters.textWidth ),
+                                           static_cast<float>( textParameters.textHeight ) );
+
+  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<float>( 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<Character>& 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 +1081,94 @@ Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<Embe
   return renderer.Render( rendererParameters );
 }
 
+
+Devel::PixelBuffer Render( const RendererParameters& textParameters, Vector<EmbeddedItemInfo>& 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 +1478,92 @@ 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<Dali::Toolkit::DevelText::EmbeddedItemInfo> 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<LineRun>& 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
index 83c6ea9..0670e8e 100755 (executable)
@@ -19,6 +19,7 @@
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
 #include <dali-toolkit/public-api/dali-toolkit-common.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
@@ -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
index 55968e1..bae4fbc 100644 (file)
@@ -70,7 +70,6 @@ VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, cons
   mAnimationDataIndex( 0 ),
   mLoopCount( LOOP_FOREVER ),
   mCurrentLoop( 0 ),
-  mResourceReady( false ),
   mForward( true ),
   mUpdateFrameNumber( false ),
   mNeedAnimationFinishedTrigger( true ),
@@ -138,8 +137,6 @@ void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
     mWidth = width;
     mHeight = height;
 
-    mResourceReady = false;
-
     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
   }
 }
@@ -148,6 +145,7 @@ void VectorAnimationTask::PlayAnimation()
 {
   if( mPlayState != PlayState::PLAYING )
   {
+    mNeedAnimationFinishedTrigger = true;
     mUpdateFrameNumber = false;
     mPlayState = PlayState::PLAYING;
 
@@ -266,12 +264,10 @@ void VectorAnimationTask::SetPlayRange( const Property::Array& playRange )
       if( mStartFrame > mCurrentFrame )
       {
         mCurrentFrame = mStartFrame;
-        mResourceReady = false;
       }
       else if( mEndFrame < mCurrentFrame )
       {
         mCurrentFrame = mEndFrame;
-        mResourceReady = false;
       }
 
       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
@@ -302,7 +298,6 @@ void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
   {
     mCurrentFrame = frameNumber;
     mUpdateFrameNumber = false;
-    mResourceReady = false;
 
     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
   }
@@ -394,10 +389,7 @@ bool VectorAnimationTask::Rasterize()
 
   currentFrame = mCurrentFrame;
 
-  // Reset values
-  mResourceReady = true;
   mUpdateFrameNumber = true;
-  mNeedAnimationFinishedTrigger = true;
 
   if( mPlayState == PlayState::STOPPING )
   {
@@ -462,11 +454,6 @@ bool VectorAnimationTask::Rasterize()
     {
       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
       mUpdateFrameNumber = false;
-
-      if( !mResourceReady )
-      {
-        mResourceReady = false;
-      }
     }
   }
 
index 79c3ee2..844d378 100644 (file)
@@ -309,7 +309,6 @@ private:
   uint32_t                               mAnimationDataIndex;
   int32_t                                mLoopCount;
   int32_t                                mCurrentLoop;
-  bool                                   mResourceReady;
   bool                                   mForward;
   bool                                   mUpdateFrameNumber;
   bool                                   mNeedAnimationFinishedTrigger;
index 8403e6a..c80e00a 100644 (file)
@@ -59,6 +59,7 @@ Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging,
 VectorAnimationThread::VectorAnimationThread()
 : mAnimationTasks(),
   mCompletedTasks(),
+  mWorkingTasks(),
   mRasterizers( GetNumberOfThreads( NUMBER_OF_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_RASTERIZE_THREADS ), [&]() { return RasterizeHelper( *this ); } ),
   mSleepThread( MakeCallback( this, &VectorAnimationThread::OnAwakeFromSleep ) ),
   mConditionalWait(),
@@ -75,6 +76,7 @@ VectorAnimationThread::~VectorAnimationThread()
   {
     ConditionalWait::ScopedLock lock( mConditionalWait );
     mDestroyThread = true;
+    mNeedToSleep = false;
     mConditionalWait.Notify( lock );
   }
 
@@ -108,6 +110,7 @@ void VectorAnimationThread::AddTask( VectorAnimationTaskPtr task )
       mAnimationTasks.push_back( task );
     }
 
+    mNeedToSleep = false;
     // wake up the animation thread
     mConditionalWait.Notify( lock );
   }
@@ -115,14 +118,35 @@ void VectorAnimationThread::AddTask( VectorAnimationTaskPtr task )
 
 void VectorAnimationThread::OnTaskCompleted( VectorAnimationTaskPtr task, bool keepAnimation )
 {
-  if( keepAnimation && !mDestroyThread )
+  if( !mDestroyThread )
   {
     ConditionalWait::ScopedLock lock( mConditionalWait );
+    bool needRasterize = false;
+
+    auto workingTask = std::find( mWorkingTasks.begin(), mWorkingTasks.end(), task );
+    if( workingTask != mWorkingTasks.end() )
+    {
+      mWorkingTasks.erase( workingTask );
+    }
 
-    if( mCompletedTasks.end() == std::find( mCompletedTasks.begin(), mCompletedTasks.end(), task ) )
+    // Check pending task
+    if( mAnimationTasks.end() != std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
     {
-      mCompletedTasks.push_back( task );
+      needRasterize = true;
+    }
+
+    if( keepAnimation )
+    {
+      if( mCompletedTasks.end() == std::find( mCompletedTasks.begin(), mCompletedTasks.end(), task ) )
+      {
+        mCompletedTasks.push_back( task );
+        needRasterize = true;
+      }
+    }
 
+    if( needRasterize )
+    {
+      mNeedToSleep = false;
       // wake up the animation thread
       mConditionalWait.Notify( lock );
     }
@@ -156,12 +180,12 @@ void VectorAnimationThread::Rasterize()
   ConditionalWait::ScopedLock lock( mConditionalWait );
 
   // conditional wait
-  if( (mAnimationTasks.empty() && mCompletedTasks.empty() ) || mNeedToSleep )
+  if( mNeedToSleep )
   {
     mConditionalWait.Wait( lock );
   }
 
-  mNeedToSleep = false;
+  mNeedToSleep = true;
 
   // Process completed tasks
   for( auto&& task : mCompletedTasks )
@@ -192,10 +216,9 @@ void VectorAnimationThread::Rasterize()
   mCompletedTasks.clear();
 
   // pop out the next task from the queue
-  while( !mAnimationTasks.empty() && !mNeedToSleep )
+  for( auto it = mAnimationTasks.begin(); it != mAnimationTasks.end(); )
   {
-    std::vector< VectorAnimationTaskPtr >::iterator next = mAnimationTasks.begin();
-    VectorAnimationTaskPtr nextTask = *next;
+    VectorAnimationTaskPtr nextTask = *it;
 
     auto currentTime = std::chrono::system_clock::now();
     auto nextFrameTime = nextTask->GetNextFrameTime();
@@ -208,17 +231,28 @@ void VectorAnimationThread::Rasterize()
 
     if( nextFrameTime <= currentTime )
     {
-      mAnimationTasks.erase( next );
+      // If the task is not in the working list
+      if( std::find( mWorkingTasks.begin(), mWorkingTasks.end(), nextTask ) == mWorkingTasks.end() )
+      {
+        it = mAnimationTasks.erase( it );
+
+        // Add it to the working list
+        mWorkingTasks.push_back( nextTask );
 
-      auto rasterizerHelperIt = mRasterizers.GetNext();
-      DALI_ASSERT_ALWAYS( rasterizerHelperIt != mRasterizers.End() );
+        auto rasterizerHelperIt = mRasterizers.GetNext();
+        DALI_ASSERT_ALWAYS( rasterizerHelperIt != mRasterizers.End() );
 
-      rasterizerHelperIt->Rasterize( nextTask );
+        rasterizerHelperIt->Rasterize( nextTask );
+      }
+      else
+      {
+        it++;
+      }
     }
     else
     {
-      mNeedToSleep = true;
       mSleepThread.SleepUntil( nextFrameTime );
+      break;
     }
   }
 }
index 8d3dd64..964f662 100755 (executable)
@@ -183,6 +183,7 @@ private:
 
   std::vector< VectorAnimationTaskPtr >      mAnimationTasks;
   std::vector< VectorAnimationTaskPtr >      mCompletedTasks;
+  std::vector< VectorAnimationTaskPtr >      mWorkingTasks;
   RoundRobinContainerView< RasterizeHelper > mRasterizers;
   SleepThread                                mSleepThread;
   ConditionalWait                            mConditionalWait;