Merge "TextModel interface" into new_text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / visual-model.cpp
index 975a70e..e7015e0 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/internal/text/visual-model.h>
 
-// INTERNAL INCLUDES
+// EXTERNAL INCLUDES
+#include <memory.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/math/vector2.h>
-#include <dali-toolkit/internal/text/line-run.h>
 
-// EXTERNAL INCLUDES
-#include <memory.h>
-#include <vector>
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/line-run.h>
 
 namespace Dali
 {
@@ -36,17 +35,32 @@ namespace Toolkit
 namespace Text
 {
 
-const GlyphInfo GLYPH_INFO; // VCC to be removed.
+/**
+ * @brief caches some temporary values of the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation
+ * as they are going to be used in the GetLinesOfGlyphRange() call.
+ */
+struct GetLineCache
+{
+  GlyphIndex glyphIndex;     ///< The glyph index.
+  Length     numberOfGlyphs; ///< The number of glyphs.
+  Length     firstLine;      ///< Index to the first line.
+  Length     numberOfLines;  ///< The number of lines.
+};
 
 struct VisualModel::Impl
 {
-  Vector<GlyphInfo>      mGlyphs;
-  Vector<CharacterIndex> mGlyphsToCharacters;
-  Vector<Length>         mCharactersPerGlyph;
-  std::vector<Vector2>   mGlyphPositions;
-
-  Size                   mNaturalSize;
-  Size                   mActualSize;
+  Vector<GlyphInfo>      mGlyphs;             ///< For each glyph, the font's id, glyph's index within the font and glyph's metrics.
+  Vector<CharacterIndex> mGlyphsToCharacters; ///< For each glyph, the index of the first character.
+  Vector<GlyphIndex>     mCharactersToGlyph;  ///< For each character, the index of the first glyph.
+  Vector<Length>         mCharactersPerGlyph; ///< For each glyph, the number of characters that form the glyph.
+  Vector<Length>         mGlyphsPerCharacter; ///< For each character, the number of glyphs that are shaped.
+  Vector<Vector2>        mGlyphPositions;     ///< For each glyph, the position.
+  Vector<LineRun>        mLines;              ///< The laid out lines.
+
+  Size                   mNaturalSize;        ///< Size of the text with no line wrapping.
+  Size                   mActualSize;         ///< Size of the laid-out text considering the layout properties set.
+
+  GetLineCache           mGetLineCache;       ///< Caches the GetNumberOfLines( glyphIndex, numberOfGlyphs ) operation.
 };
 
 VisualModelPtr VisualModel::New()
@@ -60,16 +74,85 @@ void VisualModel::SetGlyphs( const GlyphInfo* glyphs,
                              Length numberOfGlyphs )
 {
   Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
-  modelGlyphs.Resize( numberOfGlyphs );
-  memcpy( &modelGlyphs[0], glyphs, numberOfGlyphs*sizeof(GlyphInfo) );
+  Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
+  Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+  Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+  Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
 
-  Vector<CharacterIndex>& glyphsToCharacters = mImpl->mGlyphsToCharacters;
-  glyphsToCharacters.Resize( numberOfGlyphs );
-  memcpy( &glyphsToCharacters[0], characterIndices, numberOfGlyphs*sizeof(CharacterIndex) );
+  if( 0u == numberOfGlyphs )
+  {
+    modelGlyphs.Clear();
+    modelGlyphsToCharacters.Clear();
+    modelCharactersToGlyph.Clear();
+    modelCharactersPerGlyph.Clear();
+    modelGlyphsPerCharacter.Clear();
+  }
+  else
+  {
+    if( NULL != glyphs )
+    {
+      modelGlyphs.Resize( numberOfGlyphs );
+      memcpy( modelGlyphs.Begin(), glyphs, numberOfGlyphs * sizeof( GlyphInfo ) );
+    }
 
-  Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
-  modelCharactersPerGlyph.Resize( numberOfGlyphs );
-  memcpy( &modelCharactersPerGlyph[0], charactersPerGlyph, numberOfGlyphs*sizeof(Length) );
+    if( NULL != characterIndices )
+    {
+      modelGlyphsToCharacters.Resize( numberOfGlyphs );
+      memcpy( modelGlyphsToCharacters.Begin(), characterIndices, numberOfGlyphs * sizeof( CharacterIndex ) );
+    }
+
+    if( NULL != charactersPerGlyph )
+    {
+      modelCharactersPerGlyph.Resize( numberOfGlyphs );
+      memcpy( modelCharactersPerGlyph.Begin(), charactersPerGlyph, numberOfGlyphs * sizeof( Length ) );
+
+      // Build the characters to glyph conversion table.
+
+      // 1) Reserve some space for the characters to avoid reallocations.
+      const Length numberOfCharacters = static_cast<Length> ( static_cast<float>( numberOfGlyphs ) * 1.3f );
+      modelCharactersToGlyph.Reserve( numberOfCharacters );
+      modelGlyphsPerCharacter.Reserve( numberOfCharacters );
+
+      // 2) Traverse the glyphs and set the glyph indices and the glyphs per character.
+
+      // The number of 'characters per glyph' equal to zero.
+      Length zeroCharactersPerGlyph = 0u;
+
+      // Index to the glyph.
+      GlyphIndex glyphIndex = 0u;
+      for( Vector<Length>::ConstIterator it = modelCharactersPerGlyph.Begin(),
+             endIt = modelCharactersPerGlyph.End();
+           it != endIt;
+           ++it, ++glyphIndex )
+      {
+        const Length numberOfCharacters = *it;
+
+        // Set the glyph indices.
+        for( Length index = 0u; index < numberOfCharacters; ++index )
+        {
+          modelCharactersToGlyph.PushBack( glyphIndex );
+        }
+
+        // Set the glyphs per character.
+        if( 0u == numberOfCharacters )
+        {
+          ++zeroCharactersPerGlyph;
+        }
+        else
+        {
+          const Length numberOfZeroGlyphsPerCharacter = ( numberOfCharacters - 1u );
+          for( Length zeroIndex = 0u; zeroIndex < numberOfZeroGlyphsPerCharacter ; ++zeroIndex )
+          {
+            modelGlyphsPerCharacter.PushBack( 0u );
+          }
+
+          modelGlyphsPerCharacter.PushBack( 1u + zeroCharactersPerGlyph );
+
+          zeroCharactersPerGlyph = 0u;
+        }
+      }
+    }
+  }
 }
 
 Length VisualModel::GetNumberOfGlyphs() const
@@ -81,13 +164,21 @@ void VisualModel::GetGlyphs( GlyphInfo* glyphs,
                              GlyphIndex glyphIndex,
                              Length numberOfGlyphs ) const
 {
-  Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
-  memcpy( glyphs, &modelGlyphs[glyphIndex], numberOfGlyphs*sizeof(GlyphInfo) );
+  const Vector<GlyphInfo>& modelGlyphs = mImpl->mGlyphs;
+  memcpy( glyphs, modelGlyphs.Begin() + glyphIndex, numberOfGlyphs * sizeof( GlyphInfo ) );
 }
 
 const GlyphInfo& VisualModel::GetGlyphInfo( GlyphIndex glyphIndex ) const
 {
-  return GLYPH_INFO;
+  return mImpl->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
@@ -102,85 +193,199 @@ Length VisualModel::GetCharactersPerGlyph( GlyphIndex glyphIndex ) const
 
 GlyphIndex VisualModel::GetGlyphIndex( CharacterIndex characterIndex ) const
 {
-  GlyphIndex index( 0 );
-
-  for( unsigned int i=0; i<mImpl->mGlyphsToCharacters.Count(); ++i )
-  {
-    if( mImpl->mGlyphsToCharacters[i] == characterIndex )
-    {
-      index = i;
-      break;
-    }
-  }
-
-  return index;
+  return mImpl->mCharactersToGlyph[characterIndex];
 }
 
 void VisualModel::GetCharacterToGlyphMap( GlyphIndex* characterToGlyphMap,
                                           CharacterIndex characterIndex,
                                           Length numberOfCharacters ) const
 {
+  const Vector<GlyphIndex>& modelCharactersToGlyph = mImpl->mCharactersToGlyph;
+  memcpy( characterToGlyphMap, modelCharactersToGlyph.Begin() + characterIndex, numberOfCharacters * sizeof( GlyphIndex ) );
+}
+
+void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
+                                          GlyphIndex glyphIndex,
+                                          Length numberOfGlyphs ) const
+{
+  const Vector<CharacterIndex>& modelGlyphsToCharacters = mImpl->mGlyphsToCharacters;
+  memcpy( glyphToCharacter, modelGlyphsToCharacters.Begin() + glyphIndex, numberOfGlyphs * sizeof( CharacterIndex ) );
 }
 
 void VisualModel::GetCharactersPerGlyphMap( Length* charactersPerGlyph,
                                             GlyphIndex glyphIndex,
                                             Length numberOfGlyphs ) const
 {
+  const Vector<Length>& modelCharactersPerGlyph = mImpl->mCharactersPerGlyph;
+  memcpy( charactersPerGlyph, modelCharactersPerGlyph.Begin() + glyphIndex, numberOfGlyphs * sizeof( Length ) );
 }
 
-void VisualModel::GetGlyphToCharacterMap( CharacterIndex* glyphToCharacter,
-                                          GlyphIndex glyphIndex,
-                                          Length numberOfGlyphs ) const
+void VisualModel::GetGlyphsPerCharacterMap( Length* glyphsPerCharacter,
+                                            CharacterIndex characterIndex,
+                                            Length numberOfCharacters ) const
 {
+  const Vector<Length>& modelGlyphsPerCharacter = mImpl->mGlyphsPerCharacter;
+  memcpy( glyphsPerCharacter, modelGlyphsPerCharacter.Begin() + characterIndex, numberOfCharacters * sizeof( Length ) );
 }
 
 void VisualModel::SetGlyphPositions( const Vector2* glyphPositions,
                                      Length numberOfGlyphs )
 {
-  std::vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
-  modelPositions.resize( numberOfGlyphs );
-  memcpy( &modelPositions[0], glyphPositions, numberOfGlyphs*sizeof(Vector2) );
+  Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
+  if( 0u == numberOfGlyphs )
+  {
+    modelPositions.Clear();
+  }
+  else
+  {
+    modelPositions.Resize( numberOfGlyphs );
+    memcpy( modelPositions.Begin(), glyphPositions, numberOfGlyphs * sizeof( Vector2 ) );
+  }
+}
+
+Length VisualModel::GetNumberOfGlyphPositions() const
+{
+  return mImpl->mGlyphPositions.Count();
 }
 
 void VisualModel::GetGlyphPositions( Vector2* glyphPositions,
                                      GlyphIndex glyphIndex,
                                      Length numberOfGlyphs ) const
 {
-  std::vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
-  memcpy( glyphPositions, &modelPositions[0], numberOfGlyphs*sizeof(Vector2) );
+  const Vector<Vector2>& modelPositions = mImpl->mGlyphPositions;
+  memcpy( glyphPositions, modelPositions.Begin() + glyphIndex, numberOfGlyphs * sizeof( Vector2 ) );
 }
 
 const Vector2& VisualModel::GetGlyphPosition( GlyphIndex glyphIndex ) const
 {
-  return Vector2::ZERO;
+  return *( mImpl->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 )
 {
+  Vector<LineRun>& modelLines = mImpl->mLines;
+  GetLineCache& lineCache = mImpl->mGetLineCache;
+
+  if( 0u == numberOfLines )
+  {
+    modelLines.Clear();
+  }
+  else
+  {
+    modelLines.Resize( numberOfLines );
+    memcpy( modelLines.Begin(), lines, numberOfLines * sizeof( LineRun ) );
+  }
+
+  // Clear the get line cache.
+  lineCache.glyphIndex = 0u;
+  lineCache.numberOfGlyphs = 0u;
+  lineCache.firstLine = 0u;
+  lineCache.numberOfLines = 0u;
 }
 
 Length VisualModel::GetNumberOfLines() const
 {
-  return 0u;
+  return mImpl->mLines.Count();
 }
 
 void VisualModel::GetLines( LineRun* lines,
                             LineIndex lineIndex,
                             Length numberOfLines ) const
 {
+  const Vector<LineRun>& modelLines = mImpl->mLines;
+  memcpy( lines, modelLines.Begin() + lineIndex, numberOfLines * sizeof( LineRun ) );
 }
 
 Length VisualModel::GetNumberOfLines( GlyphIndex glyphIndex,
                                       Length numberOfGlyphs ) const
 {
-  return 0u;
+  // If is likely the user query consecutively for the number of lines with the same
+  // glyph index and number of glyphs, use the cache could be considered.
+  GetLineCache& lineCache = mImpl->mGetLineCache;
+
+  // Cache the glyph index and number of glyphs to be used in the GetLinesOfGlyphRange().
+  lineCache.glyphIndex = glyphIndex;
+  lineCache.numberOfGlyphs = numberOfGlyphs;
+
+  // Check first if the query is for the total number of glyphs.
+  const Length totalNumberOfGlyphs = mImpl->mGlyphs.Count();
+
+  if( ( 0u == glyphIndex ) &&
+      ( totalNumberOfGlyphs == numberOfGlyphs ) )
+  {
+    lineCache.firstLine = 0u;
+    lineCache.numberOfLines = mImpl->mLines.Count();
+
+    return lineCache.numberOfLines;
+  }
+
+  // Initialize the number of lines and the first line.
+  lineCache.numberOfLines = 0u;
+  lineCache.firstLine = 0u;
+  bool firstLineFound = false;
+
+  const Vector<LineRun>& modelLines = mImpl->mLines;
+  const GlyphIndex lastGlyphIndex = glyphIndex + numberOfGlyphs;
+
+  // Traverse the lines and count those lines within the range of glyphs.
+  for( Vector<LineRun>::ConstIterator it = modelLines.Begin(),
+         endIt = modelLines.End();
+       it != endIt;
+       ++it )
+  {
+    const LineRun& line = *it;
+
+    if( ( line.glyphIndex + line.numberOfGlyphs > glyphIndex ) &&
+        ( lastGlyphIndex > line.glyphIndex ) )
+    {
+      firstLineFound = true;
+      ++lineCache.numberOfLines;
+    }
+    else if( lastGlyphIndex <= line.glyphIndex )
+    {
+      // nothing else to do.
+      break;
+    }
+
+    if( !firstLineFound )
+    {
+      ++lineCache.firstLine;
+    }
+  }
+
+  return lineCache.numberOfLines;
 }
 
 void VisualModel::GetLinesOfGlyphRange( LineRun* lines,
                                         GlyphIndex glyphIndex,
                                         Length numberOfGlyphs ) const
 {
+  const Vector<LineRun>& modelLines = mImpl->mLines;
+  GetLineCache& lineCache = mImpl->mGetLineCache;
+
+  if( ( glyphIndex != lineCache.glyphIndex ) ||
+      ( numberOfGlyphs != lineCache.numberOfGlyphs ) )
+  {
+    GetNumberOfLines( glyphIndex,
+                      numberOfGlyphs );
+  }
+
+  memcpy( lines, modelLines.Begin() + lineCache.firstLine, lineCache.numberOfLines * sizeof( LineRun ) );
+}
+
+void VisualModel::ReplaceLines( GlyphIndex glyphIndex,
+                                Length numberOfGlyphsToRemove,
+                                const LineRun* const lines,
+                                Length numberOfGlyphsToInsert )
+{
 }
 
 void VisualModel::SetNaturalSize( const Vector2& size  )