Merge "TextController - Update the text model." into devel/master
authorPaul Wisbey <p.wisbey@samsung.com>
Thu, 21 Apr 2016 14:59:26 +0000 (07:59 -0700)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Thu, 21 Apr 2016 14:59:27 +0000 (07:59 -0700)
1  2 
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/text-controller-impl.cpp

@@@ -24,9 -24,8 +24,9 @@@
  #include <dali/devel-api/text-abstraction/font-client.h>
  
  // INTERNAL INCLUDES
 -#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
  #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
 +#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
 +#include <dali-toolkit/internal/text/layouts/layout-parameters.h>
  
  namespace Dali
  {
@@@ -48,26 -47,6 +48,6 @@@ const float MAX_FLOAT = std::numeric_li
  const bool RTL = true;
  const float CURSOR_WIDTH = 1.f;
  
- Length CountParagraphs( const LayoutParameters& layoutParameters )
- {
-   Length numberOfParagraphs = 0u;
-   const CharacterIndex startCharacterIndex = *( layoutParameters.glyphsToCharactersBuffer + layoutParameters.startGlyphIndex );
-   const GlyphIndex lastGlyphIndex = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs - 1u;
-   const CharacterIndex lastCharacterIndexPlusOne = *( layoutParameters.glyphsToCharactersBuffer + lastGlyphIndex ) + *( layoutParameters.charactersPerGlyphBuffer + lastGlyphIndex );
-   for( CharacterIndex index = startCharacterIndex; index < lastCharacterIndexPlusOne; ++index )
-   {
-     if( TextAbstraction::LINE_MUST_BREAK == *( layoutParameters.lineBreakInfoBuffer + index ) )
-     {
-       ++numberOfParagraphs;
-     }
-   }
-   return numberOfParagraphs;
- }
  } //namespace
  
  /**
@@@ -215,81 -194,59 +195,81 @@@ struct LayoutEngine::Imp
      LineLayout tmpLineLayout;
  
      const bool isMultiline = mLayout == MULTI_LINE_BOX;
 -    const GlyphIndex lastGlyphIndex = parameters.totalNumberOfGlyphs - 1u;
 +
 +    // The last glyph to be laid-out.
 +    const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
  
      // If the first glyph has a negative bearing its absolute value needs to be added to the line length.
      // In the case the line starts with a right to left character, if the width is longer than the advance,
      // the difference needs to be added to the line length.
 -    const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + lineLayout.glyphIndex );
 +
 +    // Check whether the first glyph comes from a character that is shaped in multiple glyphs.
 +    const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( lineLayout.glyphIndex,
 +                                                                   lastGlyphOfParagraphPlusOne,
 +                                                                   parameters.charactersPerGlyphBuffer );
 +
 +    GlyphMetrics glyphMetrics;
 +    GetGlyphsMetrics( lineLayout.glyphIndex,
 +                      numberOfGLyphsInGroup,
 +                      glyphMetrics,
 +                      parameters.glyphsBuffer,
 +                      mMetrics );
  
      // Set the direction of the first character of the line.
      lineLayout.characterIndex = *( parameters.glyphsToCharactersBuffer + lineLayout.glyphIndex );
      const CharacterDirection firstCharacterDirection = ( NULL == parameters.characterDirectionBuffer ) ? false : *( parameters.characterDirectionBuffer + lineLayout.characterIndex );
      CharacterDirection previousCharacterDirection = firstCharacterDirection;
  
 -    const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
 +    const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
      float tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
  
 -    float tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
 +    float tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
  
      tmpLineLayout.length += mCursorWidth; // Added to give some space to the cursor.
  
      // Calculate the line height if there is no characters.
 -    FontId lastFontId = glyphInfo.fontId;
 +    FontId lastFontId = glyphMetrics.fontId;
      UpdateLineHeight( lastFontId, tmpLineLayout );
  
      bool oneWordLaidOut = false;
  
 -    const GlyphIndex lastGlyphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
      for( GlyphIndex glyphIndex = lineLayout.glyphIndex;
 -         glyphIndex < lastGlyphPlusOne;
 -         ++glyphIndex )
 +         glyphIndex < lastGlyphOfParagraphPlusOne; )
      {
        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  glyph index : %d\n", glyphIndex );
 -      const bool isLastGlyph = glyphIndex == lastGlyphIndex;
  
 -      // Get the glyph info.
 -      const GlyphInfo& glyphInfo = *( parameters.glyphsBuffer + glyphIndex );
 +      // Check whether this glyph comes from a character that is shaped in multiple glyphs.
 +      const Length numberOfGLyphsInGroup = GetNumberOfGlyphsOfGroup( glyphIndex,
 +                                                                     lastGlyphOfParagraphPlusOne,
 +                                                                     parameters.charactersPerGlyphBuffer );
 +
 +      GlyphMetrics glyphMetrics;
 +      GetGlyphsMetrics( glyphIndex,
 +                        numberOfGLyphsInGroup,
 +                        glyphMetrics,
 +                        parameters.glyphsBuffer,
 +                        mMetrics );
 +
 +      const bool isLastGlyph = glyphIndex + numberOfGLyphsInGroup  == parameters.totalNumberOfGlyphs;
  
        // Check if the font of the current glyph is the same of the previous one.
        // If it's different the ascender and descender need to be updated.
 -      if( lastFontId != glyphInfo.fontId )
 +      if( lastFontId != glyphMetrics.fontId )
        {
 -        UpdateLineHeight( glyphInfo.fontId, tmpLineLayout );
 -        lastFontId = glyphInfo.fontId;
 +        UpdateLineHeight( glyphMetrics.fontId, tmpLineLayout );
 +        lastFontId = glyphMetrics.fontId;
        }
  
        // Get the character indices for the current glyph. The last character index is needed
        // because there are glyphs formed by more than one character but their break info is
        // given only for the last character.
 -      const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex );
 +      const Length charactersPerGlyph = *( parameters.charactersPerGlyphBuffer + glyphIndex + numberOfGLyphsInGroup - 1u );
 +      const bool hasCharacters = charactersPerGlyph > 0u;
        const CharacterIndex characterFirstIndex = *( parameters.glyphsToCharactersBuffer + glyphIndex );
 -      const CharacterIndex characterLastIndex = characterFirstIndex + ( ( 1u > charactersPerGlyph ) ? 0u : charactersPerGlyph - 1u );
 +      const CharacterIndex characterLastIndex = characterFirstIndex + ( hasCharacters ? charactersPerGlyph - 1u : 0u );
  
        // Get the line break info for the current character.
 -      const LineBreakInfo lineBreakInfo = *( parameters.lineBreakInfoBuffer + characterLastIndex );
 +      const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
  
        // Get the word break info for the current character.
        const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
        tmpLineLayout.numberOfCharacters += charactersPerGlyph;
  
        // Increase the number of glyphs.
 -      tmpLineLayout.numberOfGlyphs++;
 +      tmpLineLayout.numberOfGlyphs += numberOfGLyphsInGroup;
  
        // Check whether is a white space.
        const Character character = *( parameters.textBuffer + characterFirstIndex );
        if( isWhiteSpace )
        {
          // Add the length to the length of white spaces at the end of the line.
 -        tmpLineLayout.wsLengthEndOfLine += glyphInfo.advance; // The advance is used as the width is always zero for the white spaces.
 +        tmpLineLayout.wsLengthEndOfLine += glyphMetrics.advance; // The advance is used as the width is always zero for the white spaces.
        }
        else
        {
          // Add as well any previous white space length.
 -        tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphInfo.advance;
 +        tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine + glyphMetrics.advance;
  
          // An extra space may be added to the line for the first and last glyph of the line.
          // If the bearing of the first glyph is negative, its positive value needs to be added.
              // |     Rll|
              //
  
 -            tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
 +            tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
            }
            else // LTR
            {
              // |rrL     |
              //
  
 -            const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
 +            const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
              tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
            }
          }
                //  -->
                // |lllR    |
  
 -              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
 +              const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
                tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
              }
              else // LTR
                //       <--
                // |   Lrrrr|
  
 -              tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
 +              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
              }
            }
            else if( characterDirection == firstCharacterDirection )
                // |llllllrr|
                // |Rr      |
  
 -              tmpExtraBearing = ( 0.f > glyphInfo.xBearing ) ? -glyphInfo.xBearing : 0.f;
 +              tmpExtraBearing = ( 0.f > glyphMetrics.xBearing ) ? -glyphMetrics.xBearing : 0.f;
              }
              else // LTR
              {
                // |llllrrrr|
                // |     llL|
  
 -              const float extraWidth = glyphInfo.xBearing + glyphInfo.width - glyphInfo.advance;
 +              const float extraWidth = glyphMetrics.xBearing + glyphMetrics.width - glyphMetrics.advance;
                tmpExtraWidth = ( 0.f < extraWidth ) ? extraWidth : 0.f;
              }
            }
            if( tmpLineLayout.numberOfGlyphs > 0u )
            {
              tmpLineLayout.numberOfCharacters -= charactersPerGlyph;
 -            --tmpLineLayout.numberOfGlyphs;
 +            tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
              tmpLineLayout.length = previousTmpLineLength;
              tmpExtraBearing = previousTmpExtraBearing;
              tmpExtraWidth = previousTmpExtraWidth;
  
          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  Must break\n" );
          DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--GetLineLayoutForBox\n" );
 +
          return;
        }
  
        }
  
        previousCharacterDirection = characterDirection;
 +      glyphIndex += numberOfGLyphsInGroup;
      }
  
      lineLayout.extraBearing = tmpExtraBearing;
  
    void SetGlyphPositions( const GlyphInfo* const glyphsBuffer,
                            Length numberOfGlyphs,
-                           float penY,
                            Vector2* glyphPositionsBuffer )
    {
      // Traverse the glyphs and set the positions.
        Vector2& position = *( glyphPositionsBuffer + i );
  
        position.x = penX + glyph.xBearing;
-       position.y = penY - glyph.yBearing;
+       position.y = -glyph.yBearing;
  
        penX += glyph.advance;
      }
  
        SetGlyphPositions( layoutParameters.glyphsBuffer + lineRun->glyphRun.glyphIndex,
                           ellipsisLayout.numberOfGlyphs,
-                          penY,
                           glyphPositionsBuffer + lineRun->glyphRun.glyphIndex - layoutParameters.startGlyphIndex );
      }
  
     * @brief Updates the text layout with the last laid-out line.
     *
     * @param[in] layoutParameters The parameters needed to layout the text.
-    * @param[in] layout The line layout.
+    * @param[in] characterIndex The character index of the line.
+    * @param[in] glyphIndex The glyph index of the line.
     * @param[in,out] layoutSize The text's layout size.
     * @param[in,out] linesBuffer Pointer to the line's buffer.
-    * @param[in] index Index to the vector of glyphs.
     * @param[in,out] numberOfLines The number of laid-out lines.
     */
    void UpdateTextLayout( const LayoutParameters& layoutParameters,
-                          const LineLayout& layout,
+                          CharacterIndex characterIndex,
+                          GlyphIndex glyphIndex,
                           Size& layoutSize,
                           LineRun* linesBuffer,
-                          GlyphIndex index,
                           Length& numberOfLines )
    {
      // Need to add a new line with no characters but with height to increase the layoutSize.height
      LineRun& lineRun = *( linesBuffer + numberOfLines );
      ++numberOfLines;
  
-     lineRun.glyphRun.glyphIndex = index + layout.numberOfGlyphs;
+     lineRun.glyphRun.glyphIndex = glyphIndex;
      lineRun.glyphRun.numberOfGlyphs = 0u;
-     lineRun.characterRun.characterIndex = layout.characterIndex + layout.numberOfCharacters;
+     lineRun.characterRun.characterIndex = characterIndex;
      lineRun.characterRun.numberOfCharacters = 0u;
      lineRun.width = 0.f;
      lineRun.ascender = fontMetrics.ascender;
  
      if( 0u == layoutParameters.numberOfGlyphs )
      {
-       // Nothing to do if there are no glyphs to layout.
+       // Add an extra line if the last character is a new paragraph character and the last line doesn't have zero characters.
+       if( layoutParameters.isLastNewParagraph )
+       {
+         Length numberOfLines = lines.Count();
+         if( 0u != numberOfLines )
+         {
+           const LineRun& lastLine = *( lines.End() - 1u );
+           if( 0u != lastLine.characterRun.numberOfCharacters )
+           {
+             // Need to add a new line with no characters but with height to increase the layoutSize.height
+             LineRun newLine;
+             lines.PushBack( newLine );
+             UpdateTextLayout( layoutParameters,
+                               lastLine.characterRun.characterIndex + lastLine.characterRun.numberOfCharacters,
+                               lastLine.glyphRun.glyphIndex + lastLine.glyphRun.numberOfGlyphs,
+                               layoutSize,
+                               lines.Begin(),
+                               numberOfLines );
+           }
+         }
+       }
+       // Nothing else do if there are no glyphs to layout.
        return false;
      }
  
+     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
+     // In a previous layout, an extra line with no characters may have been added if the text ended with a new paragraph character.
+     // This extra line needs to be removed.
+     if( 0u != lines.Count() )
+     {
+       Vector<LineRun>::Iterator lastLine = lines.End() - 1u;
+       if( ( 0u == lastLine->characterRun.numberOfCharacters ) &&
+           ( lastGlyphPlusOne == layoutParameters.totalNumberOfGlyphs ) )
+       {
+         lines.Remove( lastLine );
+       }
+     }
      // Set the first paragraph's direction.
      CharacterDirection paragraphDirection = ( NULL != layoutParameters.characterDirectionBuffer ) ? *layoutParameters.characterDirectionBuffer : !RTL;
  
      Vector<LineRun> newLines;
  
      // Estimate the number of lines.
-     // TODO: In a next patch the paragraphs are properly managed and this can be removed.
-     Length linesCapacity = CountParagraphs( layoutParameters );
+     Length linesCapacity = layoutParameters.estimatedNumberOfLines;
      Length numberOfLines = 0u;
  
      if( updateCurrentBuffer )
      float penY = SetParagraphOffset( lines,
                                       layoutParameters.startLineIndex );
  
-     const GlyphIndex lastGlyphPlusOne = layoutParameters.startGlyphIndex + layoutParameters.numberOfGlyphs;
      for( GlyphIndex index = layoutParameters.startGlyphIndex; index < lastGlyphPlusOne; )
      {
        CharacterDirection currentParagraphDirection = paragraphDirection;
                            numberOfLines,
                            isLastLine );
  
-         if( isLastLine &&
+         const GlyphIndex nextIndex = index + layout.numberOfGlyphs;
+         if( ( nextIndex == layoutParameters.totalNumberOfGlyphs ) &&
              layoutParameters.isLastNewParagraph &&
              ( mLayout == MULTI_LINE_BOX ) )
          {
            }
  
            UpdateTextLayout( layoutParameters,
-                             layout,
+                             layout.characterIndex + layout.numberOfCharacters,
+                             index + layout.numberOfGlyphs,
                              layoutSize,
                              linesBuffer,
-                             index,
                              numberOfLines );
          } // whether to add a last line.
  
          // Sets the positions of the glyphs.
          SetGlyphPositions( layoutParameters.glyphsBuffer + index,
                             layout.numberOfGlyphs,
-                            penY,
                             glyphPositionsBuffer + index - layoutParameters.startGlyphIndex );
  
          // Updates the vertical pen's position.
          penY += -layout.descender;
  
          // Increase the glyph index.
-         index += layout.numberOfGlyphs;
+         index = nextIndex;
        } // no ellipsis
      } // end for() traversing glyphs.
  
        glyphPositions.Insert( glyphPositions.Begin() + layoutParameters.startGlyphIndex,
                               newGlyphPositions.Begin(),
                               newGlyphPositions.End() );
