Refactor TextLabel to use text visual
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model-impl.cpp
index 5822469..1b114c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
 
 // EXTERNAL INCLUDES
 #include <memory.h>
-#include <dali/public-api/math/vector2.h>
 
 namespace Dali
 {
@@ -36,97 +35,130 @@ VisualModelPtr VisualModel::New()
   return VisualModelPtr( new VisualModel() );
 }
 
-void VisualModel::SetGlyphs( const GlyphInfo* glyphs,
-                             const CharacterIndex* characterIndices,
-                             const Length* charactersPerGlyph,
-                             Length numberOfGlyphs )
+void VisualModel::CreateCharacterToGlyphTable( CharacterIndex startIndex,
+                                               GlyphIndex startGlyphIndex,
+                                               Length numberOfCharacters )
 {
-  if( 0u == numberOfGlyphs )
+  if( 0u == numberOfCharacters )
   {
-    mGlyphs.Clear();
-    mGlyphsToCharacters.Clear();
-    mCharactersToGlyph.Clear();
-    mCharactersPerGlyph.Clear();
-    mGlyphsPerCharacter.Clear();
+    // Nothing to do.
+    return;
   }
-  else
-  {
-    if( NULL != glyphs )
-    {
-      mGlyphs.Resize( numberOfGlyphs );
-      memcpy( mGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
-    }
 
-    if( NULL != characterIndices )
-    {
-      mGlyphsToCharacters.Resize( numberOfGlyphs );
-      memcpy( mGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
-    }
+  DALI_ASSERT_DEBUG( mGlyphsPerCharacter.Count() != 0u );
 
-    if( NULL != charactersPerGlyph )
-    {
-      mCharactersPerGlyph.Resize( numberOfGlyphs );
-      memcpy( mCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
+  // Get the total number of characters.
+  const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
 
-      // Build the characters to glyph conversion table.
-      CreateCharacterToGlyphTable();
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
 
-      // Build the glyphs per character table.
-      CreateGlyphsPerCharacterTable();
-    }
-  }
-}
+  Vector<GlyphIndex> newCharactersToGlyph;
+  GlyphIndex* charactersToGlyphBuffer = NULL;
 
-void VisualModel::CreateCharacterToGlyphTable( Length numberOfCharacters )
-{
-  // 1) Reserve some space for the characters to avoid reallocations.
-  if( 0u == numberOfCharacters )
+  // 1) Reserve some space for the glyph indices to avoid reallocations.
+  if( updateCurrentBuffer )
+  {
+    newCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = newCharactersToGlyph.Begin();
+  }
+  else
   {
-    // If no number of characters is given, just set something sensible to avoid reallocations.
-    numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
+    mCharactersToGlyph.Resize( numberOfCharacters );
+    charactersToGlyphBuffer = mCharactersToGlyph.Begin() + startIndex;
   }
-  mCharactersToGlyph.Reserve( numberOfCharacters );
+
+  const Length* const glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin();
 
   // 2) Traverse the glyphs and set the glyph indices per character.
 
   // Index to the glyph.
-  GlyphIndex glyphIndex = 0u;
-  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
+  GlyphIndex glyphIndex = startGlyphIndex;
+  CharacterIndex characterIndex = startIndex;
+  const CharacterIndex lastCharacterIndexPlusOne = startIndex + numberOfCharacters;
+  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + glyphIndex,
          endIt = mCharactersPerGlyph.End();
-       it != endIt;
-       ++it, ++glyphIndex )
+       ( it != endIt ) && ( characterIndex < lastCharacterIndexPlusOne );
+       ++it )
   {
     const Length numberOfCharactersPerGlyph = *it;
 
+    Length numberOfGlyphs = 0u;
     // Set the glyph indices.
-    for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index )
+    for( Length index = 0u; index < numberOfCharactersPerGlyph; ++index, ++characterIndex )
+    {
+      *charactersToGlyphBuffer = glyphIndex;
+      numberOfGlyphs += *( glyphsPerCharacterBuffer + characterIndex );
+      ++charactersToGlyphBuffer;
+    }
+    glyphIndex += numberOfGlyphs;
+  }
+
+  // If the character to glyph buffer is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    // Update the indices.
+    const Length numberOfGlyphs = glyphIndex - startGlyphIndex;
+    for( Vector<Length>::Iterator it = mCharactersToGlyph.Begin() + startIndex,
+           endIt = mCharactersToGlyph.End();
+         it != endIt;
+         ++it )
     {
-      mCharactersToGlyph.PushBack( glyphIndex );
+      *it += numberOfGlyphs;
     }
+
+    mCharactersToGlyph.Insert( mCharactersToGlyph.Begin() + startIndex,
+                               newCharactersToGlyph.Begin(),
+                               newCharactersToGlyph.End() );
+
   }
 }
 