+       glyphPositions.Resize( layoutParameters.totalNumberOfGlyphs );
  
        newLines.Resize( numberOfLines );
  
  #include <dali-toolkit/internal/text/bidirectional-support.h>
  #include <dali-toolkit/internal/text/character-set-conversion.h>
  #include <dali-toolkit/internal/text/color-segmentation.h>
 +#include <dali-toolkit/internal/text/glyph-metrics-helper.h>
  #include <dali-toolkit/internal/text/multi-language-support.h>
  #include <dali-toolkit/internal/text/segmentation.h>
  #include <dali-toolkit/internal/text/shaper.h>
+ #include <dali-toolkit/internal/text/text-run-container.h>
  
  namespace
  {
    Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
  #endif
  
 -/**
 - * @brief Some characters can be shaped in more than one glyph.
 - * This struct is used to retrieve metrics from these group of glyphs.
 - */
 -struct GlyphMetrics
 -{
 -  GlyphMetrics()
 -  : fontHeight( 0.f ),
 -    advance( 0.f ),
 -    ascender( 0.f ),
 -    xBearing( 0.f )
 -  {}
 -
 -  ~GlyphMetrics()
 -  {}
 -
 -  float fontHeight; ///< The font's height of that glyphs.
 -  float advance;    ///< The sum of all the advances of all the glyphs.
 -  float ascender;   ///< The font's ascender.
 -  float xBearing;   ///< The x bearing of the first glyph.
 -};
 -
  } // namespace
  
  namespace Dali
@@@ -49,6 -71,41 +50,6 @@@ namespace Toolki
  namespace Text
  {
  
 -/**
 - * @brief Get some glyph's metrics of a group of glyphs formed as a result of shaping one character.
 - *
 - * @param[in] glyphIndex The index to the first glyph.
 - * @param[in] numberOfGlyphs The number of glyphs.
 - * @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
 - * @param[in] visualModel The visual model.
 - * @param[in] metrics Used to access metrics from FontClient.
 - */
 -void GetGlyphsMetrics( GlyphIndex glyphIndex,
 -                       Length numberOfGlyphs,
 -                       GlyphMetrics& glyphMetrics,
 -                       VisualModelPtr& visualModel,
 -                       MetricsPtr& metrics )
 -{
 -  const GlyphInfo* glyphsBuffer = visualModel->mGlyphs.Begin();
 -
 -  const GlyphInfo& firstGlyph = *( glyphsBuffer + glyphIndex );
 -
 -  Text::FontMetrics fontMetrics;
 -  metrics->GetFontMetrics( firstGlyph.fontId, fontMetrics );
 -
 -  glyphMetrics.fontHeight = fontMetrics.height;
 -  glyphMetrics.advance = firstGlyph.advance;
 -  glyphMetrics.ascender = fontMetrics.ascender;
 -  glyphMetrics.xBearing = firstGlyph.xBearing;
 -
 -  for( unsigned int i = 1u; i < numberOfGlyphs; ++i )
 -  {
 -    const GlyphInfo& glyphInfo = *( glyphsBuffer + glyphIndex + i );
 -
 -    glyphMetrics.advance += glyphInfo.advance;
 -  }
 -}
 -
  EventData::EventData( DecoratorPtr decorator )
  : mDecorator( decorator ),
    mImfManager(),
@@@ -257,6 -314,381 +258,381 @@@ bool Controller::Impl::ProcessInputEven
    return decoratorUpdated;
  }
  