-void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
+void VisualModel::CreateGlyphsPerCharacterTable( CharacterIndex startIndex,
+                                                 GlyphIndex startGlyphIndex,
+                                                 Length numberOfCharacters )
 {
-  // 1) Reserve some space for the characters to avoid reallocations.
   if( 0u == numberOfCharacters )
   {
-    // If no number of characters is given, just set something sensible to avoid reallocations.
-    numberOfCharacters = static_cast<Length> ( static_cast<float>( mGlyphs.Count() ) * 1.3f );
+    // Nothing to do.
+    return;
+  }
+
+  // Get the total number of characters.
+  const Length totalNumberOfCharacters = ( 0u == mGlyphsToCharacters.Count() ) ? 0u : *( mGlyphsToCharacters.End() - 1u ) + *( mCharactersPerGlyph.End() - 1u ); // Index to the first character + the number of characters that form the last glyph.
+
+  // Whether the current buffer is being updated or is set from scratch.
+  const bool updateCurrentBuffer = numberOfCharacters < totalNumberOfCharacters;
+
+  Vector<Length> newGlyphsPerCharacter;
+  Length* glyphsPerCharacterBuffer = NULL;
+
+  // 1) Reserve some space for the glyphs per character to avoid reallocations.
+  if( updateCurrentBuffer )
+  {
+    newGlyphsPerCharacter.Resize( numberOfCharacters );
+    glyphsPerCharacterBuffer = newGlyphsPerCharacter.Begin();
+  }
+  else
+  {
+    mGlyphsPerCharacter.Resize( numberOfCharacters );
+    glyphsPerCharacterBuffer = mGlyphsPerCharacter.Begin() + startIndex;
   }
-  mCharactersToGlyph.Reserve( numberOfCharacters );
 
   // 2) Traverse the glyphs and set the number of glyphs per character.
 
+  Length traversedCharacters = 0;
+
   // The number of 'characters per glyph' equal to zero.
   Length zeroCharactersPerGlyph = 0u;
 
-  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin(),
+  for( Vector<Length>::ConstIterator it = mCharactersPerGlyph.Begin() + startGlyphIndex,
          endIt = mCharactersPerGlyph.End();
-       it != endIt;
+       ( it != endIt ) && ( traversedCharacters < numberOfCharacters );
        ++it )
   {
     const Length numberOfCharactersPerGlyph = *it;
+    traversedCharacters += numberOfCharactersPerGlyph;
 
     // Set the glyphs per character.
     if( 0u == numberOfCharactersPerGlyph )
@@ -136,21 +168,30 @@ void VisualModel::CreateGlyphsPerCharacterTable( Length numberOfCharacters )
     else
     {
       const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharactersPerGlyph - 1u );
-      for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
+      for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter; ++zeroIndex )
       {
-        mGlyphsPerCharacter.PushBack( 0u );
+        *glyphsPerCharacterBuffer = 0u;
+
+        // Point to the next position in the buffer.
+        ++glyphsPerCharacterBuffer;
       }
 
-      mGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
+      *glyphsPerCharacterBuffer = zeroCharactersPerGlyph + 1u;
 
       zeroCharactersPerGlyph = 0u;
+
+      // Point to the next position in the buffer.
+      ++glyphsPerCharacterBuffer;
     }
   }
-}
 