+ void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
+ {
+   mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+   mTextUpdateInfo.mStartGlyphIndex = 0u;
+   mTextUpdateInfo.mStartLineIndex = 0u;
+   numberOfCharacters = 0u;
+   const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
+   if( 0u == numberOfParagraphs )
+   {
+     mTextUpdateInfo.mParagraphCharacterIndex = 0u;
+     numberOfCharacters = 0u;
+     mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+     // Nothing else to do if there are no paragraphs.
+     return;
+   }
+   // Find the paragraphs to be updated.
+   Vector<ParagraphRunIndex> paragraphsToBeUpdated;
+   if( mTextUpdateInfo.mCharacterIndex >= mTextUpdateInfo.mPreviousNumberOfCharacters )
+   {
+     // Text is being added at the end of the current text.
+     if( mTextUpdateInfo.mIsLastCharacterNewParagraph )
+     {
+       // Text is being added in a new paragraph after the last character of the text.
+       mTextUpdateInfo.mParagraphCharacterIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+       numberOfCharacters = 0u;
+       mTextUpdateInfo.mRequestedNumberOfCharacters = mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+       mTextUpdateInfo.mStartGlyphIndex = mVisualModel->mGlyphs.Count();
+       mTextUpdateInfo.mStartLineIndex = mVisualModel->mLines.Count() - 1u;
+       // Nothing else to do;
+       return;
+     }
+     paragraphsToBeUpdated.PushBack( numberOfParagraphs - 1u );
+   }
+   else
+   {
+     CharacterIndex lastIndex = 0u;
+     if( mTextUpdateInfo.mFullRelayoutNeeded )
+     {
+       lastIndex = mTextUpdateInfo.mPreviousNumberOfCharacters;
+     }
+     else
+     {
+       lastIndex = ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) ? mTextUpdateInfo.mNumberOfCharactersToRemove : 1u;
+     }
+     mLogicalModel->FindParagraphs( mTextUpdateInfo.mCharacterIndex,
+                                    lastIndex,
+                                    paragraphsToBeUpdated );
+   }
+   if( 0u != paragraphsToBeUpdated.Count() )
+   {
+     const ParagraphRunIndex firstParagraphIndex = *( paragraphsToBeUpdated.Begin() );
+     const ParagraphRun& firstParagraph = *( mLogicalModel->mParagraphInfo.Begin() + firstParagraphIndex );
+     mTextUpdateInfo.mParagraphCharacterIndex = firstParagraph.characterRun.characterIndex;
+     ParagraphRunIndex lastParagraphIndex = *( paragraphsToBeUpdated.End() - 1u );
+     const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex );
+     if( ( mTextUpdateInfo.mNumberOfCharactersToRemove > 0u ) &&                                            // Some character are removed.
+         ( lastParagraphIndex < numberOfParagraphs - 1u ) &&                                                // There is a next paragraph.
+         ( ( lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters ) == // The last removed character is the new paragraph character.
+           ( mTextUpdateInfo.mCharacterIndex + mTextUpdateInfo.mNumberOfCharactersToRemove ) ) )
+     {
+       // The new paragraph character of the last updated paragraph has been removed so is going to be merged with the next one.
+       const ParagraphRun& lastParagraph = *( mLogicalModel->mParagraphInfo.Begin() + lastParagraphIndex + 1u );
+       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+     }
+     else
+     {
+       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
+     }
+   }
+   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
+   mTextUpdateInfo.mStartGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
+ }
+ void Controller::Impl::ClearFullModelData( OperationsMask operations )
+ {
+   if( GET_LINE_BREAKS & operations )
+   {
+     mLogicalModel->mLineBreakInfo.Clear();
+     mLogicalModel->mParagraphInfo.Clear();
+   }
+   if( GET_WORD_BREAKS & operations )
+   {
+     mLogicalModel->mLineBreakInfo.Clear();
+   }
+   if( GET_SCRIPTS & operations )
+   {
+     mLogicalModel->mScriptRuns.Clear();
+   }
+   if( VALIDATE_FONTS & operations )
+   {
+     mLogicalModel->mFontRuns.Clear();
+   }
+   if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+   {
+     if( BIDI_INFO & operations )
+     {
+       mLogicalModel->mBidirectionalParagraphInfo.Clear();
+       mLogicalModel->mCharacterDirections.Clear();
+     }
+     if( REORDER & operations )
+     {
+       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+       for( Vector<BidirectionalLineInfoRun>::Iterator it = mLogicalModel->mBidirectionalLineInfo.Begin(),
+              endIt = mLogicalModel->mBidirectionalLineInfo.End();
+            it != endIt;
+            ++it )
+       {
+         BidirectionalLineInfoRun& bidiLineInfo = *it;
+         free( bidiLineInfo.visualToLogicalMap );
+         bidiLineInfo.visualToLogicalMap = NULL;
+       }
+       mLogicalModel->mBidirectionalLineInfo.Clear();
+       mLogicalModel->mLogicalToVisualMap.Clear();
+       mLogicalModel->mVisualToLogicalMap.Clear();
+     }
+   }
+   if( SHAPE_TEXT & operations )
+   {
+     mVisualModel->mGlyphs.Clear();
+     mVisualModel->mGlyphsToCharacters.Clear();
+     mVisualModel->mCharactersToGlyph.Clear();
+     mVisualModel->mCharactersPerGlyph.Clear();
+     mVisualModel->mGlyphsPerCharacter.Clear();
+     mVisualModel->mGlyphPositions.Clear();
+   }
+   if( LAYOUT & operations )
+   {
+     mVisualModel->mLines.Clear();
+   }
+ }
+ void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+ {
+   const CharacterIndex endIndexPlusOne = endIndex + 1u;
+   if( GET_LINE_BREAKS & operations )
+   {
+     // Clear the line break info.
+     LineBreakInfo* lineBreakInfoBuffer = mLogicalModel->mLineBreakInfo.Begin();
+     mLogicalModel->mLineBreakInfo.Erase( lineBreakInfoBuffer + startIndex,
+                                          lineBreakInfoBuffer + endIndexPlusOne );
+     // Clear the paragraphs.
+     ClearCharacterRuns( startIndex,
+                         endIndex,
+                         mLogicalModel->mParagraphInfo );
+   }
+   if( GET_WORD_BREAKS & operations )
+   {
+     // Clear the word break info.
+     WordBreakInfo* wordBreakInfoBuffer = mLogicalModel->mWordBreakInfo.Begin();
+     mLogicalModel->mWordBreakInfo.Erase( wordBreakInfoBuffer + startIndex,
+                                          wordBreakInfoBuffer + endIndexPlusOne );
+   }
+   if( GET_SCRIPTS & operations )
+   {
+     // Clear the scripts.
+     ClearCharacterRuns( startIndex,
+                         endIndex,
+                         mLogicalModel->mScriptRuns );
+   }
+   if( VALIDATE_FONTS & operations )
+   {
+     // Clear the fonts.
+     ClearCharacterRuns( startIndex,
+                         endIndex,
+                         mLogicalModel->mFontRuns );
+   }
+   if( 0u != mLogicalModel->mBidirectionalParagraphInfo.Count() )
+   {
+     if( BIDI_INFO & operations )
+     {
+       // Clear the bidirectional paragraph info.
+       ClearCharacterRuns( startIndex,
+                           endIndex,
+                           mLogicalModel->mBidirectionalParagraphInfo );
+       // Clear the character's directions.
+       CharacterDirection* characterDirectionsBuffer = mLogicalModel->mCharacterDirections.Begin();
+       mLogicalModel->mCharacterDirections.Erase( characterDirectionsBuffer + startIndex,
+                                                  characterDirectionsBuffer + endIndexPlusOne );
+     }
+     if( REORDER & operations )
+     {
+       uint32_t startRemoveIndex = mLogicalModel->mBidirectionalLineInfo.Count();
+       uint32_t endRemoveIndex = startRemoveIndex;
+       ClearCharacterRuns( startIndex,
+                           endIndex,
+                           mLogicalModel->mBidirectionalLineInfo,
+                           startRemoveIndex,
+                           endRemoveIndex );
+       BidirectionalLineInfoRun* bidirectionalLineInfoBuffer = mLogicalModel->mBidirectionalLineInfo.Begin();
+       // Free the allocated memory used to store the conversion table in the bidirectional line info run.
+       for( Vector<BidirectionalLineInfoRun>::Iterator it = bidirectionalLineInfoBuffer + startRemoveIndex,
+              endIt = bidirectionalLineInfoBuffer + endRemoveIndex;
+            it != endIt;
+            ++it )
+       {
+         BidirectionalLineInfoRun& bidiLineInfo = *it;
+         free( bidiLineInfo.visualToLogicalMap );
+         bidiLineInfo.visualToLogicalMap = NULL;
+       }
+       mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
+                                                    bidirectionalLineInfoBuffer + endRemoveIndex );
+       // Clear the logical to visual and the visual to logical conversion tables.
+       CharacterIndex* logicalToVisualMapBuffer = mLogicalModel->mLogicalToVisualMap.Begin();
+       mLogicalModel->mLogicalToVisualMap.Erase( logicalToVisualMapBuffer + startIndex,
+                                                 logicalToVisualMapBuffer + endIndexPlusOne );
+       CharacterIndex* visualToLogicalMapBuffer = mLogicalModel->mVisualToLogicalMap.Begin();
+       mLogicalModel->mVisualToLogicalMap.Erase( visualToLogicalMapBuffer + startIndex,
+                                                 visualToLogicalMapBuffer + endIndexPlusOne );
+     }
+   }
+ }
+ void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+ {
+   const CharacterIndex endIndexPlusOne = endIndex + 1u;
+   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
+   const bool clearShape = SHAPE_TEXT & operations;
+   const bool clearLayout = LAYOUT & operations;
+   if( clearShape || clearLayout )
+   {
+     // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+     GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+     Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+     const GlyphIndex endGlyphIndex = *( charactersToGlyphBuffer + endIndex );
+     const GlyphIndex endGlyphIndexPlusOne = endGlyphIndex + *( glyphsPerCharacterBuffer + endIndex );
+     const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+     if( clearShape )
+     {
+       // Update the character to glyph indices.
+       for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
+              endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
+            it != endIt;
+            ++it )
+       {
+         CharacterIndex& index = *it;
+         index -= numberOfGlyphsRemoved;
+       }
+       // Clear the character to glyph conversion table.
+       mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
+                                               charactersToGlyphBuffer + endIndexPlusOne );
+       // Clear the glyphs per character table.
+       mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
+                                                glyphsPerCharacterBuffer + endIndexPlusOne );
+       // Clear the glyphs buffer.
+       GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
+       mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                    glyphsBuffer + endGlyphIndexPlusOne );
+       CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+       // Update the glyph to character indices.
+       for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+              endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
+            it != endIt;
+            ++it )
+       {
+         CharacterIndex& index = *it;
+         index -= numberOfCharactersRemoved;
+       }
+       // Clear the glyphs to characters buffer.
+       mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
+       // Clear the characters per glyph buffer.
+       Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+       mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                                charactersPerGlyphBuffer + endGlyphIndexPlusOne );
+       // Clear the positions buffer.
+       Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+       mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                            positionsBuffer + endGlyphIndexPlusOne );
+     }
+     if( clearLayout )
+     {
+       // Clear the lines.
+       uint32_t startRemoveIndex = mVisualModel->mLines.Count();
+       uint32_t endRemoveIndex = startRemoveIndex;
+       ClearCharacterRuns( startIndex,
+                           endIndex,
+                           mVisualModel->mLines,
+                           startRemoveIndex,
+                           endRemoveIndex );
+       // Will update the glyph runs.
+       uint32_t startRemoveGlyphIndex = mVisualModel->mLines.Count();
+       uint32_t endRemoveGlyphIndex = startRemoveIndex;
+       ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                       endGlyphIndex,
+                       mVisualModel->mLines,
+                       startRemoveGlyphIndex,
+                       endRemoveGlyphIndex );
+       // Set the line index from where to insert the new laid-out lines.
+       mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
+       LineRun* linesBuffer = mVisualModel->mLines.Begin();
+       mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
+                                   linesBuffer + endRemoveIndex );
+     }
+   }
+ }
+ void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
+ {
+   if( mTextUpdateInfo.mClearAll ||
+       ( ( 0u == startIndex ) &&
+         ( mTextUpdateInfo.mPreviousNumberOfCharacters == endIndex + 1u ) ) )
+   {
+     ClearFullModelData( operations );
+   }
+   else
+   {
+     // Clear the model data related with characters.
+     ClearCharacterModelData( startIndex, endIndex, operations );
+     // Clear the model data related with glyphs.
+     ClearGlyphModelData( startIndex, endIndex, operations );
+   }
+   // The estimated number of lines. Used to avoid reallocations when layouting.
+   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+   mVisualModel->ClearCaches();
+   // TODO finish the mark-up.
+   mVisualModel->mColorRuns.Clear();
+ }
  void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
  {
    DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
    // Calculate the operations to be done.
    const OperationsMask operations = static_cast<OperationsMask>( mOperationsPending & operationsRequired );
  
+   if( NO_OPERATION == operations )
+   {
+     // Nothing to do if no operations are pending and required.
+     return;
+   }
    Vector<Character>& utf32Characters = mLogicalModel->mText;
  
    const Length numberOfCharacters = utf32Characters.Count();
  
-   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+   // Index to the first character of the first paragraph to be updated.
    CharacterIndex startIndex = 0u;
-   Length requestedNumberOfCharacters = numberOfCharacters;
+   // Number of characters of the paragraphs to be removed.
+   Length paragraphCharacters = 0u;
+   CalculateTextUpdateIndices( paragraphCharacters );
+   startIndex = mTextUpdateInfo.mParagraphCharacterIndex;
+   if( mTextUpdateInfo.mClearAll ||
+       ( 0u != paragraphCharacters ) )
+   {
+     ClearModelData( startIndex, startIndex + ( ( paragraphCharacters > 0u ) ? paragraphCharacters - 1u : 0u ), operationsRequired );
+   }
+   mTextUpdateInfo.mClearAll = false;
+   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
+   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
    if( GET_LINE_BREAKS & operations )
    {
      // Retrieves the line break info. The line break info is used to split the text in 'paragraphs' to
  
    Vector<Character> mirroredUtf32Characters;
    bool textMirrored = false;
-   Length numberOfParagraphs = 0u;
+   const Length numberOfParagraphs = mLogicalModel->mParagraphInfo.Count();
    if( BIDI_INFO & operations )
    {
-     // Count the number of LINE_NO_BREAK to reserve some space for the vector of paragraph's
-     // bidirectional info.
-     const TextAbstraction::LineBreakInfo* lineBreakInfoBuffer = lineBreakInfo.Begin();
-     for( Length index = 0u; index < numberOfCharacters; ++index )
-     {
-       if( TextAbstraction::LINE_NO_BREAK == *( lineBreakInfoBuffer + index ) )
-       {
-         ++numberOfParagraphs;
-       }
-     }
      Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = mLogicalModel->mBidirectionalParagraphInfo;
      bidirectionalInfo.Reserve( numberOfParagraphs );
  
    Vector<GlyphIndex> newParagraphGlyphs;
    newParagraphGlyphs.Reserve( numberOfParagraphs );
  
-   GlyphIndex startGlyphIndex = 0u;
+   const Length currentNumberOfGlyphs = glyphs.Count();
    if( SHAPE_TEXT & operations )
    {
      const Vector<Character>& textToShape = textMirrored ? mirroredUtf32Characters : utf32Characters;
                 scripts,
                 validFonts,
                 startIndex,
-                startGlyphIndex,
+                mTextUpdateInfo.mStartGlyphIndex,
                 requestedNumberOfCharacters,
                 glyphs,
                 glyphsToCharactersMap,
                 newParagraphGlyphs );
  
      // Create the 'number of glyphs' per character and the glyph to character conversion tables.
-     mVisualModel->CreateGlyphsPerCharacterTable( startIndex, startGlyphIndex, numberOfCharacters );
-     mVisualModel->CreateCharacterToGlyphTable( startIndex, startGlyphIndex, numberOfCharacters );
+     mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+     mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
    }
  
-   const Length numberOfGlyphs = glyphs.Count();
+   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
  
    if( GET_GLYPH_METRICS & operations )
    {
-     GlyphInfo* glyphsBuffer = glyphs.Begin() + startGlyphIndex;
-     mMetrics->GetGlyphMetrics( glyphsBuffer, numberOfGlyphs );
+     GlyphInfo* glyphsBuffer = glyphs.Begin();
+     mMetrics->GetGlyphMetrics( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex, numberOfGlyphs );
  
      // Update the width and advance of all new paragraph characters.
      for( Vector<GlyphIndex>::ConstIterator it = newParagraphGlyphs.Begin(), endIt = newParagraphGlyphs.End(); it != endIt; ++it )
      // TODO: At the moment the underline runs are only for pre-edit.
      mVisualModel->mUnderlineRuns.PushBack( underlineRun );
    }
+   // The estimated number of lines. Used to avoid reallocations when layouting.
+   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
+   // Set the previous number of characters for the next time the text is updated.
+   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
  }
  
  bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired )
@@@ -932,12 -1380,13 +1324,13 @@@ void Controller::Impl::RetrieveSelectio
    const CharacterIndex startOfSelectedText = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
    const Length lengthOfSelectedText = ( handlesCrossed ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition ) - startOfSelectedText;
  
+   Vector<Character>& utf32Characters = mLogicalModel->mText;
+   const Length numberOfCharacters = utf32Characters.Count();
    // Validate the start and end selection points
-   if( ( startOfSelectedText + lengthOfSelectedText ) <= mLogicalModel->mText.Count() )
+   if( ( startOfSelectedText + lengthOfSelectedText ) <= numberOfCharacters )
    {
      //Get text as a UTF8 string
-     Vector<Character>& utf32Characters = mLogicalModel->mText;
      Utf32ToUtf8( &utf32Characters[startOfSelectedText], lengthOfSelectedText, selectedText );
  
      if( deleteAfterRetrieval ) // Only delete text if copied successfully
  
        mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
  
-       // Delete text between handles
-       Vector<Character>& currentText = mLogicalModel->mText;
+       // Mark the paragraphs to be updated.
+       mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+       mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
  
-       Vector<Character>::Iterator first = currentText.Begin() + startOfSelectedText;
+       // Delete text between handles
+       Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
        Vector<Character>::Iterator last  = first + lengthOfSelectedText;
-       currentText.Erase( first, last );
+       utf32Characters.Erase( first, last );
  
        // Scroll after delete.
        mEventData->mPrimaryCursorPosition = handlesCrossed ? mEventData->mRightSelectionPosition : mEventData->mLeftSelectionPosition;
@@@ -1529,9 -1980,6 +1924,9 @@@ CharacterIndex Controller::Impl::GetClo
    // Get the glyphs per character table.
    const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
  
 +  // Get the glyph's info buffer.
 +  const GlyphInfo* const glyphInfoBuffer = mVisualModel->mGlyphs.Begin();
 +
    // If the vector is void, there is no right to left characters.
    const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
  
        GetGlyphsMetrics( firstLogicalGlyphIndex,
                          numberOfGlyphs,
                          glyphMetrics,
 -                        mVisualModel,
 +                        glyphInfoBuffer,
                          mMetrics );
  
        // Get the position of the first glyph.
@@@ -1749,7 -2197,6 +2144,7 @@@ void Controller::Impl::GetCursorPositio
    const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
    const CharacterIndex* const glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
    const Vector2* const glyphPositionsBuffer = mVisualModel->mGlyphPositions.Begin();
 +  const GlyphInfo* const glyphInfoBuffer = mVisualModel->mGlyphs.Begin();
  
    // Convert the cursor position into the glyph position.
    const GlyphIndex primaryGlyphIndex = *( charactersToGlyphBuffer + index );
    GetGlyphsMetrics( primaryGlyphIndex,
                      primaryNumberOfGlyphs,
                      glyphMetrics,
 -                    mVisualModel,
 +                    glyphInfoBuffer,
                      mMetrics );
  
    // Whether to add the glyph's advance to the cursor position.
      GetGlyphsMetrics( secondaryGlyphIndex,
                        secondaryNumberOfGlyphs,
                        glyphMetrics,
 -                      mVisualModel,
 +                      glyphInfoBuffer,
                        mMetrics );
  
      // Set the secondary cursor's position.