-Length VisualModel::GetNumberOfGlyphs() const
-{
-  return mGlyphs.Count();
+  // If the glyphs per character buffer is updated, it needs to be inserted in the model.
+  if( updateCurrentBuffer )
+  {
+    mGlyphsPerCharacter.Insert( mGlyphsPerCharacter.Begin() + startIndex,
+                                newGlyphsPerCharacter.Begin(),
+                                newGlyphsPerCharacter.End() );
+  }
 }
 
 void VisualModel::GetGlyphs( GlyphInfo* glyphs,
@@ -160,81 +201,6 @@ void VisualModel::GetGlyphs( GlyphInfo* glyphs,
   memcpy( glyphs, mGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
 }
 
-const GlyphInfo& VisualModel::GetGlyphInfo( GlyphIndex glyphIndex ) const
-{
-  return mGlyphs[glyphIndex];
-}
-
-void VisualModel::ReplaceGlyphs( GlyphIndex glyphIndex,
-                                 Length numberOfGlyphsToRemove,
-                                 const GlyphInfo* const glyphs,
-                                 const Length* const numberOfCharacters,
-                                 Length numberOfGlyphsToInsert )
-{
-}
-
-CharacterIndex VisualModel::GetCharacterIndex( GlyphIndex glyphIndex ) const
-{
-  return mGlyphsToCharacters[glyphIndex];
-}
-
-Length VisualModel::GetCharactersPerGlyph( GlyphIndex glyphIndex ) const
-{
-  return mCharactersPerGlyph[glyphIndex];
-}
-
-GlyphIndex VisualModel::GetGlyphIndex( CharacterIndex characterIndex ) const
-{
-  return mCharactersToGlyph[characterIndex];
-}
-
-void VisualModel::GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
-                                          CharacterIndex characterIndex,
-                                          Length numberOfCharacters ) const
-{
-  memcpy( characterToGlyphMap, mCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
-}
-
-void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
-                                          GlyphIndex glyphIndex,
-                                          Length numberOfGlyphs ) const
-{
-  memcpy( glyphToCharacter, mGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
-}
-
-void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
-                                            GlyphIndex glyphIndex,
-                                            Length numberOfGlyphs ) const
-{
-  memcpy( charactersPerGlyph, mCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
-}
-
-void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
-                                            CharacterIndex characterIndex,
-                                            Length numberOfCharacters ) const
-{
-  memcpy( glyphsPerCharacter, mGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
-}
-
-void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
-                                     Length numberOfGlyphs )
-{
-  if( 0u == numberOfGlyphs )
-  {
-    mGlyphPositions.Clear();
-  }
-  else
-  {
-    mGlyphPositions.Resize( numberOfGlyphs );
-    memcpy( mGlyphPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
-  }
-}
-
-Length VisualModel::GetNumberOfGlyphPositions() const
-{
-  return mGlyphPositions.Count();
-}
-
 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
                                      GlyphIndex glyphIndex,
                                      Length numberOfGlyphs ) const
@@ -242,44 +208,6 @@ void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
   memcpy( glyphPositions, mGlyphPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
 }
 
-const Vector2& VisualModel::GetGlyphPosition( GlyphIndex glyphIndex ) const
-{
-  return *( mGlyphPositions.Begin() + glyphIndex );
-}
-
-void VisualModel::ReplaceGlyphPositions( GlyphIndex glyphIndex,
-                                         Length numberOfGlyphsToRemove,
-                                         const Vector2* const positions,
-                                         Length numberOfGlyphsToInsert )
-{
-}
-
-void VisualModel::SetLines( const LineRun* const lines,
-                            Length numberOfLines )
-{
-  if( 0u == numberOfLines )
-  {
-    mLines.Clear();
-  }
-  else
-  {
-    mLines.Resize( numberOfLines );
-    memcpy( mLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
-  }
-}
-
-Length VisualModel::GetNumberOfLines() const
-{
-  return mLines.Count();
-}
-
-void VisualModel::GetLines( LineRun* lines,
-                            LineIndex lineIndex,
-                            Length numberOfLines ) const
-{
-  memcpy( lines, mLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
-}
-
 void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
                                     Length numberOfGlyphs,
                                     LineIndex& firstLine,
@@ -300,13 +228,13 @@ void VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
   {
     const LineRun& line = *it;
 
-    if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
-        ( lastGlyphIndex > line.glyphIndex ) )
+    if( ( line.glyphRun.glyphIndex + line.glyphRun.numberOfGlyphs > glyphIndex ) &&
+        ( lastGlyphIndex > line.glyphRun.glyphIndex ) )
     {
       firstLineFound = true;
       ++numberOfLines;
     }
-    else if( lastGlyphIndex <= line.glyphIndex )
+    else if( lastGlyphIndex <= line.glyphRun.glyphIndex )
     {
       // nothing else to do.
       break;
@@ -334,11 +262,46 @@ void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
   memcpy( lines, mLines.Begin() + firstLine, numberOfLines * sizeof( LineRun ) );
 }
 
-void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
-                                Length numberOfGlyphsToRemove,
-                                const LineRun* const lines,
-                                Length numberOfGlyphsToInsert )
+LineIndex VisualModel::GetLineOfCharacter( CharacterIndex characterIndex )
 {
+  // 1) Check first in the cached line.
+
+  const LineRun& lineRun = *( mLines.Begin() + mCachedLineIndex );
+
+  if( ( lineRun.characterRun.characterIndex <= characterIndex ) &&
+      ( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters ) )
+  {
+    return mCachedLineIndex;
+  }
+
+  // 2) Is not in the cached line. Check in the other lines.
+
+  LineIndex index = characterIndex < lineRun.characterRun.characterIndex ? 0u : mCachedLineIndex + 1u;
+
+  for( Vector<LineRun>::ConstIterator it = mLines.Begin() + index,
+         endIt = mLines.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const LineRun& lineRun = *it;
+
+    if( characterIndex < lineRun.characterRun.characterIndex + lineRun.characterRun.numberOfCharacters )
+    {
+      mCachedLineIndex = index;
+      break;
+    }
+  }
+
+  return index;
+}
+
+void VisualModel::GetUnderlineRuns( GlyphRun* underlineRuns,
+                                    UnderlineRunIndex index,
+                                    Length numberOfRuns ) const
+{
+  memcpy( underlineRuns,
+          mUnderlineRuns.Begin() + index,
+          numberOfRuns * sizeof( GlyphRun ) );
 }
 
 void VisualModel::SetNaturalSize( const Vector2& size  )
@@ -351,14 +314,90 @@ const Vector2& VisualModel::GetNaturalSize() const
   return mNaturalSize;
 }
 
-void VisualModel::SetActualSize( const Vector2& size )
+void VisualModel::SetLayoutSize( const Vector2& size )
+{
+  mLayoutSize = size;
+}
+
+const Vector2& VisualModel::GetLayoutSize() const
+{
+  return mLayoutSize;
+}
+
+void VisualModel::SetTextColor( const Vector4& textColor )
+{
+  mTextColor = textColor;
+
+  if ( !mUnderlineColorSet )
+  {
+    mUnderlineColor = textColor;
+  }
+}
+
+void VisualModel::SetShadowOffset( const Vector2& shadowOffset )
+{
+  mShadowOffset = shadowOffset;
+}
+
+void VisualModel::SetShadowColor( const Vector4& shadowColor )
+{
+  mShadowColor = shadowColor;
+}
+
+void VisualModel::SetUnderlineColor( const Vector4& color )
+{
+  mUnderlineColor = color;
+  mUnderlineColorSet = true;
+}
+
+void VisualModel::SetUnderlineEnabled( bool enabled )
+{
+  mUnderlineEnabled = enabled;
+}
+
+void VisualModel::SetUnderlineHeight( float height )
+{
+  mUnderlineHeight = height;
+}
+
+const Vector4& VisualModel::GetTextColor() const
+{
+  return mTextColor;
+}
+
+const Vector2& VisualModel::GetShadowOffset() const
+{
+  return mShadowOffset;
+}
+
+const Vector4& VisualModel::GetShadowColor() const
+{
+  return mShadowColor;
+}
+
+const Vector4& VisualModel::GetUnderlineColor() const
+{
+  return mUnderlineColor;
+}
+
+bool VisualModel::IsUnderlineEnabled() const
+{
+  return mUnderlineEnabled;
+}
+
+float VisualModel::GetUnderlineHeight() const
+{
+  return mUnderlineHeight;
+}
+
+Length VisualModel::GetNumberOfUnderlineRuns() const
 {
-  mActualSize = size;
+  return mUnderlineRuns.Count();
 }
 
-const Vector2& VisualModel::GetActualSize() const
+void VisualModel::ClearCaches()
 {
-  return mActualSize;
+  mCachedLineIndex = 0u;
 }
 
 VisualModel::~VisualModel()
@@ -366,6 +405,24 @@ VisualModel::~VisualModel()
 }
 
 VisualModel::VisualModel()
+: mGlyphs(),
+  mGlyphsToCharacters(),
+  mCharactersToGlyph(),
+  mCharactersPerGlyph(),
+  mGlyphsPerCharacter(),
+  mGlyphPositions(),
+  mLines(),
+  mTextColor( Color::BLACK ),
+  mShadowColor( Color::BLACK ),
+  mUnderlineColor( Color::BLACK ),
+  mControlSize(),
+  mShadowOffset(),
+  mUnderlineHeight( 0.0f ),
+  mNaturalSize(),
+  mLayoutSize(),
+  mCachedLineIndex( 0u ),
+  mUnderlineEnabled( false ),
+  mUnderlineColorSet( false )
 {
 }